web-dev-qa-db-fra.com

Le contexte d'invocation (this) de l'appel de fonction forEach

Je me demandais quelle était la valeur "this" (ou contexte d'invocation) de la fonction de rappel forEach. Ce code ne semble pas fonctionner:

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

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

    this[i] = v + 1;

});

alert(jow);

Merci de m'expliquer.

25
kevinius

J'ai terminé la construction de la méthode forEach et je voulais partager ce diagramme avec tout le monde, en espérant qu'il aide quelqu'un d'autre à essayer de comprendre son fonctionnement interne.

The forEach method

10
kevinius

MDN déclare:

array.forEach (rappel [ thisArg])

Si un paramètre thisArg est fourni à forEach, il sera utilisé comme valeur this pour chaque appel de rappel, comme si callback.call (thisArg, élément, index, tableau) était appelé. Si thisArg est indéfini ou nul, la valeur this dans la fonction dépend si la fonction est en mode strict ou non (valeur transmise si en mode strict, objet global si en mode non strict).

Donc, en bref, si vous fournissez uniquement le rappel et que vous êtes en mode non strict (le cas que vous avez présenté), ce sera l'objet global (fenêtre).

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

44
Tibos

Dans forEach, this fait référence à l'objet global window. C'est le cas même si vous l'appelez depuis un autre objet (c'est-à-dire que vous avez créé)

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
vladvlad

Si vous ne passez pas le deuxième paramètre à forEach, this pointera vers l'objet global. Pour réaliser ce que vous essayez de faire

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

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

console.log(jow);

Sortie

[ 6, 11, 46, 68 ]
3
thefourtheye

J'ai une approche très simple pour la question de contexte "ceci" et ça se passe comme ceci: chaque fois que vous voulez savoir quel est le contexte de "ceci", vérifiez qui est laissé à l'appelant s'il n'y a pas d'appelant à gauche que lui est le global sinon c'est cette instance d'objet:

Exemples:

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)

Donc, pour le cas 'foreach' lorsque vous donnez une fonction de rappel, ce qui se passe réellement dans l'implémentation foreach est quelque chose comme ça:

-> vous appelez [1,2,3] .foreach (rappel, 'facultatif 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])
  }
 }

Sauf si vous lui donnez l'option 'this' ou que vous liez le rappel avec un this (par exemple une fonction de flèche) si cela se produit, le callback appelé a déjà un obj 'this' qui vous empêche de modifier le contexte donné plus d'informations sur bind peuvent être trouvées ici entrez la description du lien ici Mais fondamentalement, l'implémentation de bind ressemble à ceci:

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

Ainsi, vous pouvez voir que le fn (votre rappel) sera toujours appelé avec votre 'ceci' (portée)

J'espère que cela aide...

0
benchuk