开发者

How should I define a JavaScript 'namespace' to satisfy JSLint?

I want to be able to package my JavaScript code into a 'namespace' to prevent name clashes with other libraries. Since the declaration of a namespace should be a simple piece of code I don't want to depend on any external li开发者_如何学Cbraries to provide me with this functionality. I've found various pieces of advice on how to do this simply but none seem to be free of errors when run through JSLint (using 'The Good Parts' options).

As an example, I tried this from Advanced JavaScript (section Namespaces without YUI):

"use strict";
if (typeof(MyNamespace) === 'undefined') {
    MyNamespace = {};
}

Running this through JSLint gives the following errors:

Problem at line 2 character 12: 'MyNamespace' is not defined.
Problem at line 3 character 5: 'MyNamespace' is not defined.
Implied global: MyNamespace 2,3

The 'Implied global' error can be fixed by explicitly declaring MyNamespace...

"use strict";
if (typeof(MyNamespace) === 'undefined') {
    var MyNamespace = {};
}

...and the other two errors can be fixed by declaring the variable outside the if block.

"use strict";
var MyNamespace;
if (typeof(MyNamespace) === 'undefined') {
    MyNamespace = {};
}

So that works, but it seems to me that (since MyNamespace will always be undefined at the point it is checked?) it is equivalent to the much simpler:

"use strict";
var MyNamespace = {};

JSLint is content with this but I'm concerned that I've simplified the code to such an extent that it will no longer function correctly as a namespace. Is this final formulation sensible?


Don't take JSLint's word as gospel. Much of what it says is sensible, but it also comes with a lot of Crockford's personal dogma attached. In particular I don't always agree with him about the best place for var.

"use strict";
if (typeof(MyNamespace) === 'undefined') {
    MyNamespace = {};
}

That one's no good; JSLint is correct to complain about the implied global. 'use strict' requires you don't imply globals.

"use strict";
if (typeof(MyNamespace) === 'undefined') {
    var MyNamespace = {};
}

That's fine. The var is hoisted so MyNamespace is present and set to undefined on entering the code block. So you could do that test as (MyNamespace===undefined) even without the typeof operator's magic ability to let you refer to variables that don't exist.

The other way is to use the unambiguous in operator (which is the only way to distinguish between an absent property one that is present but set to undefined). For the case of globals in a normal browser script, you can use it against the global window object:

'use strict';
if (!('MyNamespace' in window)) {
    window.MyNamespace = {};
}

(JSLint doesn't like that either, as ‘assume a browser’ doesn't seem to define window for some unfathomable reason. Hey ho.)


You can try a much shorter version:

var MyNamespace = MyNamespace || {};

This should be valid in JSLint, even in strict mode, using the name if it already exists and creating it if it doesn't, as best a namespace in JavaScript can be expected to work.


This is a REALLY old question but I thought I would answer anyway since none of the above cleared all errors of jslint for me because I suspect the lint'r has been updated :-)

There maybe other ways to do this but as of 2013 it's the best I can come up with

If you want an error free jsLint module pattern with a namespace and strict see below

Assuming that this is contained in some .js file ...

this.ns = this.ns || {}; // Check for global namespace and if not found create 

(function(ns) {
  'use strict'   // restrict usage to this module 

  ns.myFunction = function() {
  } 

} (this.ns)); // Pass in the global namespace you 'might' have created above and 
              // drop 'this' reference

'this' is necessary to avoid the out-of-scope error (seems like it shouldn't matter but I guess using 'this' is explicit vs. just using ns or var ns both of which toss errors.

The iffy pattern is required to avoid the global 'use strict' error

Of course other tools don't like the 'this' as an iffy param warning that it's global (which is the intent of course) so ... tomatoe tomato


You can access global variables through the window["NAMEOFGLOBAL"] syntax, so you could do your check like this instead:

if(typeof(window['MyNamespace']) === 'undefined') {


Surely the point of the undefined check is to ensure that users are not double-loading or overwriting an existing namespace. As such, I think you've gone too far.

How about:

var MyNs;
if(MyNs==null){
    //foo()
}


I've encountered this issue before. You definitely don't want to use your final form, as it is completely bypassing the check for a defined variable and will always overwrite it to an empty object, even if things were already stored in it.

I think your second to last form is the most appropriate for creating a namespace, but really the first form is decent as well. The errors that JSLint reports with it are sort of catch-22s in my opinion and not much to worry about. The reason I think it's not a big deal to leave off the declaration is that, in the case where the namespace is loaded at some previous point, you'd end up with JSLint's "variable was used before it was defined" error, so you're essentially just trading one warning for another.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜