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é?
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:
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 ).
… 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()
.
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 (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 dethis
dans l'environnement dans lequel la fonction de flèche est définie.
Pour afficher les réponses, passez la souris sur les cases jaune pâle.
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?
}
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);
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 surwindow
.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);
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
estobj
. Toutefois, dans le code d'évaluation,myFun
n'est pas appelé sur un objet. ThisBinding est donc défini surwindow
pour l'appel.
function myFun() {
return this; // What is `this` here?
}
var obj = {
myMethod: function () {
eval("myFun()");
}
};
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écialeFunction.prototype.call()
, qui acceptethisArg
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);
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.
this
. pour les spécifier.new
.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 ()
Function.prototype
.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,...
.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
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
.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.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
.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
this
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
.
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 Array
s et Function
s). 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
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
.
new
initialise immédiatement une Object
de type Person
.Object
a son constructeur défini sur Person
. Notez également que typeof awal
ne renverrait que Object
.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
.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.
call
et apply
Donc oui, puisque function
s 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 :)
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.
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:
this
par défaut?new
?this
avec call
et apply
?bind
.this
pour résoudre les problèmes de portée imbriquée."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
Comme ce fil de discussion est remonté, j'ai compilé quelques points pour les lecteurs novices dans le sujet this
.
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)
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:
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.
Chaque une fonction contexte d'exécution en javascript a portéele contexte this paramètre défini par:
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.
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>
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 []
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"
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();
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>
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();
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"
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>
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:
Ce qui suit décrit chacun de ces contextes un par un:
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.
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.
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.
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.
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.
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
Dans le contexte global "this" se réfère toujours à l'objet "window"
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.
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")
La valeur de "this" dans une fonction non liée peut être remplacée par les méthodes appel et appliquer de la fonction.
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.
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.
La valeur de "this" dans un constructeur correspond à l'objet créé et initialisé.
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.
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.
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)">
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:
Il donne des exemples de code, des explications et des solutions qui, selon moi, ont été très utiles.
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.
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;
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é
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
.
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.
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
)
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.
.apply()
.call()
et .bind()
.var that = this
signifie en JavaScriptLa 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.
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)
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
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);
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
this
Javascript:this
est déterminée par comment la fonction n'est pas appelée, où elle a été créée!this
est déterminée par l'objet qui reste du point. (window
dans l'espace global)this
fait référence à l'élément DOM sur lequel l'événement a été appelé.new
, la valeur de this
fait référence au nouvel objet créé.this
avec les fonctions: call
, apply
, bind
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
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>
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.
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.