我应该如何定义一个 JavaScript 的“命名空间”来满足 JSLint?

Posted

技术标签:

【中文标题】我应该如何定义一个 JavaScript 的“命名空间”来满足 JSLint?【英文标题】:How should I define a JavaScript 'namespace' to satisfy JSLint? 【发布时间】:2011-01-19 02:30:20 【问题描述】:

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

例如,我从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 对此感到满意,但我担心我已经将代码简化到无法再作为命名空间正常工作的程度。这个最终的表述是否合理?

【问题讨论】:

您特别担心MyNamespace 不能作为命名空间正常工作? 只是一种琐碎的感觉,因为那里的建议建议更复杂的配方,我错过了一些对我来说并不明显的细微差别。 【参考方案1】:

这是一个非常老的问题,但我想我还是会回答,因为以上都没有为我清除 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 模式以避免全局“use strict”错误

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

【讨论】:

这不再是“jslint 兼容”!但是,正如@bobince 所解释的那样,我担心可能没有办法做到这一点。 :(【参考方案2】:

您可以尝试更短的版本:

var MyNamespace = MyNamespace || ;

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

【讨论】:

这现在失败了,即使 MyNamespace 作为全局预定义添加。报告的错误是“MyNamespace”超出范围。【参考方案3】:

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

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

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

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

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

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

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

(JSLint 也不喜欢这样,因为“假设浏览器”似乎没有定义 window 出于某种深不可测的原因。嘿嘿。)

【讨论】:

+1 - 不错的答案!那么在 if 块之外使用var MyNamespace; 的公式(不给出 JSLint 错误)是否有任何语义问题,或者这也可以吗? 没关系,只要我们确实在谈论全局代码。如果您声明一个已经有值的全局var,则不会发生任何事情(它不会重置为undefined)。而如果您声明一个与定义的全局同名的局部 var,则值为 undefined 的局部变量会隐藏全局。【参考方案4】:

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

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

【讨论】:

您能否详细解释一下为什么这些错误是“catch-22”? 检查已定义变量有什么好处 - 是否只是为了防止@spender 强调的“双重加载”场景? 编辑了我的答案,以更好地解释为什么 JSLint 给你的警告应该持保留态度。是的,未定义检查的重点是防止意外覆盖以前使用过的变量。在一个简单的应用程序中它可能永远不会出现,但是当事情开始变得更加复杂并且您的代码分布在多个文件中时,它是一种有用的保护措施。 +1,但是 JSLint 是否可以检测命名空间被加载两次的情况(即,它可以用于查看由 html 文件一起加载的多个 .js 文件)? 据我所知,您可以通过它运行 HTML,但它只会查看 script 标记和内联事件处理程序中的代码——它不会加载外部脚本并执行它们按照浏览器的顺序排列。【参考方案5】:

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

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

【讨论】:

我猜这是假设 javascript 代码将作为网页的一部分运行(例如,如果代码在 firefox 扩展中使用,我认为这不会起作用)。 正确; window 通常特定于浏览器。 this 通常指的是全局浏览器范围内的windowif(typeof(this['MyNamespace']) === 'undefined') 会在无法假设 window 的地方工作吗?【参考方案6】:

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

怎么样:

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

【讨论】:

JSLint 建议使用 === 而不是 ==(使用“优质部件”选项),但是从语法的角度来看,它和空格的变化对此很满意。 -1:检查null在概念上是错误的,并且仅因为==的邪恶而起作用 Christoph:但是 == null 可以识别空值和未定义。 +1 问题

以上是关于我应该如何定义一个 JavaScript 的“命名空间”来满足 JSLint?的主要内容,如果未能解决你的问题,请参考以下文章

如何在另一个 C++ 命名空间内的全局命名空间中定义朋友?

我们应该为 JavaScript 重新命名吗?[每日前端夜话0xDA]

学习Javascript的算法和数据结构--数组

如何重命名 AWS 客户 IAM 策略?

JavaScript变量应该选择啥样的命名规则

在 Javascript 中定义一个具有命名空间的类