【问题标题】:Why are namespaces considered bad practice in JavaScript? [closed]为什么命名空间在 JavaScript 中被认为是不好的做法? [关闭]
【发布时间】:2012-04-20 16:47:25
【问题描述】:

有人告诉我不应该使用命名空间,因为它们会“污染”全局范围。我想知道有什么替代方案?

当我想定义实用函数和/或常量时,例如对于一个网站,一个简单的方法是通过命名空间来定义它们,这样对全局范围的损害仅限于一个对象。

如果命名空间是不好的做法,我会想到几个问题:

  1. 为什么这是不好的做法?
  2. 此声明的范围是什么(网络应用程序/动态网站/静态网站等)?
  3. 有哪些替代方案?

这个问题是在a post on the benefits of using extend.js 发起的讨论的结果。

【问题讨论】:

  • 而且我一直认为命名空间正是为了污染全局范围......(-> 它们是)。跨度>
  • 是的,有人反其道而行之。
  • @FelixKling 命名空间仍然污染全局范围。你永远不需要 JavaScript 中的全局标记。任何使用它们的人都做错了。
  • @Raynos:当然,每个顶级命名空间都会在全局范围内创建一个符号……但如果它不这样做,您将如何访问外部库?
  • @FelixKling 使用闭包的自定义模块加载器。库不应该公开全局令牌,它们应该使用 AMD 或 commonJS 等标准格式公开它们的模块,并且模块加载器应该提取这些模块并处理模块间的依赖关系。这可以通过零个用户创建的全局令牌来完成(甚至避免临时全局令牌)

标签: javascript namespaces


【解决方案1】:

为什么这是不好的做法?

命名空间本身很糟糕,因为它是一个不必要的概念。

拥有带有属性和方法的对象是可以接受的。拥有一个类似于“命名空间”的“模块”令牌也很好,但意思是每个文件都有一个“模块”令牌,其中包含所有属性和方法。这与“命名空间”不同,因为它仅在单个文件中创建/更改,并且不作为全局令牌公开。

此声明的范围是什么(网络应用程序/动态网站/静态网站等)?

所有 ECMAScript,从不创建新的全局令牌

有什么选择?

而不是拥有命名空间,您应该支持多个“文件本地”令牌。这意味着每个文件/“模块”都应该包装在一个闭包中,并且您应该可以访问该闭包内的多个局部变量。

全局变量也很糟糕,因为您根本不需要它们。避免全局变量的方法是将所有内容包装在闭包中,并在加载外部 javascript 文件的方式上保持智能。

零全局模块加载器示例

进一步阅读:

【讨论】:

  • 只需要两个全局变量:AMD definerequire 函数。 ;)
  • 需要零个全局变量。您可以通过全局令牌以外的方式将令牌 definerequire 注入模块
  • Raynos,我知道您的技能足以说明问题,但您缺少的是演示您正在谈论的内容的实际示例代码(请参阅问题中的第 3 条)。跨度>
  • 好的,有人应该挖掘它并找到说明你观点的代码吗?第一个 think I clicked on 显示了五个全局变量。
  • @JaredFarrish 所有这些文件都为您包装在闭包中。当构建任务可以为您完成时,将每个单独的文件包装在闭包中是很难看的。这些是“文件本地”令牌或“模块范围令牌”
【解决方案2】:

我无法想象为什么命名空间会是一件坏事。除非有一些我不知道的特定于 JavaScript 的命名空间定义。

我目前正在开发一个小型库,所有内容都包含在一个顶级对象(命名空间?)中。我没有在窗口或内在类型上放任何东西;如果您需要我的库中的某些内容,可以在 kilo 对象中找到它。

对我来说,拥有这个“命名空间”是一种的做法,因为它可以让我很快知道我是否正在调用库中的方法。无需重写 window.alert 方法,该方法可能会与页面上加载的另一个库发生冲突;只需将kilo.alert 用于自定义版本(这是一个人为的示例,但我希望它能够说明问题)。

【讨论】:

  • 您不需要“命名空间”来知道您是否从库中调用方法,您只需操作该库公开的对象和令牌。
  • 我想我们需要的是一个更清晰的命名空间定义。 JavaScript 没有它们,但我们谈论它们就像它实际上是语言的一部分一样。真的,我只是为我的库使用一个父对象。命名空间在 JavaScript 中并不是真正的东西。甚至这里所谓的命名空间实际上也只是一个对象链。
【解决方案3】:

我个人认为那些说你应该永远污染全局范围的人未能正确定义“污染”。例如,您可以在一定程度上在本机 Math 对象中看到这一点。我知道的所有其他编程语言都将所有数学函数都作为普通函数,但 JS 没有。但是,如果您将其发挥到极致,例如,一个简单的警告框将改为 core.dialog.alert

我喜欢将我的所有代码封闭在闭包中,以保持变量干净。但是,我的主 JS 脚本文件在全局范围内定义了一堆实用函数,例如自定义的Alert(),或AJAX(),或其他广泛使用的函数。如果我要经常使用它们,我不想用命名空间调用来膨胀文件。而且由于我在闭包中定义了所有变量,因此不会有意外覆盖函数的风险(我可能会在闭包本身中这样做,但它对全局范围没有影响)。

总体而言,命名空间被高估了。只需编写您的代码,不要为每个 window 属性哭泣。

【讨论】:

  • 你推荐人们使用全局变量,这是一种不好的做法。
  • Namespacing 和其他技术在您可能有可能发生冲突的分层库的某些环境中更有用。例如,JIRA 使用命名空间将诸如 jQuery 之类的东西放在窗口范围之外,但是它使用了大量的库,所以它是有意义的。总体而言,目前还没有人指出为什么应该避免在 JS 中使用全局变量,因为它们很容易被任何其他脚本覆盖,如果发生这种情况,您可能会遇到问题。因此,谨慎行事是有道理的,一般来说不要夸大其词。
  • 全局变量的另一个问题是它们是全局的,任何东西都可以读取/修改/损坏/更改/通常会弄乱它们。这类似于不应将 SQL 查询直接嵌入服务器端 Web 应用程序的视图中的概念。基本上全局变量打破了关注点的分离
【解决方案4】:

JavaScript 中的“命名空间”实际上只是具有命名属性的对象。在其他 OO 语言(即 C++、C# 等)中,我认为您不需要以下内容:

C# --

public static class MyAppName {}
public static class MyArea {}
public static class MySubArea {}

public static class Test {
  public string Property1 { get { return "test"; }}
}

只是为了让你拥有

MyAppName.MyArea.MySubArea.Test.Property1;

所以基本上,因为 JS 实际上并不支持命名空间,所以人们发明了一种 hack 来模拟命名空间,这使得编写如下内容变得“酷”:

myAppSpace.mySubArea.myObject = blah...

【讨论】:

  • 引用“现实世界”然后包含其他语言的代码来说明您的观点通常是一个坏主意(更不用说糟糕的形式)。
  • @JaredFarrish 我相信他试图说明这种“命名空间”概念在移植到另一种语言(如 C#)时也会产生丑陋和愚蠢的代码。
  • @Raynos - 我知道重点是什么,我们正在谈论 JS。这就是 C#。
猜你喜欢
  • 2010-10-22
  • 2011-11-20
  • 2010-09-26
  • 1970-01-01
  • 2010-09-26
  • 2010-11-04
相关资源
最近更新 更多