我有这段代码:
var obj1;
var obj2;
function x() {
obj1 = this;
}
function y() {
obj2 = this;
}
x();
y();
console.log(obj1 === obj2);
console.log(obj1 === this);
我在NodeJS中使用命令行:node app.js运行了这段代码,并在Chrome浏览器中作为脚本运行
结果:在NodeJS中,结果为:真假NodeJS结果
在Chrome浏览器中,结果是:true true浏览器结果
怎么会发生这种事?有人能解释一下引擎盖下面到底发生了什么吗?
在浏览器中,在全局范围内运行,this
在您的示例中始终是window
var obj1;
var obj2;
function x() {
obj1 = this; // window
}
function y() {
obj2 = this; // window
}
x();
y();
console.log(obj1 === obj2); // window === window = true
console.log(obj1 === this); // window === window = true
这不是它在Node中的工作方式。在Node.js中,所有模块(脚本文件)都在它们自己的闭包中执行,而浏览器则直接在全局范围内执行所有脚本文件。
换句话说,在Node中运行的几乎任何文件中,this
都将只是一个空对象,因为Node将代码包装在一个立即调用的匿名函数中,您可以使用global
访问该上下文中的全局范围。
Globals文档中也提到了这一点:
其中一些对象实际上并不在全局范围内,而是在模块范围内--这一点将会被注意到。
但是,当在node.js中调用一个没有特定上下文的函数时,它通常默认为全局对象--与前面提到的global
相同,作为它的执行上下文。
因此,在函数外部,this
是一个空对象,因为代码是按节点包装在函数中的,以便为每个模块(脚本文件)创建它自己的执行上下文;而在函数内部,因为它们是在没有指定执行上下文的情况下调用的,所以this
是节点global
对象
在node.js中,您将得到
var obj1;
var obj2;
function x() {
obj1 = this; // GLOBAL
}
function y() {
obj2 = this; // GLOBAL
}
x();
y();
console.log(obj1 === obj2); // GLOBAL === GLOBAL = true
console.log(obj1 === this); // GLOBAL === {} = false
其中最后一个this
确实是一个空对象,如上所述
为了完整起见,值得注意的是,在严格模式下,您将在浏览器中得到与在Node中相同的结果(true,false
),但这是因为变量与它们在Node中的结果正好相反
"use strict"
var obj1;
var obj2;
function x() {
obj1 = this; // undefined
}
function y() {
obj2 = this; // undefined
}
x();
y();
console.log(obj1 === obj2); // undefined === undefined = true
console.log(obj1 === this); // undefined === window = false
这是因为在严格模式下作为This
传递给函数的值不会被强制为对象(也就是“装箱”)。
对于非严格模式下的普通函数,This
总是一个对象,并且如果使用未定义
或null
this-value(即没有特定的执行上下文)调用,它总是全局对象。
自动装箱不仅是性能成本,而且在浏览器中公开全局对象也是安全隐患,因为全局对象提供了对“安全”JavaScript环境必须限制的功能的访问。
因此,对于严格模式函数,指定的this
不装箱到对象中,如果未指定,则this
将是函数中的undefined
,如上所示,但this
仍将是全局范围中的窗口。
在Node.js中的严格模式下也会发生同样的情况,其中函数内部的this
不再是global
而是undefined
,函数外部的this
仍然是相同的空对象,最终结果仍然是true,false
,但是在Node.js中严格模式下的this
的值也会不同。
Node在此处将this
显式设置为模块导出:
const result = compiledWrapper.apply(this.exports, args);
apply
所做的是显式地固定this
值(和参数)--在本例中,它将其设置为this.exports
。例如,您可以执行:
(function() { console.log(this.x); }).apply({x:3}); // alerts 3
节点重写是默认行为。但是,它必须使用global
调用对象内部的函数--这是JS规范规定的。
在浏览器上下文中,最后一个指向Windowobject,它确实存在于节点上下文中。因此,最后一个是一个空对象。然而,在函数中出现的这种情况指向节点上下文中的某个全局对象。