ES6模块中定义全局变量的正确方式是什么?

46

我似乎找不到从ES6模块导出全局变量的描述方式。是否有定义这种方式的资源?

唯一有效的解决方案似乎是引用全局对象,例如 window

window['v'] = 3;

但如果这个脚本在Node.js中运行呢?那么我就没有window,而是有global。但这段代码并不好:

var g = window || global;
g['v'] = 3;

我了解模块的概念,并且在我的应用程序中不使用全局变量。然而,在控制台调试时使用全局变量可能是有益的,特别是在使用类似Webpack的打包工具而不是像SystemJs这样的加载器时,在控制台中可以轻松地导入一个模块。


2
个人观点是,我认为你不应该在模块内实例化全局变量,因为它们应该是自包含的。如果你想要从模块中访问一个变量,你需要将该变量导出。 - George
@George,看看我在问题末尾的更新。 - Max Koretskyi
@CodingIntrigue,非常感谢你提供的链接,正是我在寻找的内容。你可以把它发布为回答。 - Max Koretskyi
@George,据我所知,如果代码不作为模块的一部分执行,则顶层的this指向全局对象,并且没有任何问题。在模块内部的顶层,this是未定义的。因此,这个问题是针对模块功能的。 - Max Koretskyi
可能是JavaScript和ES6中的“全局”变量的重复问题。 - totymedli
显示剩余3条评论
3个回答

21

有几种方法可以将全局变量在你的应用程序中使用。

使用ES6模块,您可以创建一个常量并从您的模块中导出它。然后,您可以像这样从任何其他模块或组件中导入它:

/* Constants.js */
export default {
    VALUE_1: 123,
    VALUE_2: "abc"
};

/* OtherModule.js */
import Constants from '../Constants';

console.log(Constants.VALUE_1);
console.log(Constants.VALUE_2);

另外,一些JS打包工具提供了一种在构建时将值传递到组件中的方法。

例如,如果您正在使用Webpack,可以使用DefinePlugin在编译时配置几个常量,如下所示:

/* Webpack configuration */
const webpack = require('webpack');

/* Webpack plugins definition */
new webpack.DefinePlugin({
    'VALUE_1': 123,
    'VALUE_2': 'abc'
});

/* SomeComponent.js */
if (VALUE_1 === 123) {
    // do something
}

6
您可以使用globalThis

function test(h) {
    globalThis.testVar = h
}

test("This is a global var")
console.log(testVar)


4

您可以通过间接的 eval 调用来获取全局对象。

// this weird syntax grabs the global object
const global = (0,eval)("this");
// (0,eval) === eval; but the first one is an indirect evaluation
// inside indirect evaluation of eval, "this" is global object
// this takes advantage of that fact to identify "global"

// then set whatever global values you need
global.VALUE_1 = 123;
global.VALUE_2 = "abc";

为确保正确顺序,您需要注意模块加载的方式。

更多信息请参见:(1, eval)('this') 与 eval('this') 在 JavaScript 中有何不同?


5
我:哇,ES6模块发布了。第一步)我如何声明全局变量。ES6:不允许。让我搞清楚,Vanilla JS:允许。ES6:不行。ES6:如果我们给你全局变量,所有混乱的人就会像意大利面一样把他们的代码全部耦合在一起。我:如果你是一个更好的FP软件架构师怎么办?ES6:竖中指。 真的吗?他们不允许全局变量的决定就像C#不允许在类和命名空间之外使用静态定义一样糟糕。我要大量编码生成。导入所有内容是不可行的。这就像没有基本情况的归纳证明。令人沮丧。 - Chris C
@ChrisC 我想看一个全局变量的有效使用案例的例子(这里指的是变量,而非常量)。我的理解是,全局变量是导致大多数JavaScript安全漏洞的罪魁祸首。 - diachedelic
2
假设我在模块A中有一个服务总线。它有两个方法bus.send(msg)和bus.receive(callback)。无论我在哪里使用这个总线,我都需要导入它。可能会有数百次。DRY告诉我们这是荒谬的。无用的噪声样板文件。安全漏洞不是来自全局变量,而是来自将它们键入字符串的人可以随意搞乱它们。如果我们有符号全局变量,在我的模块中无论我在哪里输入“Bus”,我都只引用我的Bus定义,而没有其他第三方垃圾塞进全局命名空间,那就可以正常工作。 - Chris C
模块A:导出全局总线 | 模块B:bus.Send("hi") | 基本上,模块系统只是在引用总线的每个文件中插入自动导入。据我所知,这并不是什么争议性的问题... - Chris C
2
在JavaScript中,你通常会在测试框架中找到全局变量。例如,mocha库声明了全局函数“describe”和“it”。它允许你构建类似DSL的语言,而不会混淆代码。 - Rich Remer
以下是一个有效的使用案例:检测您不在浏览器中并以不同方式行事。这不会修改全局变量,但仍需要读取它来检查 window。(再说一遍,如果有其他方法可以实现,我仍在寻找) - Lazerbeak12345

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接