21

我希望能够将我的 JavaScript 代码打包到“命名空间”中,以防止与其他库发生名称冲突。由于命名空间的声明应该是一段简单的代码,我不想依赖任何外部库来为我提供此功能。我已经找到了关于如何简单地做到这一点的各种建议,但在通过JSLint运行时似乎没有一个没有错误(使用“The Good Parts”选项)。

例如,我从Advanced JavaScript(没有 YUI 的命名空间部分)尝试了这个:

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

通过JSLint运行它会出现以下错误:

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

“隐含全局”错误可以通过显式声明来修复MyNamespace...

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

...并且可以通过在 if 块之外声明变量来修复其他两个错误。

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

所以这行得通,但在我看来(因为MyNamespace在检查时总是未定义?)它相当于更简单的:

"use strict";
var MyNamespace = {};

JSLint 对此很满意,但我担心我已经将代码简化到无法再作为命名空间正常工作的程度。这个最终的表述是否合理?

4

6 回答 6

19

不要把 JSLint 的话当成福音。它所说的大部分内容都是明智的,但它也附带了许多 Crockford 的个人教条。特别是我并不总是同意他关于最佳地点的看法var

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

那个不好;JSLint 抱怨隐含的全局是正确的。'use strict'要求您不要暗示全局变量。

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

没关系。被var提升所以MyNamespace存在并设置为undefined进入代码块。因此,(MyNamespace===undefined)即使没有typeof操作员的神奇能力让您引用不存在的变量,您也可以进行该测试。

另一种方法是使用明确的in运算符(这是区分存在但设置为的不存在属性的唯一方法undefined)。对于普通浏览器脚本中的全局变量,您可以将其用于全局window对象:

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

(JSLint 也不喜欢这样,因为“假设浏览器”似乎并没有window因为一些深不可测的原因而被定义。嘿嘿。)

于 2010-02-20T12:05:32.817 回答
7

您可以尝试更短的版本:

var MyNamespace = MyNamespace || {};

这在 JSLint 中应该是有效的,即使在严格模式下,如果名称已经存在则使用该名称,如果不存在则创建它,因为 JavaScript 中的命名空间最好可以正常工作。

于 2011-02-15T00:38:54.263 回答
6

这是一个非常老的问题,但我想我还是会回答,因为以上都没有为我清除 jslint 的所有错误,因为我怀疑 lint'r 已更新:-)

也许还有其他方法可以做到这一点,但截至 2013 年,这是我能想到的最好的方法

如果您想要一个带有命名空间和严格的无错误 jsLint 模块模式,请参见下文

假设这包含在一些 .js 文件中......

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' 是避免超出范围错误所必需的(似乎无关紧要,但我想使用 'this' 是明确的,而仅使用 ns 或 var ns 两者都会抛出错误。

需要 iffy 模式以避免全局“使用严格”错误

当然,其他工具不喜欢“this”作为一个不确定的参数警告它是全球性的(这当然是意图)所以......番茄番茄

于 2013-11-02T22:58:45.003 回答
3

您可以通过语法访问全局变量window["NAMEOFGLOBAL"],因此您可以像这样进行检查:

if(typeof(window['MyNamespace']) === 'undefined') {
于 2010-02-20T11:09:20.957 回答
1

当然,未定义检查的重点是确保用户不会重复加载或覆盖现有的命名空间。因此,我认为你走得太远了。

怎么样:

var MyNs;
if(MyNs==null){
    //foo()
}
于 2010-02-20T11:05:19.260 回答
1

我以前遇到过这个问题。您绝对不想使用最终形式,因为它完全绕过了对已定义变量的检查,并且总是将其覆盖为空对象,即使其中已经存储了东西。

我认为您的倒数第二个表单最适合创建命名空间,但实际上第一个表单也很不错。在我看来,JSLint 报告的错误有点像 catch-22,不用担心。我认为放弃声明没什么大不了的原因是,如果命名空间在之前的某个时间点加载的,你最终会遇到 JSLint 的“变量在定义之前使用”错误,所以你'本质上只是用一个警告换另一个警告。

于 2010-02-20T11:14:00.467 回答