【问题标题】:JavaScript: Namespace vs ScopeJavaScript:命名空间与作用域
【发布时间】:2018-10-10 12:53:45
【问题描述】:

我对 JavaScript 中作用域和闭包的概念有相当好的把握。

此外,以下网站提供了如何实现 JavaScript 命名空间的示例:

  1. Everything you wanted to know about JavaScript scope
  2. Namespacing in JavaScript

我仍然不明白的是有多少人似乎混合了范围和命名空间的概念。此外,同样的人还经常提到不应该“污染全局命名空间”而不是“在全局范围内创建全局变量/变量”。

问题

  • 作用域和命名空间是两个完全不同的概念,这不正确吗?
    • 命名空间:对代码进行分组,使组内的名称是唯一的,并且不能与其他命名空间中的相似名称发生冲突
    • 范围:定义变量的可访问性。 JavaScript 有两个作用域,全局作用域和本地/函数作用域(ES 2015 引入了块作用域,let/const
  • 下面的对象字面量为bar创建一个新的命名空间,避免污染全局命名空间(foo除外)是否正确,但bar仍在全局范围内:var foo = { bar: 42 }
  • 说“不要创建全局变量,以免污染全局命名空间”是不是错了?全局变量与局部变量(范围)与命名空间不同。正如所见,完全有可能在一个新的命名空间中屏蔽一个变量,并且仍然让它在全局范围内。
  • 如果避免污染全局命名空间是我们不应该创建全局变量的唯一原因,那么仅仅创建新的命名空间并使其保持全局性还不够吗?

【问题讨论】:

  • 现代 JavaScript 也通过 letconst 声明具有 block 范围。
  • @Pointy True,更新了帖子。

标签: javascript scope namespaces


【解决方案1】:

作用域和命名空间是两个完全不同的概念,这不正确吗?

我不会说作用域和命名空间是完全不相关的。如果我们采用“namespace”的字面意思,它是一个具有不同名称的space - 正如你所说的,它是唯一的,并且不会与其他空间的名称冲突。

在这方面,作用域肯定形成了一个命名空间——变量名称是不同的,并且不会与其他作用域的名称发生冲突。但是,作用域是内部的,无法从外部访问,因此组织事物并不是特别有趣。

一个对象也形成了一个名称空间——属性名称是不同的,并且不会与其他对象上的名称冲突。这就是为什么使用对象将代码结构化为模块的原因,这也是 JavaScript 中“命名空间”的传统含义。

下面的对象字面量是否为bar创建了一个新的命名空间,避免污染全局命名空间(foo除外),但bar仍在全局范围内:var foo = { bar: 42 }

不,bar 不是全局范围的成员。它是某个对象的属性。

说“不要创建全局变量以免污染全局命名空间”是不是错了?全局变量与局部变量(作用域)与命名空间不同。

全局变量在 JS 中有点特殊:它们既是全局对象的属性,又是全局范围内的变量。这就是为什么我们谈论“全局命名空间”来涵盖所有内容 - 特别是要强调名称不得冲突。

如果避免污染全局命名空间是我们不应该创建全局变量的唯一原因,那么仅仅创建新的命名空间并仍然保持全局是不够的吗?

创建命名空间,如上面示例中的{bar: 42},仍然会创建全局变量:foo。它只是创建 更少 变量 - 每个模块一个。它还创建了一个特定的命名约定,即全局变量应该引用模块而不是普通变量。我们不会使用var i, increment, decrement;,而是使用var counter = {i: …, increment(){…}, decrement(){…}};,并在名称counter 中提及它们的用途。

【讨论】:

  • 谢谢你,Bergi。您能否详细说明bar 不在全球范围内?据我了解barfoo 的属性,而foo 又是全局对象的属性(浏览器中的window)。因此,由于bar 不在函数范围内,它必须在全局范围内。旁注:我们可以选择在新命名空间 (var bar = 42) 之外定义 bar,在这种情况下,它将在全局命名空间和全局范围内。相反,我们将它放在自己的命名空间(对象)中以避免名称冲突。但它不在函数中,因此没有创建新范围。
  • @Magnus bar 根本不在任何 范围 中,它是对象属性而不是变量。这就是它不在全局范围内的原因。
  • @Magnus 我们可以想象一个由所有全局可访问路径组成的“名称空间”(类似于 URI 名称空间是域名称空间的超集)。然后“foo”和“foo.bar”将位于该命名空间中。但这并不是我们通常所说的“全局命名空间”的意思。
  • 嗯,我明白了。但是,bar 的工作方式与变量相同,对吧?毕竟,我们是在var bar = 42 或在对象内命名空间(从而使其成为对象属性)之间做出决定。这是正确的理解吗?另外,foo 是不是既是变量又是全局对象的属性?
  • 如果可以的话,另一个跟进:如果问题是造成名称冲突,那么语句不应该是Don't create variables in the global scope。是的,正如您所说,创建局部变量的副作用是它们是命名空间的,但这只是一个副作用。该声明应改为:Don't create variables in the global *namespace*。它更具体/更少误导,你不同意吗?
猜你喜欢
  • 2016-12-13
  • 2019-07-20
  • 1970-01-01
  • 1970-01-01
  • 2016-05-24
  • 2010-12-05
  • 2011-12-02
  • 2011-03-25
相关资源
最近更新 更多