简体   繁体   English

为什么JavaScript“ this”在节点和浏览器环境中返回不同的值?

[英]Why does JavaScript “this” returns different values in Node and Browser environments?

After watching Kyle Simpson's Advanced JavaScript course on Pluralsight, I created a simple code snippet to try out this binding. 看完Kyle Simpson在Pluralsight上的高级JavaScript课程之后,我创建了一个简单的代码片段来尝试this绑定。 I usually work in SublimeText editor and have node build engine configured in it and occasionally I run the same code in browser as well. 我通常在SublimeText编辑器中工作,并在其中配置了节点构建引擎,有时我也在浏览器中运行相同的代码。 I have noticed one difference in the program output when execute code in Node and in Browser [Chrome]. 我注意到在Node和浏览器[Chrome]中执行代码时,程序输出中的一个区别。

Following is the code snippet to try out this binding. 以下是尝试进行this绑定的代码段。

function foo() {
    console.log(this.bar);
}

var bar = "bar1";
var obj = {bar : "bar2"};

foo();
foo.call(obj);

When I execute it using Sublime, it returns undefined and bar2 . 当我使用Sublime执行它时,它返回undefinedbar2 However when I execute same snippet in a browser it returns bar1 and bar2 , which I think is correct since variable bar is defined at global scope. 但是,当我在浏览器中执行相同的代码片段时,它将返回bar1bar2 ,我认为这是正确的,因为变量bar是在全局范围内定义的。 I am not able to understand why Node environment is returning it as undefined . 我不明白为什么Node环境会返回undefined Kindly help. 请帮助。

In node.js, your bar variable is a module variable which is local to that module. 在node.js中,您的bar变量是该模块本地的模块变量。 It is not a global variable. 它不是全局变量。 Globals in node must be explicitly assigned to the global object. 必须将节点中的全局变量明确分配给global对象。 Top level declarations in a node.js module are not automatically globals like they are in a browser JS file. node.js模块中的顶级声明并不像浏览器JS文件中那样自动成为全局变量。 Technically, they exist inside a function scope that is created by the module loader so they are local variables to the module's function scope. 从技术上讲,它们存在于模块加载器创建的功能范围内,因此它们是模块功能范围的局部变量。

In node.js, the value of this in a plain function call like foo() is the global object. 在node.js中,像foo()这样的普通函数调用中的this值是global对象。

But, in node.js, your bar variable is NOT a property of the global object. 但是,在node.js中,您的bar变量不是全局对象的属性。 So, when you try to reference this.bar , that's global.bar and there is no property on the global object by that name. 因此,当您尝试引用this.bar ,即为global.bar并且该名称在全局对象上没有属性。

So, in node.js, you're essentially doing this: 因此,在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();

And, hopefully you can see why there is no global.bar property, thus you get undefined . 并且,希望您能看到为什么没有global.bar属性,从而得到undefined


This all accidentally works in a browser because var bar is a global and globals are on the window object and this === window so it accidentally works. 由于var bar是全局变量,而全局变量位于window对象上,并且this === window偶然地起作用,所以这一切在浏览器中都无法正常工作。 Two wrongs make a right that works only sometimes. 两种错误使一项权利有时仅适用。

As I said in my comment, it is highly recommended to run your code in strict mode and things will not accidentally work sometimes, but not others - this issue will all be highly consistent and you will get an immediate error when you have written the wrong sort of code. 就像我在评论中说的那样,强烈建议您以严格模式运行代码,有时情况不会偶然发生,但其他情况则不会正常-这个问题都是高度一致的,并且如果您写错了错误,您将立即得到错误。某种代码。


Though you said you already understand what is happening in the browser environment, since your question asks why the two are different, I will describe the browser situation just to cover all the bases. 尽管您已经说过您已经了解了浏览器环境中正在发生的事情,但是由于您的问题询问了两者为何不同,因此,我将仅出于涵盖所有基础的目的来描述浏览器的情况。

In the browser, the value of this in a plain function call (when not in strict mode) is the window object. 在浏览器中的值this在一个普通的函数调用(在不严格模式)是window对象。

In the browser, your bar variable is a global variable and thus automatically becomes a property of the window object. 在浏览器中, bar变量是全局变量,因此自动成为window对象的属性。

So, in the browser, you are essentially doing this: 因此,在浏览器中,您实际上是在这样做:

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

window.bar = "bar1";

foo();

And, thus you can see why it happily creates a property on the window object and then references it. 并且,因此,您可以看到为什么它愉快地在window对象上创建一个属性,然后引用它。

That is because of the variable declaration var bar = "bar1"; 那是因为变量声明var bar = "bar1"; , That is declared in the global scope. 在全局范围内声明。 All global variables are available as properties of the window object. 所有全局变量都可以用作窗口对象的属性。

When you call foo() without any context the default context of the method is the window object(in non strict mode), so your code execution becomes console.log(window.bar); 当您在没有任何上下文的情况下调用foo() ,该方法的默认上下文是window对象(在非严格模式下),因此您的代码执行将成为console.log(window.bar); , as we have seen above your bar variable has attached itself to the window object as a property, so its prints the value bar1 ,正如我们在上方看到的, bar变量已将其自身作为属性附加到window对象,因此其输出值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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM