大家好,我是万天。让我们从一段代码开始让我们从一段代码开始。下面的代码分别通过const和var定义了name1和name2,然后在newFunction()中访问name1和name2。constname1='jack';varname2='tom';newFunction(`console.log('name',name1,name2)`);这段代码分别在VSCode终端和浏览器控制台运行,结果不一样。VSCode终端:在Vscode终端运行时,直接报错ReferenceError:name1isnotdefined浏览器控制台:在浏览器控制台运行,name1和name2都可以正常访问。为什么同样的一段代码在不同的地方运行会得到不同的结果?追溯newFunction()此时,我们需要追溯Function构造函数的定义:Function构造函数创建仅在全局范围内执行的函数。也就是说,由Function构造函数创建的函数只会在全局范围内实现。上述代码的不同执行结果是由不同执行环境的全局作用域不同造成的。接下来我们看看Node.js的全局作用域和浏览器环境的区别。Node.js和浏览器环境的全局作用域先看Node.js文档中的一段描述:在浏览器中,顶级作用域是全局作用域。这意味着在浏览器中varsomething将定义一个新的全局变量。在Node.js中这是不同的。顶级作用域不是全局作用域;Node.js模块中的varsomething将是该模块的本地内容。也就是说,Node.js和浏览器域中的全局角色明显不同。Node.js:最顶层作用域不是全局作用域。在Node.js模块中使用var定义变量,会在模块中定义一个局部变量;浏览器:最顶层的作用域是全局作用域。在浏览器中使用var定义变量将定义一个新的全局变量。Node.jsconsole.log(this)在不同场景下的表现:在一个空的JS文件(模块)中:会打印一个指向空模块的空对象{};inafunction:Node.js的全局函数会打印出作用域对象;在严格模式下的函数中:undefined将被打印出来,因为在严格模式下,函数没有局部作用域对象。从上面的例子我们可以看出这是一个空文件中的空对象,在非严格模式函数中这是一个全局对象。接下来我们再来看这个例子:从上面的例子我们可以看出模块文件中定义的变量是一个局部变量,在模块文件中是不能通过this访问的;模块文件中的this指向module.exports对象;new函数直接在全局作用域(即全局对象)执行;函数声明中的this指向全局作用域,即全局对象;函数声明中的变量会沿着作用域链逐级查找变量;作用域链:localScope->ModuleScope(module.exports)->GlobalScopeBrowser相比Node.js,浏览器的全局作用域更容易理解,浏览器的全局作用域就是window对象。看具体代码执行结果:从上面的代码我们可以看到,在浏览器控制台中:虽然都是全局变量,也就是都存在于全局作用域中,但是通过var声明的变量会在window上创建属性对象,通过用const声明的变量将不会;也就是说,global作用域和浏览器中的window对象不能完全相等,很容易混淆。与var变量不同,用const声明的全局常量不会成为window对象的属性。this指向window对象,可以通过this、globalThis、window访问window对象;在newFunction中,只能访问全局作用域,因为name1和name2都存在于全局作用域中,所以可以直接访问;函数声明中this的this指向window对象;在函数声明中,变量会沿着作用域链逐级查找;作用域链:局部作用域->全局作用域总结简单来说,Node.js中全局作用域的区别。:Node.js中的全局作用域指向全局对象,模块文件中的this指向module.exports,在模块文件中创建的变量会在局部作用域中声明;浏览器中的全局作用域指向window对象,全局声明用var声明的变量会在全局作用域中声明,用var声明的变量会添加相应的window属性,用const/let声明的变量不会有对应的window添加的属性。这也是一开始代码执行结果不一致的核心原因。参考Whatisthe'global'objectinNodeJSFunctionNode.jsDocumentsImmediatelyinvokedfunctionexpression-IIFEHowareselfinvokingfunctionshoistedfunctiondeclarationthis
