`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 alerts 字符串 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 不同的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript高级this绑定绑定优先级相关面试题与箭头函数

移动端和pc端事件绑定方式以及取消浏览器默认样式和取消冒泡

this关键字指向绑定

this关键字指向绑定

js中判定this的规则

如何使用chrome浏览器进行js调试找出元素绑定的点击事件