【问题标题】:Default binding of `this` is different from Chrome browser and Node.js`this` 的默认绑定与 Chrome 浏览器和 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() 被调用时,我期待以下事情:

  1. 由于getA的调用点在全局范围内,getA()将绑定到全局对象。
  2. 由于var a是在全局范围内声明的,我认为全局对象会有一个名为a的属性,该属性与变量a相同。
  3. 因此,我希望 this.a 引用变量 a。
  4. 因此我希望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 不同?

【问题讨论】:

    标签: javascript node.js google-chrome scope v8


    【解决方案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 的全局对象以进行该调用。

      这里的其他答案是正确的......您的节点主程序运行的范围实际上是一个模块(函数包装),而不是真正的全局范围。

      【讨论】:

        猜你喜欢
        • 2014-11-08
        • 2023-03-28
        • 1970-01-01
        • 2012-06-09
        • 1970-01-01
        • 1970-01-01
        • 2019-09-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多