Le thismot clé se comporte différemment en JavaScript par rapport à d'autres langues. Dans les langages orientés objet, le thismot - clé fait référence à l'instance actuelle de la classe. En JavaScript, la valeur de thisest déterminée par le contexte d'invocation de la fonction ( context.function()) et l'endroit où elle est appelée.
1. Lorsqu'il est utilisé dans un contexte mondial
Lorsque vous utilisez thisdans un contexte global, il est lié à un objet global ( windowdans le navigateur)
document.write(this); //[object Window]
Lorsque vous utilisez à l' thisintérieur d'une fonction définie dans le contexte global, thisest toujours lié à un objet global car la fonction est en fait une méthode de contexte global.
function f1()
{
return this;
}
document.write(f1()); //[object Window]
Ci f1- dessus est faite une méthode d'objet global. Ainsi, nous pouvons également l'appeler sur l' windowobjet comme suit:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. Lorsqu'il est utilisé à l'intérieur de la méthode objet
Lorsque vous utilisez un thismot clé dans une méthode objet, thisest lié à l'objet englobant "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. Cela signifie que si vous imbriquez l'objet dans un autre objet, il thisest 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, elle suit toujours les règles ci-dessus, c'est-à-dire thispointe vers 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 de la fonction sans contexte
Lorsque vous utilisez une thisfonction interne invoquée sans aucun contexte (c'est-à-dire pas sur un objet), elle est liée à l'objet global ( windowdans 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 également essayer les points ci-dessus avec des fonctions. Il existe cependant quelques différences.
- Ci-dessus, nous avons ajouté des membres aux objets en utilisant la notation littérale des objets. Nous pouvons ajouter des membres aux fonctions en utilisant
this. pour les préciser.
- La notation littérale d'objet crée une instance d'objet que nous pouvons utiliser immédiatement. Avec la fonction, nous devrons peut-être d'abord créer son instance à l'aide de l'
newopérateur.
- Toujours dans une approche littérale d'objet, nous pouvons explicitement ajouter des membres à un objet déjà défini en utilisant l'opérateur point. Cela est ajouté à l'instance spécifique uniquement. Cependant, j'ai ajouté une variable au prototype de fonction afin qu'elle se reflète dans toutes les instances de la fonction.
Ci-dessous, j'ai essayé toutes les choses que nous avons faites avec Object et thisci - 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 comme constructeur (c'est-à-dire lorsqu'elle est appelée avec un newmot-clé), le thiscorps de la fonction interne 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é à l'intérieur d'une fonction définie sur la chaîne du prototype
Si la méthode se trouve sur la chaîne prototype d'un objet, à l' thisintérieur d'une telle méthode fait référence à l'objet auquel 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. Fonctions internes 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
thisqui sera utilisée lors de l'exécution de la fonction. Ils prennent également tous les paramètres à transmettre à la fonction d'origine lors de son appel.
fun.apply(obj1 [, argsArray])Définit obj1comme la valeur de thisinside fun()et appelle fun()les éléments de passage de argsArraycomme arguments.
fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Définit obj1comme la valeur de thisinside fun()et les appels fun()passant arg1, arg2, arg3, ...comme arguments.
fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Renvoie la référence à la fonction funavec thisfun intérieur lié à obj1et paramètres de funlié aux paramètres spécifiés arg1, arg2, arg3,....
- Désormais, la différence entre
apply, callet binddoit être devenue apparente. applypermet de spécifier les arguments pour fonctionner comme un objet de type tableau, c'est-à-dire un objet avec une lengthpropriété numérique et des propriétés entières non négatives correspondantes. Alors que callpermet de spécifier directement les arguments de la fonction. Les deux applyet callinvoque immédiatement la fonction dans le contexte spécifié et avec les arguments spécifiés. En revanche, bindrenvoie simplement la fonction liée à la thisvaleur spécifiée et aux arguments. Nous pouvons capturer la référence à cette fonction retournée en l'affectant à 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. thisgestionnaires d'événements internes
- Lorsque vous affectez une fonction directement aux gestionnaires d'événements d'un élément, l'utilisation de
thisla fonction de gestion d'événements directement à l'intérieur fait référence à l'élément correspondant. Une telle affectation directe de fonction peut être effectuée en utilisant la addeventListenerméthode ou par les méthodes d'enregistrement d'événements traditionnelles comme onclick.
- De même, lorsque vous utilisez
thisdirectement à l'intérieur de 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
thisindirecte via l'autre fonction appelée à l'intérieur de la fonction de gestion des événements ou de la propriété d'événement se résout en l'objet global window.
- Le même comportement ci-dessus est obtenu lorsque nous attachons la fonction au gestionnaire d'événements à l'aide de la méthode du modèle d'enregistrement d'événements de Microsoft
attachEvent. Au lieu d'affecter la fonction au gestionnaire d'événements (et donc de créer la méthode de fonction de l'élément), il appelle la fonction sur l'événement (l'appelle effectivement dans le 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. thisdans la fonction flèche ES6
Dans une fonction flèche, thisse comportera comme des variables communes: elle sera héritée de sa portée lexicale. La fonction this, où la fonction flèche est définie, sera celle de la fonction 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