为什么“this”在javascript中引用forEach中的Window?

时间:2015-02-24 23:12:42

标签: javascript arrays

如果我运行此代码,窗口对象将被打印到控制台。

var arr= [1,2,34,5,6,7,7,8];
arr.forEach(function(e){
console.log(this);
});

为什么它不引用数组对象中的arr对象或特定项?我想了解它背后的原因,就像发生了什么。使用this或调用此函数的对象来定义new,对吗?

8 个答案:

答案 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 nullundefined的值调用函数,this将设置为全局反而是对象。这是一个refresher

  

10.4.3输入功能代码

     
      
  1. 如果功能代码为strict code,请将ThisBinding设置为 thisArg
  2.   
  3. 如果 thisArg null 未定义,则将ThisBinding设置为全局对象。
  4.   
  5. ...
  6.   

正如您所看到的,如果我们不处于严格模式(默认值),this将不会指向全局对象。


  

我想了解背后的原因

为什么决定以这种方式这样做可能只能由从事该语言工作的人解释。您可以在https://esdiscuss.orghttp://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等)函数与任何对象分离运行,因此传递给它们的函数默认在全局范围内执行。

你可以明确并以两种方式之一解决这个问题。

  1. 为forEach提供一个上下文(如其他所有答案所示)
  2. 这使用如下代码:

    var arr = [...];
    var iterator = function(e) { console.log(this); };
    arr.forEach(iterator, this);
    
    1. 使您的迭代函数首先显式绑定到您的对象
    2. 这使用如下代码:

      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在不同背景下的含义。