为什么 JavaScript "this" 在 Node 和 Browser 环境中返回不同的值?



在Pluralsight上观看Kyle Simpson的高级JavaScript课程后,我创建了一个简单的代码片段来尝试this绑定。我通常在SublimeText编辑器中工作,并在其中配置节点构建引擎,偶尔我也会在浏览器中运行相同的代码。我注意到在Node和浏览器[Chrome]中执行代码时程序输出的一个差异。

下面是尝试this绑定的代码片段。

function foo() {
    console.log(this.bar);
}
var bar = "bar1";
var obj = {bar : "bar2"};
foo();
foo.call(obj);

当我使用Sublime执行它时,它返回undefinedbar2。然而,当我在浏览器中执行相同的代码片段时,它返回bar1bar2,我认为这是正确的,因为变量bar在全局范围内定义。我无法理解为什么节点环境将其返回为undefined。请帮助。

在node.js中,您的bar变量是该模块的局部模块变量。它不是一个全局变量。node中的全局变量必须显式地分配给global对象。node.js模块中的顶层声明不像在浏览器JS文件中那样是自动全局的。从技术上讲,它们存在于由模块加载器创建的函数作用域中,因此它们是模块函数作用域中的局部变量。

在node.js中,像foo()这样的普通函数调用中this的值是global对象。

但是,在node.js中,你的bar变量不是全局对象的属性。所以,当你试图引用this.bar时,那是global.bar,并且在全局对象上没有该名称的属性。

在node。js中,你可以这样做:

// create a function which is like the module scope
function myModuleFunc() {
    function foo() {
        // the value of this in a plain function call in node.js is the
        // global object
        console.log(global.bar);
    }
    // this isn't a global
    var bar = "bar1";
    foo();
}
// execute that module scope function
myModuleFunction();

并且,希望您可以看到为什么没有global.bar属性,因此您得到undefined


这一切都意外地在浏览器中工作,因为var bar是一个全局变量,全局变量在window对象和this === window上,所以它意外地工作。两错成正,有时才对。

正如我在我的评论中所说,强烈建议在严格模式下运行代码,有时事情不会意外工作,但不是其他人-这个问题将是高度一致的,当你写了错误的代码时,你会立即得到一个错误。


虽然你说你已经了解了浏览器环境中发生的事情,但由于你的问题是为什么这两者不同,我将描述浏览器的情况,只是为了涵盖所有的基础。

在浏览器中,普通函数调用(当不是严格模式时)的this的值是window对象。

在浏览器中,您的bar变量是一个全局变量,因此自动成为window对象的属性。

在浏览器中,你实际上是这样做的:

function foo() {
    console.log(window.bar);
}
window.bar = "bar1";
foo();

因此,您可以看到为什么它愉快地在window对象上创建一个属性,然后引用它。

这是因为变量声明var bar = "bar1";,它是在全局作用域中声明的。所有全局变量都可以作为window对象的属性使用。

当你在没有任何上下文的情况下调用foo()时,方法的默认上下文是window对象(在非严格模式下),所以你的代码执行变成了console.log(window.bar);,正如我们在上面看到的,你的bar变量已经将自己作为属性附加到窗口对象上,所以它打印值bar1

function foo() {
  snippet.log('is window:' + (this instanceof Window))
  snippet.log('bar value: ' + this.bar);
}
var bar = "bar1";
snippet.log('window.bar: ' + window.bar)
var obj = {
  bar: "bar2"
};
foo();
foo.call(obj);
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

最新更新