forEach函数调用的调用上下文(this)

35
我想知道forEach回调函数中的'this'值(或调用上下文)是什么。这段代码似乎不起作用:

我想知道forEach回调函数中的'this'值(或调用上下文)是什么。这段代码似乎不起作用:

var jow = [5, 10, 45, 67];

jow.forEach(function(v, i, a){

    this[i] = v + 1;

});

alert(jow);

感谢您向我解释。


5个回答

56

MDN指出:

array.forEach(callback[, thisArg])

如果提供了thisArg参数,则它将被用作forEach中每个回调函数调用的this值,就好像调用callback.call(thisArg, element, index, array)一样。如果thisArg为undefined或null,则在函数内部,this的值取决于函数是否处于严格模式(在严格模式下传递的值,在非严格模式下使用全局对象)。

因此简而言之,如果只提供了回调函数并且您处于非严格模式下(您提出的情况),则它将是全局对象(window)。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach


2
很奇怪。如果我在一个对象上创建一个方法,那么“this”值将是该对象。为什么这里不同呢? - kevinius
1
在forEach的主体内部,this确实是您特定的数组,但它与您提供的回调之间没有任何连接。回调会以forEach想要的方式被调用,具体取决于thisArgwindow或元素。 - Tibos
谢谢,我正在努力中... 我使用了jow数组作为thisArg,但是结果很糟糕:http://jsfiddle.net/39LSg/。为什么会这样?每次迭代时,-this-的值似乎会在窗口对象和jow数组之间跳转。 - kevinius
你正在使用数组中的值作为要更改的元素的索引。第一次迭代将jow [1]更改为5(用5替换2),第二次将jow [5]更改为5(在末尾添加另一个5),第三次将jow [3]更改为5(用5替换4),每隔一次迭代将jow [5]更改为5。 - Tibos
MDN表示,在严格模式下,进入执行上下文时_this的值保持不变(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)。在类方法的上下文中,作为forEach参数传递的嵌套经典函数将保留原始类实例作为this值(如果未强制使用其他函数),这听起来像箭头函数的行为,不是吗!? - Stphane
显示剩余2条评论

9

我完成了forEach方法的构建,并希望与大家分享这个图表,希望能帮助其他人理解其内部工作原理。

The forEach method


这个图表中的间距实际上并没有任何意义。 - neaumusic
6
我的意思是整体布局,这张图完全无法阅读。 - neaumusic
forEach() 上下文应该在 this 上下文内部。在 sdev 中,上下文几乎总是包装其子元素。我喜欢 UML 风格的方法。 - Nate T

6
在 forEach 中,this 指向全局的 window 对象。即使你从不同的对象(例如一个你创建的对象)调用它,这种情况仍然如此。
window.foo = 'window';

var MyObj = function(){
  this.foo = 'object';
};

MyObj.prototype.itirate = function () {
  var _this = this;

  [''].forEach(function(val, index, arr){
    console.log('this: ' + this.foo); // logs 'window'
    console.log('_this: ' + _this.foo); // logs 'object'
  });
};

var newObj = new MyObj();

newObj.itirate();
// this: window
// _this: object

4
大部分是正确的。但你可以在回调函数后面传入一个 thisArg 参数来定义 this 指向的对象。在你的例子中,你可以调用 [''].forEach(function (…) {…}, myObj),这样 this.foo 就会返回 'object' 而不是 'window' - chharvey
2
有趣的是,默认情况下,thisArg 引用全局 window 对象(我已在浏览器中测试过),而规范中说如果没有提供 thisArg,则默认应该为 undefined。MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach。规范:https://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18 - chharvey

6

如果你不向forEach传递第二个参数,this将指向全局对象。为了实现你想要做的事情,

var jow = [5, 10, 45, 67];

jow.forEach(function(v, i, a) {
    a[i] = v + 1;
});

console.log(jow);

输出

[ 6, 11, 46, 68 ]

1
我可以为“this”上下文问题提供非常简单的方法,它是这样的:每当您想知道“this”的上下文是什么时,请检查调用者左侧剩余的内容。如果没有调用者,则是全局对象,否则它是该对象实例。
示例:

let obj = { name:"test", fun:printName }

function printName(){
  console.log(this.name)
}

//who is left to the caller? obj! so obj will be 'this'
obj.fun() //test

//who is left to the caller? global! so global will be 'this'
printName() //undefined (global has no name property)

所以,在使用“foreach”时,如果您提供一个回调函数,实际上在“foreach”实现中会发生以下情况:

--> 您调用[1,2,3].foreach(callback,“可选This”)

 foreach(arr,cb)
 {
  for(i=0; i<arr.len;i++)
  {
   //who is left to the caller? global! so it will be 'this'
   cb(arr[i])
  }
 }

除非您使用可选的“this”或者使用箭头函数绑定回调函数,否则会出现这种情况,那么被调用的回调函数已经具有一个“this”对象,这在某种程度上“阻止”您更改其给定的上下文。更多关于bind的信息可以在这里找到 enter link description here。但基本上,bind的实现如下:

Function.prototype.bind = function (scope) {
    var fn = this;
    return function () {
        return fn.apply(scope);
    };
}

因此,您可以看到fn(回调函数)始终将使用您的“this”(作用域)调用。

希望对您有所帮助...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接