`this` 的默认绑定与 Chrome 浏览器和 Node.js 不同
Posted
技术标签:
【中文标题】`this` 的默认绑定与 Chrome 浏览器和 Node.js 不同【英文标题】:Default binding of `this` is different from Chrome browser and Node.js 【发布时间】:2015-01-17 20:18:09 【问题描述】:我正在从You Don't Know JS 阅读Chapter 2: this
All Makes Sense Now!,并决定做这个实验。
我有这个足够简单的脚本foo.js
:
var a = 'foo';
var output;
// lets find a way to output strings in both
// Chrome and Node.js
if (typeof alert === 'undefined')
output = console.log;
else
output = alert;
function getA()
return this.a;
var foo = getA();
output(foo);
当getA()
被调用时,我期待以下事情:
-
由于
getA
的调用点在全局范围内,getA()
将绑定到全局对象。
由于var a
是在全局范围内声明的,我认为全局对象会有一个名为a
的属性,该属性与变量a
相同。
因此,我希望 this.a
引用变量 a
。
因此我希望output(foo)
打印字符串foo
。
但是,在 Node.js(非严格模式)下运行时,输出如下:
$ node foo.js
undefined
然后我在一个简单的 html 页面中包含相同的脚本,并在 chrome 中加载它。
<html>
<head>
<script src="foo.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
Chrome alert
s 字符串 foo
,正如预期的那样。
为什么 Chrome 的输出与 Node.js 不同?
【问题讨论】:
【参考方案1】:NodeJS 的行为与浏览器不同。***范围不是全局范围,它是该文件或模块内的范围。删除“var”,您的代码将在节点环境中工作(a 将成为真正的全局),它将 console.log 字符串“foo”。
完整参考请参见以下页面:http://nodejs.org/api/globals.html
或
How to use global variable in node.js?
【讨论】:
那么为什么在这种情况下 NodeJS 的行为与浏览器不同呢?是的,我可以放弃var
,这个例子就可以了。但我对在 Node.js 中制作全局变量不感兴趣。我想了解this
的绑定在这里是如何工作的。在这个例子中,this
到底绑定了什么?
在您的浏览器中,“this”是窗口对象。在节点中,它是一个称为“全局”的对象。试试 console.log(this);在您的 getA() 方法中,并将其与 Chrome 控制台中的 console.log(this) 进行比较。您会注意到它们都是***对象,为您提供 javascript 原始和对象类型,例如 ArrayBuffer、setTimeout、setInterval。您还可以通过执行“global.name_of_var”在节点中定义一个全局对象。
查看 node 源代码中的第 788-795 行以了解它在做什么。它在编译时在源代码周围使用一种称为 NativeModule.wrap() 的方法。 github.com/joyent/node/blob/master/src/node.js#L788
@Krumia this
是全局对象。只是 a
在本地绑定到 foo.js 而不是全局。【参考方案2】:
由于 getA 的调用点在全局范围内,因此 getA() 将绑定到全局对象。
不,这不适用于节点 - 您的脚本被包装到函数 here 中,因此您的示例实际上是以下代码:
(function (exports, require, module, __filename, __dirname)
var a = 'foo';
var output;
// lets find a way to output strings in both
// Chrome and Node.js
if (typeof alert === 'undefined')
output = console.log;
else
output = alert;
function getA()
return this.a;
var foo = getA();
output(foo);
)(exports, require, module, 'file.js', '/dir/name');
【讨论】:
【参考方案3】:由于 getA 的调用点在全局范围内,因此 getA() 将绑定到全局对象。
这是对我书中this
绑定规则的误解。调用站点的位置(又名“在全球范围内”)完全不相关。这是拨打电话的方式,仅此而已。
在哪里getA()
发生并不重要,而getA()
是一个普通的普通函数调用。 那决定了您将获得绑定到 this
的全局对象以进行该调用。
这里的其他答案是正确的......您的节点主程序运行的范围实际上是一个模块(函数包装),而不是真正的全局范围。
【讨论】:
以上是关于`this` 的默认绑定与 Chrome 浏览器和 Node.js 不同的主要内容,如果未能解决你的问题,请参考以下文章