Question

The original Code:

'use strict';
function GitJs(config) {
    var defaults = {
        inheriting: false,
        clientId: undefined,
        accessToken: undefined,
        baseUrl: 'https://api.github.com',
        mode: 'read'
    };

    this.config = $.extend(defaults, config);
}

/**
 * Gets the jQuery method that GitJs#generateApiRequest is going to use to send the ajax request.
 *
 * @param {string} httpVerb The HTTP verb that the request will use,
 * @return string
 */
GitJs.prototype.getCommandMethod = function (httpVerb) {
    var method = $.get;

    switch (httpVerb) {
    case 'GET':
        method = $.get;
        break;
    case 'POST':
        method = $.post;
        break;
    }
    return method;
};

...

The new code:

(function() {
'use strict';
    'use strict';
    function GitJs(config) {
        var defaults = {
            inheriting: false,
            clientId: undefined,
            accessToken: undefined,
            baseUrl: 'https://api.github.com',
            mode: 'read'
        };

        this.config = $.extend(defaults, config);
    }

    /**
     * Gets the jQuery method that GitJs#generateApiRequest is going to use to send the ajax request.
     *
     * @param {string} httpVerb The HTTP verb that the request will use,
     * @return string
     */
    GitJs.prototype.getCommandMethod = function (httpVerb) {
        var method = $.get;

        switch (httpVerb) {
        case 'GET':
            method = $.get;
            break;
        case 'POST':
            method = $.post;
            break;
        }
        return method;
    };

    ...
}());

As this code stands, when I attempt:

var gitjs = new GitJs();

I am told that GitJs is undefined

What the hell I was thinking:

  • I don't want to put use strict inside of every method.
  • I want my code to play nice if it gets minified and concatenated to another file.
  • I want to use the .prototype syntax for ease of inheritance later on (and code clarity)
  • I don't want to make a global var gitJs variable because it could be overridden by someone else's script.
  • I assume that the user will always invoke the object constructor via the new keyword

For the record, I know I'm wrong. Way wrong. I just can't seem to figure out where the flaw in my thinking lies and I'd love some guidance.

Was it helpful?

Solution

Your problem is that GitJS is now a private variable of the immediately invoked function. You can't hide your function in a private scope and make it publicly available at the same time. They are mutually exclusive goals.

Therefore, you will want to either explicitely set the global variable, via the window

var GitJS;
(function() {
    'use strict';
     GitJS = function(){ ... }
     ...
}());

or return the exported function from inside the IIFE.

var ExportedGitJS = (function(){ //using a different name just to be clear...
    'use strict';
    var GitJS = function(){ ... }
    ...
    return GitJS;
}());

OK, I lied. You can make Javascript modules without having to rely on global variables but that usualy means also using a different module-creation convention and/or using a module library. I would highly recommend that you check out http://requirejs.org/ if you are interested in this.

OTHER TIPS

@missingno is correct, but I have to add that you're just one step from using RequireJS or an equivalent loader. You're right to be leery of global variables; if you commit to running all of your JavaScript inside asynchronous modules with defined dependencies, then you can simply return your GitJs constructor to the global define function, and then require your GitJS module in anything that needs it.

// using the global define function provided by an AMD loader
// assuming that jQuery has already been provided by the paths config
define(['jquery'],function($) {
    'use strict';
    var GitJS = function() { ... }
    return GitJS
});

Regarding giving some guidance, I'm not sure if this sounds completely obvious, but there is a way to:

  • not insert the use strict pragma in every method
  • not impose strict mode on other sources when concatenated
  • use the .prototype syntax
  • not require a global var gitJs variable
  • let the user invoke the object constructor via the new keyword

There it is:

/* Class constructor, public, globally available */
function GitJs(config) {
    'use strict'; /* You may want to drop this one */
    var defaults = {
        inheriting: false,
        clientId: undefined,
        accessToken: undefined,
        baseUrl: 'https://api.github.com',
        mode: 'read'
    };

    this.config = $.extend(defaults, config);
}

/* IIFE to wrap the *main* strict pragma */
(function () {
    'use strict';

    GitJs.prototype.getCommandMethod = function (httpVerb) {
        /* ... */
    };

    GitJs.prototype.someOtherMethod = function (someParam) {
        /* ... */
    };

})();

...

/* some other block */
... {
    var gitjs = new GitJs();
};

Does this partially respond to the question?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top