Le this
mot clé se comporte différemment en JavaScript par rapport à d'autres langues. Dans les langages orientés objet, le this
mot - clé fait référence à l'instance actuelle de la classe. En JavaScript, la valeur de this
est 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 this
dans un contexte global, il est lié à un objet global ( window
dans le navigateur)
document.write(this); //[object Window]
Lorsque vous utilisez à l' this
intérieur d'une fonction définie dans le contexte global, this
est 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' window
objet 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 this
mot clé dans une méthode objet, this
est 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 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, elle suit toujours les règles ci-dessus, c'est-à-dire this
pointe 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 this
fonction interne invoquée sans aucun contexte (c'est-à-dire pas sur un 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 é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'
new
opé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 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 comme constructeur (c'est-à-dire lorsqu'elle est appelée avec un new
mot-clé), le this
corps 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' this
inté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
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 lors de son appel.
fun.apply(obj1 [, argsArray])
Définit obj1
comme la valeur de this
inside fun()
et appelle fun()
les éléments de passage de argsArray
comme arguments.
fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Définit obj1
comme la valeur de this
inside fun()
et les appels fun()
passant arg1, arg2, arg3, ...
comme arguments.
fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Renvoie la référence à la fonction fun
avec this
fun intérieur lié à obj1
et paramètres de fun
lié aux paramètres spécifiés arg1, arg2, arg3,...
.
- Désormais, la différence entre
apply
, call
et bind
doit être devenue apparente. apply
permet de spécifier les arguments pour fonctionner comme un objet de type tableau, c'est-à-dire un objet avec une length
propriété numérique et des propriétés entières non négatives correspondantes. Alors que call
permet de spécifier directement les arguments de la fonction. Les deux apply
et call
invoque immédiatement la fonction dans le contexte spécifié et avec les arguments spécifiés. En revanche, bind
renvoie simplement la fonction liée à la this
valeur 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. this
gestionnaires d'événements internes
- Lorsque vous affectez une fonction directement aux gestionnaires d'événements d'un élément, l'utilisation de
this
la 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 addeventListener
méthode ou par les méthodes d'enregistrement d'événements traditionnelles comme onclick
.
- De même, lorsque vous utilisez
this
directement à 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
this
indirecte 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. this
dans la fonction flèche ES6
Dans une fonction 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 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