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

时间:2015-07-07 06:12:14

标签: javascript node.js function binding this

在观看了Kyle Simpson关于Pluralsight的Advanced 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是在全局范围内定义的。我无法理解为什么Node环境将其作为undefined返回。请帮助。

2 个答案:

答案 0 :(得分:2)

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

在node.js中,this这样的普通函数调用中foo()的值是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对象上愉快地创建属性然后引用它。

答案 1 :(得分:0)

这是因为变量声明var bar = "bar1";,它在全局范围内声明。所有全局变量都可用作窗口对象的属性。

当你在没有任何上下文的情况下调用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>