JavaScript 的设计导致其全局变量的定义方式与其他语言有显著的不同。本文简单介绍一些关于 JavaScript 全局变量的一些小细节。
我们都知道,JavaScript 定义全局变量有以下几种方式:
var a = 1; // 1
globalThis.a = 1; // 2
a = 1; // 3
let a = 1; // 4
const a = 1; // 5
1、2 和 3 都是将全局变量 a
挂载在 globalThis
对象上,而 4 和 5 不会。let
和 const
没什么可说的,和其他语言都很类似。这里主要对 1、2 和 3 做一些探究。主要问题是:通过这三种方式定义的 globalThis.a
,有区别吗?
有区别。通过 3 定义的 globalThis.a
和另外两种方式定义的是不一样的。1 和 2 定义的属性的 [[configurable]]
描述符是 false
,而 3 定义的为 true
:
var a = 1;
// {value: 1, writable: true, enumerable: true, configurable: false}
console.log(Object.getOwnPropertyDescriptor(globalThis, 'a'));
globalThis.a = 1;
// {value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(globalThis, 'a'));
a = 1;
// {value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(globalThis, 'a'));
[[configurable]]
属性是 false
意味着,我们不能通过 delete
删除这个属性,也不能对其他描述符进行配置:
'use strict'
var a = 1;
delete globalThis.a; // Uncaught TypeError: Cannot delete property 'a' of #<Window>
// Uncaught TypeError: Cannot redefine property: a
Object.defineProperty(globalThis, 'a', {
enumerable: false
});
以上的示例都是在浏览器中运行得到。如果你用 Node.js 运行以上的示例,会发现奇怪的现象:
var a = 1;
console.log(globalThis.a); // 在 Node.js 中是 undefined,在浏览器中是 1
乍一看非常奇怪。我们明明在全局作用域声明了一个 var
变量,怎么在 globalThis
上找不到呢?
答案很简单:我们在 Node.js 里运行的代码从来都不会运行在全局作用域里。在执行之前,Node.js 对我们的代码进行了封装(不然,module
和 require
是怎么来的呢?)。以上的代码实际运行时被改为:
(function (exports, require, module, __filename, __dirname) {
var a = 1;
console.log(globalThis.a);
})();
a
实际被定义在了这个函数作用域里,自然不能在 globalThis
上访问到。编写代码时需要注意浏览器和 Node.js 环境的不同。当然,最好永远也不要用全局变量。