如果我运行此代码,窗口对象将被打印到控制台。
var arr= [1,2,34,5,6,7,7,8];
arr.forEach(function(e){
console.log(this);
});
为什么它不引用数组对象中的arr对象或特定项?我想了解它背后的原因,就像发生了什么。使用this
或调用此函数的对象来定义new
,对吗?
答案 0 :(得分:6)
.forEach()
根据第二个参数this
指定迭代器中thisArg
的值。
arr.forEach(callback[, thisArg])
因此,如果您提供它,它将只使用特定对象:
arr.forEach(function(e){
console.log(this);
}, arr); // <---
否则,this
的值将是普通函数调用的默认值 - strict mode中的undefined
或浏览器中的全局对象(window
)在非严格。
function foo(e) {
console.log(this);
}
foo(); // [object Window]
[1].forEach(foo); // (same)
尽管如此,arr
仍然提供给迭代器,就像它的第三个参数一样:
arr.forEach(function (e, i, arr) {
console.log(arr);
});
答案 1 :(得分:4)
这取决于两个不同的因素:引擎如何确定函数的this
值,thisArg
forEach
的可选参数,以及代码是否在{ {3}}
来自strict mode:
如果向
thisArg
提供了forEach()
参数,则会在调用时将其传递给callback
,以用作其this
值。否则,将传递值undefined
以用作其this
值。最终可通过回调观察到的this
值是根据确定函数所见的常规规则确定的。
这些规则为MDN:
在函数内部,其值取决于函数的调用方式。
function f1(){ return this; } f1() === window; // global object
在这种情况下,调用不会设置
this
的值。由于代码不是严格模式,因此其值必须始终为对象,因此默认为全局对象。 (重点补充)
请注意,此行为会在严格模式下更改。如果您将"use strict"
添加到回调的顶部,则会将undefined
记录到控制台。
简而言之,如果您希望this
值引用数组arr
,则只需要像这样调用forEach
:
var arr= [1,2,34,5,6,7,7,8];
arr.forEach(function(e){
console.log(this);
}, arr);
答案 2 :(得分:3)
因为specification这样说。相关部分:
15.4.4.18 Array.prototype.forEach(callbackfn [,thisArg])
...
5。如果提供了 thisArg ,请让 T 为 thisArg ;否则让 T 未定义。
...
7.c.ii使用 T 调用 callbackfn 的[[Call]]内部方法作为 this 值和参数列表包含 kValue , k 和 O 。
现在,我们都知道(希望)如果要使用this
null
或undefined
的值调用函数,this
将设置为全局反而是对象。这是一个refresher:
10.4.3输入功能代码
- 如果功能代码为strict code,请将ThisBinding设置为 thisArg 。
- 如果 thisArg null 或未定义,则将ThisBinding设置为全局对象。
- ...
醇>
正如您所看到的,如果我们不处于严格模式(默认值),this
将不会指向全局对象。
我想了解背后的原因
为什么决定以这种方式这样做可能只能由从事该语言工作的人解释。您可以在https://esdiscuss.org或http://es-discourse.com/询问。
答案 3 :(得分:2)
使用this
或者调用此函数的对象来定义
new
对吗?
Yes。在这种情况下,它会调用你的函数forEach
。由于没有做出特殊的预防措施 [1] ,它就像任何非方法函数调用一样,只为this
[2] 传递任何内容,这将导致你的函数的全局对象是草率代码 [3] 。
1:就像将second argument传递给forEach
一样,this
用于undefined
2:The spec说它应该通过this
3:意思是它不使用strict mode。在严格的代码中,undefined
确实是{{1}}。
答案 4 :(得分:1)
您传递给forEach的函数与您的对象没有相同的上下文。 forEach
(以及map
等)函数与任何对象分离运行,因此传递给它们的函数默认在全局范围内执行。
你可以明确并以两种方式之一解决这个问题。
这使用如下代码:
var arr = [...];
var iterator = function(e) { console.log(this); };
arr.forEach(iterator, this);
这使用如下代码:
var arr = [...];
var iterator = function(e) { console.log(this); };
var iteratorWithThisContext = iterator.bind(this);
arr.forEach(iteratorWithThisContext);
bind(<context>)
函数是一个核心javascript函数,用于获取任何函数和任何上下文,并返回一个新函数,该函数在调用时始终使用指定的上下文执行,无论是谁在进行调用,或者:
var fn = function() { console.log(this); }
fn(); // window
var fndoc = fn.bind(document);
fndoc(); // document
var arr = [];
var fnarr = fn.bind(arr);
fnarr(); // the array
答案 5 :(得分:0)
来自MDN:
如果向forEach()提供thisArg参数,则在调用时它将被传递给回调,以用作其此值。否则,将传递未定义的值以用作其此值。最终通过回调可观察到的这个值是根据确定函数所见的通常规则来确定的。
如果您希望this
成为数组,则必须使用可选第二个参数arr.forEach(function(e){}, arr);
来呼叫thisArg
。
答案 6 :(得分:0)
那很有意思。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
调用this
时,您可以为forEach
对象添加第二个参数。如果未提供,this
将被限制为与您只是编写for (var i in arr) {.. }
相同的范围。我怀疑他们这样做是为了使forEach
函数尽可能地与JS的内置语法特征紧密相关。
答案 7 :(得分:0)
因为此处调用的函数未被调用为对象方法,this
引用当前对象上下文,并且在浏览器控制台窗口中引用window
对象。
Mozilla Developer Network article深入探讨this
在不同背景下的含义。