【问题标题】:JavaScript ES6 Modules: Avoid Polluting Global NamespaceJavaScript ES6 模块:避免污染全局命名空间
【发布时间】:2018-05-21 22:30:49
【问题描述】:

背景

在 JavaScript 中导入模块时,我们会用导入模块的名称污染全局命名空间:

foo.js

export foo() {..};
export const bar = 3.14;

index.js

import { foo, bar } from './foo.js';

问题

index.jsfoobar 中存在于全局命名空间中,对吧?所以,假设我发布了这个模块,有人在他们的 HTML 文件中使用它,以及另一个脚本,该脚本也在全局命名空间中定义了变量 foobar。那我们不会发生碰撞吗?

我想这可以通过将 main.js 中的所有内容包装在 IIFE 中来解决。但是,出于某种原因,ESLint 对此有所抱怨,这让我怀疑 IIFE 是否不是保护全局命名空间的首选/推荐方法。

  1. 全局命名空间会被foobar 污染吗?
  2. 如果是这样,我应该如何避免?

谢谢。

【问题讨论】:

  • 通常你会导出{ foo: ..., bar: ... },然后使用它的名字导入整个模块。这样你就只有在index.js的全局命名空间中拥有模块的名称,并且可以使用myModule.foo来访问foo
  • 您是否使用任何类型的捆绑程序?如果是这样,它们会将每个文件视为 IIFE,因此,foobar 将不会放在全局范围内。如果你不是,但是,是的,克里斯 G 说的是正确的
  • 嗨@ChrisG。不幸的是,我仍然会用myModule 污染全球名称空间。此外,它会迫使我使用对象/属性语法。
  • 根据您的示例,“在 index.js 中,foo 和 bar 位于全局命名空间中,对吗?”是的。
  • 使用 eslint.org/demo,选择 ES6,我使用 (function(){ let foo = 5; const bar = 3.14; if(foo) foo += bar; })() 并得到“Lint-free!”

标签: javascript module ecmascript-5


【解决方案1】:

在 JavaScript 中导入模块时,我们会用导入模块的名称污染全局命名空间

没有。每个模块都有自己的模块范围,所有导入的绑定和顶级声明都在其中。

在只有 ES6 模块的普通 ES6 环境中,您几乎从不使用全局范围 - 所有模块代码都是严格模式代码,因此您必须努力在全局对象上创建变量。

模块捆绑器通常允许您在捆绑脚本中声明一些导出以成为全局变量来缓解这种情况,这样您在使用其他脚本时也可以在页面中轻松访问它们。

【讨论】:

  • 啊,有趣。只是为了 100% 确定我正确地理解了你:当我导入一个模块(ES6 风格)时,它只能在它导入的 .js 文件中访问。导入的模块名称不会与其他脚本中的相同名称冲突?
  • 是的,导入是在本地范围内创建的。与脚本不同,每个模块都有自己的隐式作用域。
  • 模块之间唯一可能发生冲突的是模块名称(通常是文件路径)本身。导出与单个模块相关联。
  • 知道了。这对我来说有点反直觉,因为我确实访问了index.js 中的foobar,就好像它们是全局变量一样。注意:index.js 本身并不是一个模块,它是直接链接在index.html 中的顶级脚本。我想我们可以认为index.js 被封装在一个 IIFE 中,即使它不是?
  • 它们是引用foo.js 模块中的变量的绑定——它们只有在您导入它们时才可用。不,index.js 也是一个模块,只有模块可以使用 import 语法。您可能无法在其中创建var global。您的捆绑器/转译器当然会将所有内容放在由 IIFE 包装的脚本中,是的。
猜你喜欢
  • 2020-01-03
  • 2015-03-05
  • 1970-01-01
  • 2011-10-04
  • 2011-05-14
  • 1970-01-01
  • 2014-04-25
  • 1970-01-01
  • 2016-03-10
相关资源
最近更新 更多