为什么 JavaScript "this" returns 在节点和浏览器环境中的值不同?
Why does JavaScript "this" returns different values in Node and Browser environments?
看完 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 执行它时,它 returns undefined
和 bar2
。然而,当我在浏览器中执行相同的片段时,它 returns bar1
和 bar2
,我认为这是正确的,因为变量 bar
是在全局范围内定义的。我无法理解为什么 Node 环境将它返回为 undefined
。请帮忙。
那是因为变量声明var bar = "bar1";
,那是在全局范围内声明的。所有全局变量都可用作 window 对象的属性。
当您在没有任何上下文的情况下调用 foo()
时,该方法的默认上下文是 window
对象(在非严格模式下),因此您的代码执行变为 console.log(window.bar);
,因为我们在上面看到你的 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>
在 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
对象上创建一个 属性 然后引用它。
看完 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 执行它时,它 returns undefined
和 bar2
。然而,当我在浏览器中执行相同的片段时,它 returns bar1
和 bar2
,我认为这是正确的,因为变量 bar
是在全局范围内定义的。我无法理解为什么 Node 环境将它返回为 undefined
。请帮忙。
那是因为变量声明var bar = "bar1";
,那是在全局范围内声明的。所有全局变量都可用作 window 对象的属性。
当您在没有任何上下文的情况下调用 foo()
时,该方法的默认上下文是 window
对象(在非严格模式下),因此您的代码执行变为 console.log(window.bar);
,因为我们在上面看到你的 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>
在 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
对象上创建一个 属性 然后引用它。