web-dev-qa-db-fra.com

Comment fonctionne le mot clé "this"?

J'ai remarqué qu'il ne semble pas y avoir d'explication claire sur le mot-clé this et sur son utilisation correcte (et incorrecte) en JavaScript sur le site Stack Overflow.

J'ai été témoin d'un comportement très étrange avec ce produit et je n'ai pas compris pourquoi cela s'était produit.

Comment fonctionne this et quand doit-il être utilisé?

1226
Maxim Gershkovich

Je recommande de lire l'article de Mike WestScope in JavaScript ( miroir ) en premier. C’est une excellente et conviviale introduction aux concepts de this et des chaînes d’étendue en JavaScript.

Une fois que vous commencez à vous habituer à this, les règles sont en réalité assez simples. Le norme ECMAScript 5.1 définit this:

§11.1.1 Le mot clé this

Le mot clé this correspond à la valeur de ThisBinding du contexte d'exécution en cours.

ThisBinding est quelque chose que l'interpréteur JavaScript gère lorsqu'il évalue le code JavaScript, à la manière d'un registre de CPU spécial qui contient une référence à un objet. L'interprète met à jour ThisBinding chaque fois qu'il établit un contexte d'exécution dans l'un des trois cas seulement suivants:

1. Contexte global global d'exécution

C’est le cas du code JavaScript qui est évalué au niveau supérieur, par exemple. directement dans un <script>:

<script>
  alert("I'm evaluated in the initial global execution context!");

  setTimeout(function () {
      alert("I'm NOT evaluated in the initial global execution context.");
  }, 1);
</script>

Lors de l'évaluation du code dans le contexte global global initial, ThisBinding est défini sur l'objet global, window ( §10.4.1.1 ).

Saisie du code eval

  • … Par un appel direct à eval() ThisBinding n'est pas modifié; c'est la même valeur que ThisBinding du contexte d'exécution appelant ( §10.4.2 (2) (a)).

  • … Sinon par un appel direct à eval()
    ThisBinding est défini sur l'objet global comme si s'exécutait dans le contexte d'exécution global initial ( §10.4.2 = (1)).

Le §15.1.2.1.1 définit ce qu'est un appel direct à eval(). eval(...) est un appel direct alors que quelque chose comme (0, eval)(...) ou var indirectEval = eval; indirectEval(...); est un appel indirect à eval(). Voir réponse de chuckj à (1, eval) ('this') vs eval ('this') en JavaScript? et ECM-262-5 de Dmitry Soshnikov Chapitre 2. Mode strict. lorsque vous pouvez utiliser un appel indirect eval().

Saisie du code de fonction

Cela se produit lors de l'appel d'une fonction. Si une fonction est appelée sur un objet, tel que dans obj.myMethod() ou l'équivalent obj["myMethod"](), alors ThisBinding est défini sur l'objet (obj dans l'exemple; §13.2.1 ). Dans la plupart des autres cas, ThisBinding est défini sur l'objet global ( §10.4. ).

La raison de l'écriture "dans la plupart des autres cas" est qu'il existe huit fonctions intégrées ECMAScript 5 qui permettent de spécifier ThisBinding dans la liste des arguments. Ces fonctions spéciales prennent une soi-disant thisArg qui devient le ThisBinding lors de l'appel de la fonction ( §10.4. ).

Ces fonctions intégrées spéciales sont les suivantes:

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Array.prototype.every( callbackfn [ , thisArg ] )
  • Array.prototype.some( callbackfn [ , thisArg ] )
  • Array.prototype.forEach( callbackfn [ , thisArg ] )
  • Array.prototype.map( callbackfn [ , thisArg ] )
  • Array.prototype.filter( callbackfn [ , thisArg ] )

Dans le cas des fonctions Function.prototype, elles sont appelées sur un objet fonction, mais plutôt que de définir ThisBinding sur l'objet fonction, ThisBinding est défini sur thisArg.

Dans le cas des fonctions Array.prototype, le callbackfn donné est appelé dans un contexte d'exécution où ThisBinding est défini sur thisArg s'il est fourni; sinon, à l'objet global.

Ce sont les règles pour JavaScript simple. Lorsque vous commencez à utiliser des bibliothèques JavaScript (par exemple, jQuery), vous pouvez constater que certaines fonctions de la bibliothèque manipulent la valeur de this. Les développeurs de ces bibliothèques JavaScript le font car cela tend à prendre en charge les cas d'utilisation les plus courants et les utilisateurs de la bibliothèque trouvent généralement ce comportement plus pratique. Lorsque vous transmettez des fonctions de rappel faisant référence à this avec des fonctions de bibliothèque, vous devez vous reporter à la documentation pour connaître les garanties éventuelles sur la valeur de this lors de l'appel de la fonction.

Si vous vous demandez comment une bibliothèque JavaScript manipule la valeur de this, elle utilise simplement l’une des fonctions JavaScript intégrées acceptant un thisArg. Vous aussi, vous pouvez écrire votre propre fonction en prenant une fonction de rappel et thisArg:

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

Il y a un cas spécial que je n'ai pas encore mentionné. Lors de la construction d'un nouvel objet via l'opérateur new, l'interpréteur JavaScript crée un nouvel objet vide, définit certaines propriétés internes, puis appelle la fonction constructeur sur le nouvel objet. Ainsi, quand une fonction est appelée dans un contexte constructeur, la valeur de this est le nouvel objet créé par l'interpréteur:

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

Fonctions de flèche

fonctions de flèche (introduit dans ECMA6) modifie la portée de this. Voir la question canonique existante, Fonction flèche vs déclaration/expressions de fonctions: sont-elles équivalentes/échangeables? pour plus d'informations. Mais en bref:

Les fonctions fléchées n'ont pas leur propre liaison this..... Au lieu de cela, ces identificateurs sont résolus dans la portée lexicale comme toute autre variable. Cela signifie qu'à l'intérieur d'une fonction de flèche, this... renvoie à la valeur de this dans l'environnement dans lequel la fonction de flèche est définie.

Juste pour le plaisir, testez votre compréhension avec quelques exemples

Pour afficher les réponses, passez la souris sur les cases jaune pâle.

  1. Quelle est la valeur de this sur la ligne marquée? Pourquoi?

    window - La ligne marquée est évaluée dans le contexte d'exécution global initial.

    if (true) {
        // What is `this` here?
    }
    
  2. Quelle est la valeur de this sur la ligne marquée lorsque obj.staticFunction() est exécuté? Pourquoi?

    obj - Lors de l'appel d'une fonction sur un objet, ThisBinding est défini sur l'objet.

    var obj = {
        someData: "a string"
    };
    
    function myFun() {
        return this // What is `this` here?
    }
    
    obj.staticFunction = myFun;
    
    console.log("this is window:", obj.staticFunction() == window);
    console.log("this is obj:", obj.staticFunction() == obj);
      
  3. Quelle est la valeur de this sur la ligne marquée? Pourquoi?

    window

    Dans cet exemple, l'interpréteur JavaScript entre le code de la fonction, mais comme myFun/obj.myMethod n'est pas appelé sur un objet, ThisBinding est défini sur window.

    Ceci diffère de Python, dans lequel accéder à une méthode (obj.myMethod) crée un objet méthode liée .

    var obj = {
        myMethod: function () {
            return this; // What is `this` here?
        }
    };
    var myFun = obj.myMethod;
    console.log("this is window:", myFun() == window);
    console.log("this is obj:", myFun() == obj);
      
  4. Quelle est la valeur de this sur la ligne marquée? Pourquoi?

    window

    Celui-ci était délicat. Lors de l'évaluation du code d'évaluation, this est obj. Toutefois, dans le code d'évaluation, myFun n'est pas appelé sur un objet. ThisBinding est donc défini sur window pour l'appel.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
    
  5. Quelle est la valeur de this sur la ligne marquée? Pourquoi?

    obj

    La ligne myFun.call(obj); appelle la fonction intégrée spéciale Function.prototype.call(), qui accepte thisArg comme premier argument.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        someData: "a string"
    };
    console.log("this is window:", myFun.call(obj) == window);
    console.log("this is obj:", myFun.call(obj) == obj);
      
1287
Daniel Trebbien

Le mot clé this se comporte différemment en JavaScript par rapport à une autre langue. Dans les langues orientées objet, le mot clé this fait référence à l'instance actuelle de la classe. En JavaScript, la valeur de this est principalement déterminée par le contexte d’appel de la fonction (context.function()) et par son emplacement.

1. Lorsqu'il est utilisé dans un contexte global

Lorsque vous utilisez this dans un contexte global, il est lié à un objet global (window dans un navigateur).

document.write(this);  //[object Window]

Lorsque vous utilisez this dans une fonction définie dans le contexte global, this est toujours lié à un objet global, car cette fonction est en réalité une méthode de contexte global.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

Ci-dessus, f1 devient une méthode d'objet global. Ainsi, nous pouvons également l'appeler sur l'objet window comme suit:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. Lorsqu'il est utilisé à l'intérieur de la méthode object

Lorsque vous utilisez le mot clé this dans une méthode d'objet, this est lié à l'objet "immédiat".

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

Ci-dessus, j'ai mis le mot immédiat entre guillemets. C’est pour préciser que si vous imbriquez l’objet dans un autre objet, alors this est lié au parent immédiat.

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

Même si vous ajoutez explicitement une fonction à l'objet en tant que méthode, les règles ci-dessus sont toujours respectées, c'est-à-dire que this pointe toujours sur l'objet parent immédiat.

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3. Lors de l'appel d'une fonction sans contexte

Lorsque vous utilisez this à l'intérieur d'une fonction appelée sans contexte (c'est-à-dire sur aucun objet), elle est liée à l'objet global (window dans le navigateur) (même si la fonction est définie à l'intérieur de l'objet ).

var context = "global";

var obj = {  
    context: "object",
    method: function () {                  
        function f() {
            var context = "function";
            return this + ":" +this.context; 
        };
        return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

Tout essayer avec des fonctions

Nous pouvons aussi essayer les points ci-dessus avec des fonctions. Cependant, il y a quelques différences.

  • Ci-dessus, nous avons ajouté des membres aux objets en utilisant la notation littérale d'objet. Nous pouvons ajouter des membres aux fonctions en utilisant this. pour les spécifier.
  • La notation littérale d'objet crée une instance d'objet que nous pouvons utiliser immédiatement. Avec function, il peut être nécessaire de créer d’abord son instance à l’aide de l’opérateur new.
  • De même, dans une approche littérale d'objet, nous pouvons explicitement ajouter des membres à un objet déjà défini à l'aide de l'opérateur point. Ceci est ajouté à l'instance spécifique uniquement. Cependant, j'ai ajouté une variable au prototype de la fonction afin qu'elle soit reflétée dans toutes les instances de la fonction.

Ci-dessous, j'ai essayé toutes les choses que nous avons faites avec Object et this ci-dessus, mais en créant d'abord une fonction au lieu d'écrire directement un objet.

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. `this` keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then `this` inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object's prototype chain, `this` refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4. Lorsqu'il est utilisé dans la fonction constructeur .

Lorsque la fonction est utilisée en tant que constructeur (c'est-à-dire lorsqu'elle est appelée avec le mot clé new), this dans le corps de la fonction pointe vers le nouvel objet en cours de construction.

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5. Lorsqu'il est utilisé dans une fonction définie sur la chaîne de prototypes

Si la méthode est sur la chaîne de prototype d'un objet, this à l'intérieur de cette méthode fait référence à l'objet sur lequel la méthode a été appelée, comme si la méthode était définie sur l'objet.

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6. Dans les fonctions call (), apply () et bind ()

  • Toutes ces méthodes sont définies sur Function.prototype.
  • Ces méthodes permettent d'écrire une fonction une fois et de l'invoquer dans un contexte différent. En d'autres termes, ils permettent de spécifier la valeur de this qui sera utilisée lors de l'exécution de la fonction. Ils prennent également tous les paramètres à transmettre à la fonction d'origine lorsqu'elle est appelée.
  • fun.apply(obj1 [, argsArray]) Définit obj1 comme valeur de this dans fun() et appelle fun() en transmettant les éléments de argsArray comme arguments. .
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Définit obj1 en tant que valeur de this dans fun() et appelle fun() en transmettant arg1, arg2, arg3, ... en tant qu'arguments.
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Retourne la référence à la fonction fun avec this fun amusante liée à obj1 et aux paramètres de fun lié aux paramètres spécifiés arg1, arg2, arg3,....
  • À présent, la différence entre apply, call et bind doit être apparue. apply permet de spécifier les arguments devant fonctionner en tant qu'objet de type tableau, c'est-à-dire un objet avec une propriété numérique length et les propriétés entières non négatives correspondantes. Alors que call permet de spécifier directement les arguments de la fonction. apply et call invoquent immédiatement la fonction dans le contexte spécifié et avec les arguments spécifiés. D'autre part, bind renvoie simplement la fonction liée à la valeur this spécifiée et aux arguments. Nous pouvons capturer la référence à cette fonction retournée en l'attribuant à une variable et plus tard, nous pouvons l'appeler à tout moment.
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7. this à l'intérieur des gestionnaires d'événements

  • Lorsque vous assignez une fonction directement aux gestionnaires d'événements d'un élément, l'utilisation de this directement dans la fonction de gestion des événements fait référence à l'élément correspondant. Cette affectation directe de fonction peut être effectuée à l'aide de la méthode addeventListener ou par le biais des méthodes d'enregistrement d'événements telles que onclick.
  • De même, lorsque vous utilisez this directement dans la propriété d'événement (comme <button onclick="...this..." >) de l'élément, il fait référence à l'élément.
  • Cependant, l'utilisation de this indirectement via l'autre fonction appelée dans la fonction de gestion des événements ou la propriété d'événement est résolue en objet global window.
  • Le même comportement que ci-dessus est obtenu lorsque nous associons la fonction au gestionnaire d'événements à l'aide de la méthode modèle d'enregistrement d'événements de Microsoft attachEvent. Au lieu d'attribuer la fonction au gestionnaire d'événements (et donc la méthode de la fonction de l'élément), il appelle la fonction sur l'événement (en l'appelant dans un contexte global).

Je recommande de mieux essayer ceci dans JSFiddle .

<script> 
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    } 
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);   
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>

8. this dans la fonction de flèche ES6

Dans une fonction de flèche, this se comportera comme des variables communes: elle sera héritée de sa portée lexicale. La fonction this, où la fonction de flèche est définie, sera la fonction de flèche this.

Donc, c'est le même comportement que:

(function(){}).bind(this)

Voir le code suivant:

const globalArrowFunction = () => {
  return this;
};

console.log(globalArrowFunction()); //window

const contextObject = {
  method1: () => {return this},
  method2: function(){
    return () => {return this};
  }
};

console.log(contextObject.method1()); //window

const contextLessFunction = contextObject.method1;

console.log(contextLessFunction()); //window

console.log(contextObject.method2()()) //contextObject

const innerArrowFunction = contextObject.method2();

console.log(innerArrowFunction()); //contextObject 
144
Mahesha999

Javascript est this

Appel de fonction simple

Considérons la fonction suivante:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function

Notez que nous l’utilisons en mode normal, c’est-à-dire que le mode strict n’est pas utilisé.

Lors de l'exécution dans un navigateur, la valeur de this serait consignée en tant que window. En effet, window est la variable globale dans la portée d'un navigateur Web.

Si vous exécutez ce même morceau de code dans un environnement tel que node.js, this fera référence à la variable globale de votre application.

Maintenant, si nous l'exécutons en mode strict en ajoutant l'instruction "use strict"; au début de la déclaration de fonction, this ne ferait plus référence à la variable globale dans aucun des environnements. Ceci est fait pour éviter les confusions en mode strict. this voudrait, dans ce cas, simplement enregistrer undefined, parce que c'est ce que c'est, il n'est pas défini.

Dans les cas suivants, nous verrions comment manipuler la valeur de this.

Appeler une fonction sur un objet

Il y a différentes facons de faire cela. Si vous avez appelé des méthodes natives en Javascript comme forEach et slice, vous devez déjà savoir que la variable this fait dans ce cas référence à la Object sur laquelle vous avez appelé cette fonction. (Notez qu'en JavaScript, à peu près tout est un Object, y compris Arrays et Functions). Prenez le code suivant par exemple.

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged

Si un Object contient une propriété qui contient un Function, la propriété est appelée une méthode. Cette méthode, lorsqu'elle est appelée, aura toujours sa variable this sur la variable Object à laquelle elle est associée. Cela est vrai pour les modes strict et non strict.

Notez que si une méthode est stockée (ou plutôt copiée) dans une autre variable, la référence à this n'est plus conservée dans la nouvelle variable. Par exemple:

// continuing with the previous code snippet

var myVar = myObj.thisMethod;
myVar();
// logs either of window/global/undefined based on mode of operation

Considérant un scénario plus pratique:

var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself

Le mot clé new

Considérons une fonction constructeur en Javascript:

function Person (name) {
    this.name = name;
    this.sayHello = function () {
        console.log ("Hello", this);
    }
}

var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`

Comment cela marche-t-il? Voyons ce qui se passe lorsque nous utilisons le mot clé new.

  1. L'appel de la fonction avec le mot clé new initialise immédiatement une Object de type Person.
  2. Le constructeur de cette Object a son constructeur défini sur Person. Notez également que typeof awal ne renverrait que Object.
  3. Le nouveau prototype Object se verrait attribuer le prototype de Person.prototype. Cela signifie que toute méthode ou propriété du prototype Person serait disponible pour toutes les instances de Person, y compris awal.
  4. La fonction Person elle-même est maintenant appelée; this étant une référence à l'objet nouvellement construit awal.

Assez simple, hein?

Notez que la spécification officielle ECMAScript ne dit nulle part que ces types de fonctions sont des fonctions réelles constructor. Ce ne sont que des fonctions normales, et new peut être utilisé pour n’importe quelle fonction. C'est juste que nous les utilisons comme tels, et nous les appelons comme tels seulement.

Appel de fonctions sur Fonctions: call et apply

Donc oui, puisque functions sont aussi Objects (et en fait, les variables de première classe en Javascript), même les fonctions ont des méthodes qui sont ... bien, des fonctions elles-mêmes.

Toutes les fonctions héritent de la variable globale Function, et deux de ses nombreuses méthodes sont call et apply, et les deux peuvent être utilisées pour manipuler la valeur de this dans la fonction qu'ils s'appellent.

function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);

Ceci est un exemple typique d'utilisation de call. En gros, il prend le premier paramètre et définit this dans la fonction foo comme référence à thisArg. Tous les autres paramètres passés à call sont passés à la fonction foo sous forme d'arguments.
Le code ci-dessus consignera donc {myObj: "is cool"}, [1, 2, 3] dans la console. Jolie façon de changer la valeur de this dans n’importe quelle fonction.

apply est presque identique à call accepte qu'il ne faut que deux paramètres: thisArg et un tableau contenant les arguments à transmettre à la fonction. Ainsi, l'appel call ci-dessus peut être traduit en apply comme ceci:

foo.apply(thisArg, [1,2,3])

Notez que call et apply peuvent remplacer la valeur de this définie par l'appel de la méthode par points, comme indiqué dans la deuxième puce. Assez simple :)

Présenter .... bind!

bind est un frère de call et apply. C'est également une méthode héritée par toutes les fonctions du constructeur global Function en Javascript. La différence entre bind et call/apply réside dans le fait que call et apply invoqueront en fait la fonction. bind, en revanche, renvoie une nouvelle fonction avec les paramètres thisArg et arguments prédéfinis. Prenons un exemple pour mieux comprendre ceci:

function foo (a, b) {
    console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */

bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`

Voyez-vous la différence entre les trois? C'est subtil, mais ils sont utilisés différemment. Comme call et apply, bind remplacera également la valeur de this définie par l'appel de la méthode par points.

Notez également qu'aucune de ces trois fonctions ne modifie la fonction d'origine. call et apply renverront la valeur des fonctions nouvellement construites tandis que bind renverra la fonction nouvellement construite, prête à être appelée.

Extra stuff, copier ceci

Parfois, vous n'aimez pas le fait que this change avec la portée, en particulier la portée imbriquée. Regardez l'exemple suivant.

var myObj = {
    hello: function () {
        return "world"
        },
    myMethod: function () {
        // copy this, variable names are case-sensitive
        var that = this;
        // callbacks ftw \o/
        foo.bar("args", function () {
            // I want to call `hello` here
            this.hello(); // error
            // but `this` references to `foo` damn!
            // oh wait we have a backup \o/
            that.hello(); // "world"
        });
    }
  };

Dans le code ci-dessus, nous voyons que la valeur de this a changé avec la portée imbriquée, mais nous voulions la valeur de this à partir de la portée d'origine. Nous avons donc "copié" this dans that et utilisé la copie à la place de this. Intelligent, hein?

Indice:

  1. Que contient la valeur this par défaut?
  2. Et si nous appelons la fonction comme une méthode avec une notation point-objet?
  3. Et si nous utilisions le mot clé new?
  4. Comment pouvons-nous manipuler this avec call et apply?
  5. Utiliser bind.
  6. Copier this pour résoudre les problèmes de portée imbriquée.
58
user3459110

"ceci" est tout au sujet de la portée. Chaque fonction a sa propre portée et, comme tout dans JS est un objet, même une fonction peut stocker certaines valeurs en elle-même en utilisant "this". OOP 101 enseigne que "ceci" ne s'applique qu'à instances d'un objet. Par conséquent, chaque fois qu'une fonction s'exécute, une nouvelle "instance" de cette fonction a une nouvelle signification pour "this".

La plupart des gens s'embrouillent lorsqu'ils essaient d'utiliser "ceci" à l'intérieur de fonctions de fermeture anonymes telles que:

 (fonction (valeur) {
 this.value = valeur; 
 $ ('. quelques éléments'). each (fonction (elt) {
 elt .innerHTML = this.value; // euh oh !! éventuellement indéfini 
}); 
}) (2); 

Donc ici, à l’intérieur de chaque (), "ceci" ne contient pas la "valeur" à laquelle vous vous attendez (de

this.value = valeur;
 (fonction (valeur) {
 var self = this; // petit changement 
 self.value = value; 
 $ ('. quelques-éléments') .each (fonction (elt) {
 elt.innerHTML = self.value; // phew !! == 2 
}); 
}) (2); 

Essaye le; vous commencerez à aimer ce modèle de programmation

47
arunjitsingh

Comme ce fil de discussion est remonté, j'ai compilé quelques points pour les lecteurs novices dans le sujet this.

Comment la valeur de this est-elle déterminée?

Nous utilisons cela de la même façon que nous utilisons les pronoms dans les langues naturelles comme l'anglais: "Jean court vite parce que il essaie de prendre le train. ”Au lieu de cela, nous aurions pu écrire“… John est essayer de prendre le train ".

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

this ne reçoit aucune valeur tant qu'un objet n'invoque pas la fonction où il est défini. Dans la portée globale, toutes les variables et fonctions globales sont définies sur l'objet window. Par conséquent, this dans une fonction globale fait référence à (et a la valeur de) l'objet global window.

Lorsque use strict, this dans les fonctions globales et anonymes non liées à un objet, contient la valeur undefined.

Le mot clé this est le plus mal compris lorsque: 1) nous empruntons une méthode qui utilise this, 2) nous assignons une méthode qui utilise this à une variable, 3) une fonction qui utilise this est transmise en tant que fonction de rappel et 4) this est utilisée dans une fermeture - une fonction interne. (2)

table

Qu'est-ce qui tient l'avenir

Définis dans Script ECMA 6 , les fonctions de flèche adoptent la liaison this à partir de la portée (fonction ou globale) englobante.

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!

Bien que les fonctions de flèche offrent une alternative à l’utilisation de bind(), il est important de noter qu’elles désactivent essentiellement le mécanisme traditionnel this au profit d’une portée lexicale plus largement comprise. (1)


Références:

  1. this & Object Prototypes , de Kyle Simpson. © 2014 Getify Solutions.
  2. javascriptissexy.com - http://goo.gl/pvl0GX
  3. Angus Croll - http://goo.gl/Z2Rac
16
carlodurso

this en JavaScript fait toujours référence au 'propriétaire' de la fonction qui est en cours d'exécution.

Si aucun propriétaire explicite n'est défini, le propriétaire le plus haut, l'objet window, est référencé.

Donc si je le faisais

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

this ferait référence à l'objet élément. Mais attention, beaucoup de gens font cette erreur.

<element onclick="someKindOfFunction()">

Dans ce dernier cas, vous faites simplement référence à la fonction et non à l'élément. Par conséquent, this fera référence à l'objet window.

16
Seph

Chaque une fonction contexte d'exécution en javascript a portéele contexte this paramètre défini par:

  1. Comment la fonction est appelée (y compris en tant que méthode objet, utilisation de call et apply, utilisation de new)
  2. Utilisation de bind
  3. Lexicalement pour les fonctions de flèche (ils adoptent le this de leur contexte d'exécution externe)

Quel que soit le contexte de cette portée, il est référencé par "this".

Vous pouvez changer cela définir la valeur de this portéele contexte en utilisant func.call, func.apply ou func.bind.

Par défaut, et ce qui déroute la plupart des débutants, quand un callback L’auditeur est appelé après la levée d’un événement sur un élément DOM, le contexte de la portée this la valeur de la fonction est l'élément DOM.

jQuery rend ce changement facile avec jQuery.proxy.

12
blockhead

Ici est une bonne source de this dans JavaScript.

Voici le résumé:

  • global this

    Dans un navigateur, au niveau global, this est l'objet window

    <script type="text/javascript">
      console.log(this === window); // true
      var foo = "bar";
      console.log(this.foo); // "bar"
      console.log(window.foo); // "bar"
    

    Dans node en utilisant repl, this est l'espace de noms supérieur. Vous pouvez vous y référer comme global.

    >this
      { ArrayBuffer: [Function: ArrayBuffer],
        Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
        Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
        ...
    >global === this
     true
    

    Dans node exécuté à partir d'un script, this à la portée globale commence sous la forme d'un objet vide. Ce n'est pas la même chose que global

    \\test.js
    console.log(this);  \\ {}
    console.log(this === global); \\ fasle
    
  • fonctionne comme ceci

Sauf dans le cas des gestionnaires d'événements DOM ou lorsqu'un thisArg est fourni (voir plus bas), à la fois dans le noeud et dans un navigateur utilisant this dans une fonction qui n'est pas appelée avec new fait référence à la portée mondiale…

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

Si vous utilisez use strict;, auquel cas this sera undefined

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

Si vous appelez une fonction avec new le this sera un nouveau contexte, il ne fera pas référence au global this.

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>
  • prototype ce

Les fonctions que vous créez deviennent des objets de fonction. Ils obtiennent automatiquement une propriété spéciale prototype, à laquelle vous pouvez affecter des valeurs. Lorsque vous créez une instance en appelant votre fonction avec new, vous avez accès aux valeurs que vous avez affectées à la propriété prototype. Vous accédez à ces valeurs à l'aide de this.

function Thing() {
  console.log(this.foo);
}

Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

C’est généralement une erreur d’affecter des tableaux ou des objets à la prototype. Si vous voulez que les instances aient chacune leurs propres tableaux, créez-les dans la fonction, pas dans le prototype.

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.Push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
  • object this

Vous pouvez utiliser this dans toute fonction d'un objet pour faire référence à d'autres propriétés de cet objet. Ce n'est pas la même chose qu'une instance créée avec new.

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"
  • événement DOM this

Dans un gestionnaire d'événements HTML DOM, this est toujours une référence à l'élément DOM auquel l'événement était associé.

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();

Sauf si vous bind le contexte

function Listener() {
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs Listener {handleClick: function}
}

var listener = new Listener();
document.getElementById("foo").click();
  • HTML this

Dans les attributs HTML dans lesquels vous pouvez insérer du JavaScript, this est une référence à l'élément.

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
  • eval this

Vous pouvez utiliser eval pour accéder à this.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();
  • avec ceci

Vous pouvez utiliser with pour ajouter this à la portée actuelle afin de lire et d'écrire sur les valeurs de this sans faire référence à this de manière explicite.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
  • jQuery this

dans de nombreux endroits, jQuery aura this faire référence à un élément DOM.

<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>
10
zangw

Il y a beaucoup de confusion quant à la manière dont "this" le mot clé est interprété en JavaScript. Espérons que cet article mettra tous ceux qui se reposent une fois pour toutes. Et beaucoup plus. Veuillez lire l'article en entier attentivement. Soyez prévenu que cet article est long.

Quel que soit le contexte dans lequel il est utilisé, "this" référence toujours le "objet actuel" en Javascript. Cependant, ce que "objet actuel" est différent selon contexte. Le contexte peut être exactement 1 des 6 suivants:

  1. Global (c'est-à-dire en dehors de toutes les fonctions)
  2. Appel direct "Fonction non liée" (c'est-à-dire une fonction qui a pas été liée par l'appel functionName.bind )
  3. Appel indirect "Fonction non liée" à travers functionName.call et functionName.apply
  4. Appel "à l'intérieur de la fonction" (c'est-à-dire une fonction qui a été liée en appelant functionName.bind )
  5. Alors que la création d'objet par "nouveau"
  6. Gestionnaire d'événements Inside Inline DOM

Ce qui suit décrit chacun de ces contextes un par un:

  1. Contexte global (c'est-à-dire en dehors de toutes les fonctions):

    En dehors de toutes les fonctions (c'est-à-dire dans un contexte global), le "objet actuel" (et par conséquent la valeur de "this") est toujours le "fenêtre" = objet pour les navigateurs.

  2. appel direct "fonction non liée":

    Dans un appel direct "Fonction non liée", l'objet qui a appelé l'appel de fonction devient "l'objet actuel" (et donc la valeur de "ceci"). Si une fonction est appelée sans un objet actuel explicite, l'objet objet actuel est soit l'objet "fenêtre" (pour le mode non strict) ou - non défini (pour le mode strict). Toute fonction (ou variable) définie dans Global Context devient automatiquement une propriété de "window" object.For, par exemple, une fonction est définie comme suit:

    function UserDefinedFunction(){
        alert(this)
        }
    

    il devient la propriété de l'objet window, comme si vous l'aviez défini comme

    window.UserDefinedFunction=function(){
      alert(this)
    }  
    

    En "mode non strict", appeler/appeler cette fonction directement via "UserDefinedFunction ()" l'appellera/l'appellera automatiquement en tant que "window.UserDefinedFunction ()" rendant - "fenêtre" comme "objet actuel" (et donc la valeur de "ceci") dans "UserDefinedFunction". L’appel de cette fonction en "mode non strict" aura les conséquences suivantes:

    UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()
    

    En "mode strict", l'appel/l'appel de la fonction directement via "UserDefinedFunction ()" sera "NOT" automatiquement appeler/l'invoquer sous forme de "window.UserDefinedFunction () ". Par conséquent, " objet actuel " (et la valeur de " ceci ") dans " UserDefinedFunction " doit être - non défini. L’appel de cette fonction en "Mode strict" aura pour résultat ce qui suit:

    UserDefinedFunction() // displays undefined
    

    Cependant, l’appeler explicitement en utilisant un objet window donnera les résultats suivants

    window.UserDefinedFunction() // "always displays [object Window]   irrespective of mode."
    

    Regardons un autre exemple. Veuillez regarder le code suivant

     function UserDefinedFunction()
        {
            alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
        }
    
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
          }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    o1.f() // Shall display 1,2,undefined,undefined
    o2.f() // Shall display undefined,undefined,3,4
    

    Dans l'exemple ci-dessus, nous voyons que quand "UserDefinedFunction" a été invoqué par le biais de o1, "this" prend la valeur de o1 = et la valeur de ses propriétés "a" et "b" sont affichées. La valeur de "c" et "d" était représentée par ndefined sous la forme o1 ne définit pas ces propriétés.

    De même, lorsque "UserDefinedFunction" a été invoqué par le biais de o2, "this" prend la valeur de o2 et la valeur de son propriétés "c" et "d" sont affichées.La valeur de "a" et "b" était affiché comme non défini comme o2 ne définit pas ces propriétés.

  3. Appel indirect "Fonction non liée" à travers functionName.call et functionName.apply :

    Quand une "fonction non liée" est appelée par functionName.call ou functionName.apply , le "objet actuel" (et par conséquent la valeur de "this") a la valeur "this" paramètre (premier paramètre) transmis à call/apply. Le code suivant montre la même chose.

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
           }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
    UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined
    
    UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
    UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4
    
    o1.f.call(o2) // Shall display undefined,undefined,3,4
    o1.f.apply(o2) // Shall display undefined,undefined,3,4
    
    o2.f.call(o1) // Shall display 1,2,undefined,undefined
    o2.f.apply(o1) // Shall display 1,2,undefined,undefined
    

    Le code ci-dessus montre clairement que la valeur "this" de toute "fonction non liée" peut être modifiée via call/apply. De même, si le paramètre "this" n'est pas explicitement passé à call/apply, "objet en cours" (et donc la valeur de "this ") est réglé sur " fenêtre " en mode non strict et " non défini " en mode strict.

  4. Appel "à l'intérieur de la fonction" (c'est-à-dire une fonction liée par un appel functionName.bind =):

    Une fonction liée est une fonction dont la valeur "this" a été fixée. Le code suivant montre comment "this" fonctionne en cas de fonction liée

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
              a:1,
              b:2,
              f:UserDefinedFunction,
              bf:null
           }
    var o2={
               c:3,
               d:4,
               f:UserDefinedFunction,
               bf:null
            }
    
    var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
    bound1() // Shall display 1,2,undefined,undefined
    
    var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
    bound2() // Shall display undefined,undefined,3,4
    
    var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
    bound3() // Shall display undefined,undefined,3,4
    
    var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
    bound4() // Shall display 1,2,undefined,undefined
    
    o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
    o1.bf() // Shall display undefined,undefined,3,4
    
    o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
    o2.bf() // Shall display 1,2,undefined,undefined
    
    bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    
    bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function
    
    o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
    

    Comme indiqué dans le code ci-dessus, la valeur "this" de toute "fonction liée" NE PEUT PAS être modifiée via un appel/une application. De même, si le paramètre "this" n'est pas explicitement passé à bind, "objet actuel" (et donc la valeur de "this") est réglé sur "fenêtre" en mode non strict et "indéfini" en mode strict. Une dernière chose. Lier une fonction déjà liée ne change pas la valeur de "this". Il reste défini comme la valeur définie par la première fonction de liaison.

  5. lors de la création d'un objet via "nouveau":

    Dans une fonction constructeur, le "objet actuel" (et donc la valeur de "ceci") fait référence à l'objet en cours de création via "new" quel que soit le statut de liaison de la fonction. Toutefois, si le constructeur est une fonction liée, il doit être appelé avec un ensemble d'arguments prédéfini, comme défini pour la fonction liée.

  6. gestionnaire d'événement Inside Inline DOM:

    Veuillez regarder l'extrait de code HTML suivant

    <button onclick='this.style.color=white'>Hello World</button>
    <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
    

    Le "this" dans les exemples ci-dessus fait référence à l'élément "button" et à l'élément "div" respectivement.

    Dans le premier exemple, la couleur de police du bouton doit être blanche lorsque vous cliquez dessus.

    Dans le deuxième exemple, lorsque l'élément "div" est cliqué, il appellera la fonction OnDivClick avec son deuxième paramètre référençant l'élément div cliqué. Cependant, la valeur de "ceci" dans OnDivClick NE DOIT PAS référencer l'élément cliqué div. Il doit être défini comme "objet window" ou "indéfini" dans non strict et modes strictes ( if OnDivClick est un fonction non liée) ou défini sur une valeur Bound prédéfinie (if OnDivClick est un fonction liée)

Ce qui suit résume l'article entier

  1. Dans le contexte global "this" se réfère toujours à l'objet "window"

  2. Chaque fois qu'une fonction est appelée, elle est appelée dans le contexte d'un objet ("objet en cours"). Si le objet actuel n'est pas explicitement fourni, le objet actuel est le "objet fenêtre" dans mode NON strict et "non défini" en mode strict par défaut.

  3. La valeur de "this" dans une fonction non liée est la référence à un objet dans le contexte duquel la fonction est appelée ("objet en cours")

  4. La valeur de "this" dans une fonction non liée peut être remplacée par les méthodes appel et appliquer de la fonction.

  5. La valeur de "this" est fixée pour une fonction liée et ne peut pas être remplacée par les méthodes call et apply de la fonction.

  6. La fonction de liaison et déjà liée ne change pas la valeur de "this". Il reste défini comme la valeur définie par la première fonction de liaison.

  7. La valeur de "this" dans un constructeur correspond à l'objet créé et initialisé.

  8. La valeur de "this" dans un gestionnaire d'événements DOM intégré est une référence à l'élément pour lequel le gestionnaire d'événements est fourni.

9
Arup Hore

L'article le plus détaillé et le plus complet sur this est probablement le suivant:

Explication douce du mot clé 'this' en JavaScript

L'idée sous-jacente à this est de comprendre que les types d'appel de fonction ont une importance significative dans la définition de la valeur de this.


Lorsque vous avez des problèmes pour identifier this, ne vous demandez pas :

Où est this pris de ?

mais faites demandez-vous:

Comment la fonction est-elle appelée ?

Pour une fonction de flèche (cas particulier de transparence de contexte), posez-vous les questions suivantes:

Quelle valeur a this où la fonction flèche est définie ?

Cet état d'esprit est correct lorsqu'il s'agit de this et vous évitera des maux de tête.

9
Dmitri Pavlutin

Daniel, explication géniale! Quelques mots à ce sujet et une bonne liste de this pointeur de contexte d'exécution en cas de gestionnaires d'événements.

En deux mots, this en JavaScript pointe l'objet de qui (ou du contexte d'exécution de qui) la fonction courante a été exécutée et qui est toujours en lecture seule, vous ne pouvez pas le définir quand même (une telle tentative aboutira à Message 'Invalid left-side-side in assignation'.

Pour les gestionnaires d'événements: Les gestionnaires d'événements inline, tels que <element onclick="foo">, écrasent tous les autres gestionnaires attachés auparavant et avant. Soyez donc prudent et il est préférable de ne pas utiliser la délégation d'événements en ligne. Et merci à Zara Alaverdyan qui m'a inspiré cette liste d'exemples à travers un débat dissident :)

  • el.onclick = foo; // in the foo - obj
  • el.onclick = function () {this.style.color = '#fff';} // obj
  • el.onclick = function() {doSomething();} // In the doSomething - Window
  • el.addEventListener('click',foo,false) // in the foo - obj
  • el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
  • <button onclick="this.style.color = '#fff';"> // obj
  • <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">
9
Arman McHitarian

C'est la meilleure explication que j'ai vue: Comprenez les scripts Java this avec clarté

La référence this fait TOUJOURS référence (et contient la valeur de) un objet - un objet singulier - et il est généralement utilisé dans une fonction ou une méthode, bien qu'il puisse être utilisé en dehors d'une fonction dans l'objet global. portée. Notez que lorsque nous utilisons le mode strict, cela contient la valeur indéfinie dans les fonctions globales et dans les fonctions anonymes qui ne sont liées à aucun objet.

Il y a quatre scénarios où this peut être déroutant:

  1. Lorsque nous passons une méthode (qui utilise this) comme argument à utiliser comme fonction de rappel.
  2. Lorsque nous utilisons une fonction interne (une fermeture). Il est important de noter que les fermetures ne peuvent pas accéder à la variable this de la fonction externe en utilisant le mot-clé this car la variable this est accessible uniquement par la fonction elle-même et non par les fonctions internes.
  3. Lorsqu'une méthode qui s'appuie sur this est affectée à une variable entre contextes, auquel cas this fait référence à un autre objet que celui initialement prévu.
  4. Lors de l'utilisation de this avec les méthodes bind, apply et call.

Il donne des exemples de code, des explications et des solutions qui, selon moi, ont été très utiles.

7
James Drinkard

Il est difficile d’acquérir une bonne compréhension de JS ou d’écrire plus que tout ce qui est trivial, si vous ne le comprenez pas bien. Vous ne pouvez pas vous permettre de faire un plongeon rapide :) Je pense que la meilleure façon de commencer avec JS est de commencer par regarder ces conférences vidéo de Douglas Crockford - http://yuiblog.com/crockford/ , qui couvre ceci et cela, et tout ce qui concerne JS.

6
tathagata

En termes pseudoclassiques, la façon dont de nombreuses conférences enseignent le mot-clé 'this' est comme un objet instancié par un constructeur de classe ou d'objet. Chaque fois qu'un nouvel objet est construit à partir d'une classe, imaginez que sous le capot, une instance locale d'un objet 'this' est créée et renvoyée. Je me souviens qu'il a enseigné comme ceci:

function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}

var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;
6
mrmaclean89

this est l’un des concepts mal compris de JavaScript car il se comporte différemment d’un endroit à l’autre. Tout simplement, this fait référence au "propriétaire" de la fonction que nous exécutons actuellement .

this aide à obtenir l'objet actuel (contexte d'exécution a.k.a.) avec lequel nous travaillons. Si vous comprenez dans quel objet la fonction en cours est exécutée, vous pouvez facilement comprendre quel this est actuellement

var val = "window.val"

var obj = {
    val: "obj.val",
    innerMethod: function () {
        var val = "obj.val.inner",
            func = function () {
                var self = this;
                return self.val;
            };

        return func;
    },
    outerMethod: function(){
        return this.val;
    }
};

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

Ci-dessus, nous créons 3 variables avec le même nom 'val'. L'une dans un contexte global, l'une dans obj et l'autre dans innerMethod de obj. JavaScript résout les identifiants dans un contexte particulier en remontant la chaîne de la portée du local au global.


Peu d'endroits où this peut être différencié

Appeler une méthode d'un objet

var status = 1;
var helper = {
    status : 2,
    getStatus: function () {
        return this.status;
    }
};

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

Lorsque line1 est exécuté, JavaScript établit un contexte d'exécution (EC) pour l'appel de la fonction, en définissant this sur l'objet référencé par tout ce qui précédait le dernier "." . ainsi, dans la dernière ligne, vous pouvez comprendre que a() a été exécuté dans le contexte global qui est le window.

Avec constructeur

this peut être utilisé pour faire référence à l'objet en cours de création

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined

Lorsque new Person() est exécuté, un nouvel objet est créé. Person est appelé et son this est défini pour référencer ce nouvel objet.

Appel de fonction

function testFunc() {
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;
}

var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

Si nous manquons le mot clé new, whatIsThis fait référence au contexte le plus global dans lequel il peut trouver (window)

Avec les gestionnaires d'événements

Si le gestionnaire d'événements est inline, this fait référence à l'objet global

<script type="application/javascript">
    function click_handler() {
        alert(this); // alerts the window object
    }
</script>

<button id='thebutton' onclick='click_handler()'>Click me!</button>

Lorsque vous ajoutez un gestionnaire d'événements via JavaScript, this fait référence à l'élément DOM qui a généré l'événement.


5
Nipuna

La valeur de "this" dépend du "contexte" dans lequel la fonction est exécutée. Le contexte peut être n’importe quel objet ou l’objet global, c’est-à-dire une fenêtre.

Ainsi, la sémantique de "ceci" est différente des langues traditionnelles OOP. Et cela pose des problèmes: 1. lorsqu'une fonction est passée à une autre variable (très probablement un rappel); et 2. lorsqu'une clôture est invoquée à partir d'une méthode membre d'une classe.

Dans les deux cas, ceci est défini sur window.

5
Trombe

Qu'est-ce que this aide? (La plus grande confusion de 'ceci' en javascript provient du fait qu'il n'est généralement pas lié à votre objet, mais à la portée d'exécution actuelle - cela peut ne pas être exactement comme cela que ça fonctionne mais c'est toujours ce que je ressens - voir l'article pour une explication complète)

3
Simon Groenewolt

Quelques infos sur this mot clé

Journalisons le mot clé this sur la console dans son étendue globale sans autre code, mais

console.log(this)

Dans Client/Navigateurthis le mot clé est un objet global qui est window

console.log(this === window) // true

et

Dans runtime Serveur/Noeud/Javascriptthis le mot clé est également un objet global qui est module.exports

console.log(this === module.exports) // true
console.log(this === exports) // true

Gardez à l'esprit que exports n'est qu'une référence à module.exports

3
unclexo

J'ai une vision différente de this des autres réponses que j'espère utiles.

Une façon de regarder JavaScript est de voir qu'il n'y a qu'une seule façon d'appeler une fonction1. Il est

functionObject.call(objectForThis, arg0, arg1, arg2, ...);

Il y a toujours une valeur fournie pour objectForThis.

Tout le reste est un sucre syntaxique pour functionObject.call

Donc, tout le reste peut être décrit par la façon dont cela se traduit par functionObject.call.

Si vous appelez simplement une fonction, alors this est "l'objet global" qui est la fenêtre dans le navigateur

function foo() {
  console.log(this);
}

foo();  // this is the window object

En d'autres termes,

foo();

a été effectivement traduit en

foo.call(window);

Notez que si vous utilisez le mode strict, alors this sera undefined

'use strict';

function foo() {
  console.log(this);
}

foo();  // this is the window object

ce qui signifie

En d'autres termes,

foo();

a été effectivement traduit en

foo.call(undefined);

En JavaScript, il existe des opérateurs tels que + et - et *. Il y a aussi l'opérateur de point qui est .

Lorsqu’il est utilisé avec une fonction à droite et un objet à gauche, l’opérateur . signifie "transmettre un objet comme this à la fonction.

Exemple

const bar = {
  name: 'bar',
  foo() { 
    console.log(this); 
  },
};

bar.foo();  // this is bar

En d'autres termes, bar.foo() se traduit par const temp = bar.foo; temp.call(bar);

Notez que peu importe la façon dont la fonction a été créée (surtout ...). Tout cela produira les mêmes résultats

const bar = {
  name: 'bar',
  fn1() { console.log(this); },
  fn2: function() { console.log(this); },
  fn3: otherFunction,
};

function otherFunction() { console.log(this) };

bar.fn1();  // this is bar
bar.fn2();  // this is bar
bar.fn3();  // this is bar

Encore une fois, tous ne sont que du sucre syntaxique pour

{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }

Une autre ride est la chaîne de prototypes. Lorsque vous utilisez a.b JavaScript commence par rechercher l'objet référencé directement par a pour la propriété b. Si b n'est pas trouvé sur l'objet, JavaScript recherchera dans le prototype de l'objet pour trouver b.

Il existe différentes manières de définir le prototype d'un objet, la plus courante en 2019 étant le mot clé class. Aux fins de this bien que ce ne soit pas grave. L’important est que, dans l’objet a de la propriété b s’il trouve la propriété b sur l’objet ou dans sa chaîne de prototypes si b finit par être une fonction, les mêmes règles que ci-dessus s'appliquent. La fonction b références sera appelée à l'aide de la méthode call et en transmettant a sous la forme objectForThis, comme indiqué au début de cette réponse.

Maintenant. Imaginons que nous créons une fonction qui définit explicitement this avant d’appeler une autre fonction, puis l’appelons avec l’opérateur . (point)

function foo() {
  console.log(this);
}

function bar() {
  const objectForThis = {name: 'moo'}
  foo.call(objectForThis);  // explicitly passing objectForThis
}

const obj = {
  bar,
};

obj.bar();  

Après la traduction pour utiliser call, obj.bar() devient const temp = obj.bar; temp.call(obj);. Lorsque nous entrons dans la fonction bar, nous appelons foo mais nous avons explicitement passé un autre objet pour objectForThis. Ainsi, lorsque nous arrivons à toto this est cet objet interne.

C’est ce que les fonctions bind et => fonctionnent efficacement. Ce sont des sucres plus syntaxiques. Ils construisent efficacement une nouvelle fonction invisible exactement comme bar ci-dessus, qui définit explicitement this avant d'appeler la fonction spécifiée. Dans le cas de bind this est défini sur ce que vous transmettez à bind.

function foo() {
  console.log(this);
}

const bar = foo.bind({name: 'moo'});

// bind created a new invisible function that calls foo with the bound object.

bar();  

// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above

bar.call({name: 'other'});

Notez que si functionObject.bind n'existait pas, nous pourrions créer le nôtre comme ceci

function bind(fn, objectForThis) {
  return function(...args) {
    return fn.call(objectForthis, ...args);
  };
}

et alors nous pourrions l'appeler comme ça

function foo() {
  console.log(this);
}

const bar = bind(foo, {name:'abc'});

Les fonctions de flèche, l’opérateur => sont un sucre syntaxique pour lier

const a = () => {console.log(this)};

est le même que

const tempFn = function() {console.log(this)}; 
const a = tempFn.bind(this);

Tout comme bind, une nouvelle fonction invisible est créée. Elle appelle la fonction donnée avec une valeur liée pour objectForThis mais, contrairement à bind, l'objet à lier est implicite. C'est ce que this se trouve lorsque l'opérateur => est utilisé.

Donc, tout comme les règles ci-dessus

const a = () => { console.log(this); }  // this is the global object
'use strict';
const a = () => { console.log(this); }  // this is undefined
function foo() {
  return () => { console.log(this); }
}

const obj = {
  foo,
};
const b = obj.foo();
b();

obj.foo() se traduit par const temp = obj.foo; temp.call(obj);, ce qui signifie que l'opérateur de flèche à l'intérieur de foo liera obj à une nouvelle fonction invisible et renverra cette nouvelle fonction invisible affectée à b . b() fonctionnera comme il le fait toujours sous la forme b.call(window) ou b.call(undefined) en appelant la nouvelle fonction invisible créée par foo. Cette fonction invisible ignore le this qui y est passé et transmet obj comme objectForThis` à la fonction de flèche.

Le code ci-dessus se traduit par

function foo() {
  function tempFn() {
    console.log(this);
  }
  return tempFn.bind(this);
}

const obj = {
  foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);

1apply est une autre fonction similaire à call

functionName.apply(objectForThis, arrayOfArgs);

Mais à partir de l’ES6, vous pouvez même traduire cela en

functionName.call(objectForThis, ...arrayOfArgs);
1
gman

cette utilisation pour Scope juste comme ça

  <script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
 txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>

la valeur de txt1 et txt est la même dans l'exemple ci-dessus $ (this) = $ ('# tbleName tbody tr') est identique

Résumé this Javascript:

  • La valeur de this est déterminée par comment la fonction n'est pas appelée, où elle a été créée!
  • Généralement, la valeur de this est déterminée par l'objet qui reste du point. (window dans l'espace global)
  • Dans les écouteurs d'événements, la valeur de this fait référence à l'élément DOM sur lequel l'événement a été appelé.
  • Lorsque la fonction est appelée avec le mot clé new, la valeur de this fait référence au nouvel objet créé.
  • Vous pouvez manipuler la valeur de this avec les fonctions: call, apply, bind

Exemple:

let object = {
  prop1: function () {console.log(this);}
}

object.prop1();   // object is left of the dot, thus this is object

const myFunction = object.prop1 // We store the function in the variable myFunction

myFunction(); // Here we are in the global space
              // myFunction is a property on the global object
              // Therefore it logs the window object
              
             

Exemple d'auditeurs d'événement:

document.querySelector('.foo').addEventListener('click', function () {
  console.log(this);   // This refers to the DOM element the eventListener was invoked from
})


document.querySelector('.foo').addEventListener('click', () => {
  console.log(this);  // Tip, es6 arrow function don't have their own binding to the this v
})                    // Therefore this will log the global object
.foo:hover {
  color: red;
  cursor: pointer;
}
<div class="foo">click me</div>

Exemple constructeur:

function Person (name) {
  this.name = name;
}

const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object

console.log(me.name); 
// Therefore, the name property was placed on the object created with new keyword.
0
Willem van der Veen

Quel est le mot clé "this" en JavaScript

Ce mot clé fait référence à un objet, cet objet qui exécute le bit actuel de code javascript.

En d'autres termes, chaque fonction javascript en cours d'exécution comporte une référence à son contexte d'exécution actuel, appelé this. Le contexte d'exécution signifie ici comment la fonction est appelée.

Pour comprendre ce mot clé, il suffit de savoir comment, quand et d'où la fonction est appelée, peu importe comment et où une fonction est déclarée ou définie.

function bike() {
  console.log(this.name);
}

var name = "Ninja";
var obj1 = { name: "Pulsar", bike: bike };
var obj2 = { name: "Gixxer", bike: bike };

bike();           // "Ninja"
obj1.bike();      // "Pulsar"
obj2.bike();      // "Gixxer"

Dans l'extrait de code ci-dessus, le travail de la fonction bike() imprime le this.name, ce qui signifie qu'il essaie d'imprimer la valeur de la propriété name du contexte d'exécution en cours(i.e.this object).

Dans l'extrait de code ci-dessus, lorsque la fonction bike() est appelée, elle affiche "Ninja" car le contexte d'exécution n'est pas spécifié. Par conséquent, son contexte global est défini par défaut et un nom de variable est présent dans le contexte global dont la valeur est "Ninja".

Dans le cas de l'appel obj1().bike(), "Pulsar" est imprimé et la raison derrière cette fonction est la fonction bike() est appelée avec le contexte d'exécution sous la forme obj1 alors this.name devient obj1.name. Idem avec l'appel obj2.bike() où le contexte d'exécution de la fonction bike() est obj2.

Liaison implicite et implicite de "this"

Si nous sommes en mode strict, la valeur par défaut de ce mot clé n'est pas définie, sinon ce mot clé agit comme un objet global, il est appelé liaison par défaut de ce mot clé. ( défaut est l'objet window dans le cas d'un navigateur ).

lorsqu'il y a une propriété d'objet que nous appelons en tant que méthode, cet objet devient cet objet ou cet objet de contexte d'exécution pour cette méthode, il s'agit de la liaison implicite de ce mot clé.

var obj1 = {
  name: "Pulsar",
  bike: function() {
    console.log(this.name);
  }
}
var obj2 = { name: "Gixxer", bike: obj1.bike };
var name = "Ninja";
var bike = obj1.bike;

bike();           // "Ninja"
obj1.bike();      // "Pulsar"
obj2.bike();      // "Gixxer"

Dans l'extrait de code ci-dessus, l'appel de fonction bike() est un exemple de liaison par défaut. obj1.bike() et obj2.bike() sont des exemples de liaison implicite. Ici, la fonction vélo est déclarée comme faisant partie de obj1 mais quel que soit le cas lorsque nous executeobj2.bike(), le contexte d’exécution est obj2 afin que obj2.name soit imprimé.

Il est important de savoir comment, quand et d'où la fonction est appelée, peu importe où une fonction est déclarée.

Liaison explicite et fixe du mot clé "this"

Si nous utilisons call et apply avec une fonction appelante, ces deux méthodes prennent comme premier paramètre leur contexte d'exécution. c'est cette liaison.

function bike() {
  console.log(this.name);
}

var name = "Ninja";
var obj = { name: "Pulsar" }

bike();           // "Ninja"
bike.call(obj);   // "Pulsar"

Dans l'extrait ci-dessus, si nous appelons la fonction bike avec la méthode call() en passant le contexte d'exécution obj comme premier argument, obj est affecté à cet objet et affiche "Pulsar", qui n'est rien d'autre que obj.name. C'est ce qu'on appelle la liaison explicite de ce mot clé.

en liaison fixe ou liaison dure

nous pouvons forcer cet objet à être toujours le même, peu importe d'où et comment il est appelé.

var bike = function() {
  console.log(this.name);
}
var name = "Ninja";
var obj1 = { name: "Pulsar" };
var obj2 = { name: "Gixxer" };

var originalBikeFun = bike;
bike = function() {
  originalBikeFun.call(obj1);
};

bike();           // "Pulsar"
bike.call(obj2);  // "Pulsar"

Comme dans l'extrait de code ci-dessus, bike() et bike.call(obj2) appellent tous deux "Pulsar", ce qui n'est rien d'autre que obj1.name signifie que le contexte d'exécution de la fonction bike est toujours obj1 et qu'il est dû à originalBikeFun.call(obj1); Ce type de liaison est simplement une autre forme de liaison explicite appelée liaison fixe.

0
Ashish