在Nodejs和浏览器中,'this'关键字的行为是不同的

我有这段代码:

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中,结果是:true false 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是一个空对象,因为代码被Node包装在函数中,为每个模块(脚本文件)创build自己的执行上下文,而在函数内部,因为它们被调用时没有指定的执行上下文, this是Node 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确实是一个空的对象,如上所述


为了完整性,值得注意的是,在严格模式下,在浏览器( true, false )中会得到与Node中相同的结果,但这是因为variables与Node中的variables相反

 "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总是一个对象,如果用一个undefinednull this值(即没有特定的执行上下文) 调用 ,它总是全局对象。

不仅是自动装箱的性能成本,而且在浏览器中暴露全局对象也是一个安全隐患,因为全局对象提供了对“安全” JavaScript环境必须进行限制的function的访问。

因此,对于一个严格的模式函数,指定的this不会被装箱到一个对象中,如果没有指定的话, this将在函数内部是undefined ,如上所示,但是this仍然是全局范围中的窗口。

同样的事情发生在Node.js的严格模式中,在函数内部这个不再是GLOBAL而是undefinedthis函数的外部仍然是同一个空对象,最终的结果仍然是true, false ,但是在Node.js中严格模式下的值也会有所不同。

节点显式地将其设置为此处的模块导出:

 const result = compiledWrapper.apply(this.exports, args); 

什么apply是明确注意this值(和参数) – 在这种情况下 – 它将其设置为this.exports 。 例如,你可以做:

 (function() { console.log(this.x); }).apply({x:3}); // alerts 3 

节点覆盖的默认行为。 但是,它必须用global在对象内部调用函数 – 正如JS规范所要求的那样。

在浏览器上下文中,最后这个指向了存在于节点上下文中的Windowobject。 所以最后这是一个空的对象。 然而,在函数中出现的这个事件指向了Node-Context中的一些全局对象。

差别很简单

在节点环境中:

指的是module.exports或者简称module.exports 。 但在一个函数内部, 是指整个Node.js包。

你可以看到它,如果你login到控制台下面:

 function test(){ console.log('this inside a function = ',this); } console.log('this outside a function = ',this); test(); 

而在浏览器环境中, 函数内部或函数外部是指窗口对象,除非您使用的是另一个故事的关键字。

在Node.js和浏览器环境中执行前面的例子,你会明白的。

我现在手头没有Node.js服务器,但我想你可以自己研究这个问题,并给我们答案:D见下面的代码

尝试运行:

console.log(this.constructor.name+" "+obj1.constructor.name+" "+obj2.constructor.name);

而且你也可以在一个函数中debugging“Parent Class”的名字:

 function x() { console.log("x this: "+this.constructor.name); obj1 = this; } function y() { console.log("y this: "+this.constructor.name); obj2 = this; } 

而对于视图对象的方法/属性,你可以使用这样的东西:

 for (a in obj2) { console.log("obj2." + a + " = " + obj2[a]); }