Comment fonctionne le mot-clé «this»?
J'ai remarqué qu'il ne semble pas y avoir d'explication claire de ce qu'est le this
mot-clé et comment il est correctement (et incorrectement) utilisé en JavaScript sur le site Stack Overflow.
J'ai été témoin d'un comportement très étrange avec lui et je n'ai pas compris pourquoi cela s'est produit.
Comment ça this
marche et quand faut-il l'utiliser?
Réponses
Je recommande la lecture de Mike West article de Scope en JavaScript ( miroir ) en premier. C'est une excellente introduction conviviale aux concepts this
et aux chaînes de portée en JavaScript.
Une fois que vous commencez à vous y habituer this
, les règles sont en fait assez simples. La norme ECMAScript 5.1 définit this
:
§11.1.1 Le
this
mot-cléLe
this
mot-clé évalue la valeur de ThisBinding du contexte d'exécution actuel
ThisBinding est quelque chose que l'interpréteur JavaScript gère lorsqu'il évalue le code JavaScript, comme un registre CPU spécial qui contient une référence à un objet. L'interpréteur met à jour ThisBinding chaque fois que vous établissez un contexte d'exécution dans l'un des trois cas différents:
1. Contexte d'exécution global initial
C'est le cas du code JavaScript qui est évalué au plus haut niveau, par exemple directement à l'intérieur d'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 d'exécution global initial, ThisBinding est mis à l'objet global, window
( §10.4.1.1 ).
2. Saisie du code d'évaluation
… Par un appel direct à
eval()
ThisBinding reste inchangé; c'est la même valeur que ThisBinding du contexte d'exécution appelant ( §10.4.2 (2) (a)).…
eval()
Sinon par un appel direct à ThisBinding est mis à l'objet global comme s'il s'exécutait dans le contexte initial d'exécution globale ( §10.4.2 (1)).
Le §15.1.2.1.1 définit ce qu'est un appel direct eval()
. Fondamentalement, eval(...)
est un appel direct alors que quelque chose comme (0, eval)(...)
ou var indirectEval = eval; indirectEval(...);
est un appel indirect à eval()
. Voir la réponse de chuckj à (1, eval) ('this') vs eval ('this') en JavaScript? et ECMA-262-5 de Dmitry Soshnikov en détail. Chapitre 2. Mode strict. pour quand vous pourriez utiliser un eval()
appel indirect .
3. Saisie du code de fonction
Cela se produit lors de l'appel d'une fonction. Si une fonction est appelée sur un objet, comme dans obj.myMethod()
ou l'équivalent obj["myMethod"]()
, alors ThisBinding est mis à 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.3 ).
La raison d'écrire «dans la plupart des autres cas» est qu'il existe huit fonctions intégrées ECMAScript 5 qui permettent à ThisBinding d'être spécifié dans la liste d'arguments. Ces fonctions spéciales prennent un soi-disant thisArg
qui devient le ThisBinding lors de l'appel de la fonction ( §10.4.3 ).
Ces fonctions intégrées spéciales sont:
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 Function.prototype
fonctions, elles sont appelées sur un objet fonction, mais plutôt que de définir ThisBinding sur l'objet fonction, ThisBinding prend la valeur thisArg
.
Dans le cas des Array.prototype
fonctions, le donné callbackfn
est appelé dans un contexte d'exécution où ThisBinding est mis à thisArg
s'il est fourni; sinon, à l'objet global.
Telles sont les règles du JavaScript brut. Lorsque vous commencez à utiliser des bibliothèques JavaScript (par exemple jQuery), vous pouvez constater que certaines fonctions de bibliothèque manipulent la valeur de this
. Les développeurs de ces bibliothèques JavaScript le font car elles ont tendance à 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 this
vous passez des fonctions de rappel faisant référence à des fonctions de bibliothèque, vous devez vous référer à la documentation pour toute garantie sur la valeur de this
lorsque la fonction est appelée.
Si vous vous demandez comment une bibliothèque JavaScript manipule la valeur de this
, la bibliothèque utilise simplement l'une des fonctions JavaScript intégrées acceptant un fichier 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 particulier que je n'ai pas encore mentionné. Lors de la construction d'un nouvel objet via l' new
opérateur, 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, lorsqu'une fonction est appelée dans un contexte de constructeur, la valeur de this
est le nouvel objet que l'interpréteur a créé:
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 fléchées
Les fonctions fléchées (introduites dans ECMA6) modifient la portée de this
. Voir la question canonique existante, Fonction Arrow vs déclaration / expressions de fonction: Sont-elles équivalentes / échangeables? pour plus d'informations. Mais en bref:
Les fonctions fléchées n'ont pas leur propre
this
... liaison. 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
... se réfèrent aux valeurs dethis
dans l'environnement dans lequel la fonction de flèche est définie.
Juste pour le plaisir, testez votre compréhension avec quelques exemples
Pour révéler les réponses, passez la souris sur les cases gris clair.
- Quelle est la valeur de
this
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
à la ligne marquée quandobj.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
la ligne marquée? Pourquoi?
window
Dans cet exemple, l'interpréteur JavaScript entre le code de fonction, mais comme
myFun
/obj.myMethod
n'est pas appelé sur un objet, ThisBinding est défini surwindow
.Ceci est différent de Python, dans lequel l'accès à une méthode (
obj.myMethod
) crée un objet méthode lié .
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
la ligne marquée? Pourquoi?
window
Celui-ci était délicat. Lors de l'évaluation du code eval,
this
estobj
. Cependant, dans le code eval,myFun
n'est pas appelé sur un objet, donc ThisBinding est défini surwindow
pour l'appel.
<!-- no snippet because, seemingly, eval doesn’t work in snippets -->
function myFun() {
return this; // What is `this` here?
}
var obj = {
myMethod: function () {
eval("myFun()");
}
};
- Quelle est la valeur de
this
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 this
mot-clé se comporte différemment en JavaScript par rapport aux autres langages. 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'appel de function ( context.function()
) et par 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 puisque 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 window
objet comme suit:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. Lorsqu'il est utilisé dans 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. C'est pour faire remarquer 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, qui this
pointe toujours 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 d'une fonction sans contexte
Lorsque vous utilisez une this
fonction interne qui est appelé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. Cependant, il existe quelques différences.
- Ci-dessus, nous avons ajouté des membres aux objets en utilisant la notation littérale d'objet. Nous pouvons ajouter des membres aux fonctions en utilisant
this
. pour les spécifier. - La notation littérale d'objet crée une instance d'objet que nous pouvons utiliser immédiatement. Avec la fonction, nous pouvons avoir besoin de créer d'abord son instance à l'aide de l'
new
opérateur. - Également dans une approche littérale d'objet, nous pouvons ajouter explicitement des membres à un objet déjà défini à l'aide de 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 soit reflétée dans toutes les instances de la fonction.
Ci-dessous, j'ai essayé toutes les choses que nous avons faites avec Object et this
au - 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é à l'intérieur de 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 à l'intérieur 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 de la fonction définie sur la chaîne prototype
Si la méthode est sur la chaîne de prototypes d'un objet, à l' this
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. 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 acceptent également tous les paramètres à passer à la fonction d'origine lorsqu'elle est appelée. fun.apply(obj1 [, argsArray])
Définitobj1
comme valeur dethis
insidefun()
et appellefun()
des éléments de passageargsArray
comme ses arguments.fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Définitobj1
la valeur dethis
insidefun()
et les appelsfun()
passantarg1, arg2, arg3, ...
comme ses arguments.fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Renvoie la référence à la fonctionfun
avecthis
fun lié à l'intérieurobj1
et les paramètres defun
liés aux paramètres spécifiésarg1, arg2, arg3,...
.- Maintenant la différence entre
apply
,call
etbind
devait se manifester.apply
permet de spécifier les arguments pour fonctionner comme un objet de type tableau, c'est-à-dire un objet avec unelength
propriété numérique et des propriétés d'entier non négatives correspondantes. Alors quecall
permet de spécifier directement les arguments de la fonction. Bothapply
andcall
appelle 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 à lathis
valeur 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
gestionnaires d'événements internes
- Lorsque vous attribuez 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 uneaddeventListener
méthode ou par les méthodes traditionnelles d'enregistrement d'événements commeonclick
. - De même, lorsque vous utilisez
this
directement à l'intérieur de la propriété event (like<button onclick="...this..." >
) de l'élément, cela 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 d'événements ou de la propriété d'événement résout l'objet globalwindow
. - Le même comportement ci-dessus est obtenu lorsque nous attachons la fonction au gestionnaire d'événements à l'aide de la méthode de modèle d'inscription d'événements de Microsoft
attachEvent
. Au lieu d'affecter la fonction au gestionnaire d'événements (et de faire ainsi la méthode de fonction de l'élément), il appelle la fonction sur l'événement (l'appelant effectivement 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 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
Javascript est this
Appel de fonction simple
Considérez la fonction suivante:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
Notez que nous l'exécutons 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 enregistrée comme window
. C'est parce que window
c'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
ferait référence à la variable globale dans 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 l'un ou l'autre des environnements. Ceci est fait pour éviter les confusions en mode strict. this
serait, dans ce cas, simplement enregistrer undefined
, car c'est ce que c'est, il n'est pas défini.
Dans les cas suivants, nous verrons comment manipuler la valeur de this
.
Appeler une fonction sur un objet
il y a différentes facons de faire cela. Si vous avez appelé des méthodes natives en Javascript comme forEach
et slice
, vous devriez déjà savoir que la this
variable dans ce cas fait référence au Object
sur lequel vous avez appelé cette fonction (notez qu'en javascript, à peu près tout est an 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 an Object
contient une propriété qui contient a Function
, la propriété est appelée une méthode. Cette méthode, lorsqu'elle est appelée, aura toujours sa this
variable définie sur celle à laquelle Object
elle est associée. Cela est vrai pour les modes stricts et non stricts.
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.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation
Considérant un scénario plus communément pratique:
var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself
Le new
mot clé
Considérez 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? Eh bien, voyons ce qui se passe lorsque nous utilisons le new
mot - clé.
- L'appel de la fonction avec le
new
mot - clé initialiserait immédiatement unObject
type dePerson
. - Le constructeur de this
Object
a son constructeur défini surPerson
. Notez également que celatypeof awal
ne reviendraitObject
que. - Ce nouveau
Object
serait assigné au prototype dePerson.prototype
. Cela signifie que toute méthode ou propriété duPerson
prototype serait disponible pour toutes les instances dePerson
, y comprisawal
. - La fonction
Person
elle-même est maintenant appelée;this
étant une référence à l'objet nouvellement construitawal
.
Assez simple, hein?
Notez que la spécification ECMAScript officielle n'indique nulle part que de tels types de fonctions sont des constructor
fonctions réelles . Ce ne sont que des fonctions normales et new
peuvent être utilisées sur n'importe quelle fonction. C'est juste que nous les utilisons comme tels, et nous les appelons donc uniquement comme tels.
Appel de fonctions sur les fonctions: call
etapply
Alors oui, puisque les function
s sont aussi Objects
(et en fait des variables de première classe en Javascript), même les fonctions ont des méthodes qui sont ... enfin, des fonctions elles-mêmes.
Toutes les fonctions héritent du global 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 sur laquelle elles sont appelées.
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
Ceci est un exemple typique d'utilisation call
. Il prend essentiellement le premier paramètre et définit this
dans la fonction foo
comme une référence à thisArg
. Tous les autres paramètres passés à call
sont passés à la fonction en foo
tant qu'arguments.
Ainsi, le code ci-dessus se connectera {myObj: "is cool"}, [1, 2, 3]
à la console. Jolie façon de changer la valeur de this
dans n'importe quelle fonction.
apply
est presque identique à call
accepter qu'il ne prend que deux paramètres: thisArg
et un tableau qui contient les arguments à passer à la fonction. Ainsi, l' call
appel ci - dessus peut être traduit apply
comme ceci:
foo.apply(thisArg, [1,2,3])
Notez que call
et apply
peut remplacer la valeur de l' this
appel de la méthode set by dot dont nous avons parlé dans la deuxième puce. Assez simple :)
Présentation .... bind
!
bind
est un frère de call
et apply
. C'est aussi une méthode héritée par toutes les fonctions du Function
constructeur global en Javascript. La différence entre bind
et call
/ apply
est que les deux call
et apply
sera en fait appeler la fonction. bind
, d'autre part, renvoie une nouvelle fonction avec le thisArg
et arguments
préréglé. 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]`
Vous voyez 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
set par l'invocation de la méthode par points.
Notez également qu'aucune de ces trois fonctions ne modifie la fonction d'origine. call
et apply
renverrait la valeur des fonctions fraîchement construites tandis que bind
renverrait la fonction fraîchement construite elle-même, prête à être appelée.
Trucs supplémentaires, copiez ceci
Parfois, vous n'aimez pas le fait que les this
changements avec la portée, en particulier la portée imbriquée. Jetez un œil à 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 a this
changé avec la portée imbriquée, mais nous voulions la valeur de this
de la portée d'origine. Nous avons donc « copié » this
à that
et utilisé la copie au lieu de this
. Intelligent, hein?
Indice:
- Qu'est-ce qui est retenu
this
par défaut? - Et si nous appelons la fonction comme une méthode avec la notation Object-dot?
- Et si nous utilisons le
new
mot-clé? - Comment manipuler
this
aveccall
etapply
? - Utilisation
bind
. - Copie
this
pour résoudre les problèmes de portée imbriquée.
"ceci" est une question de portée. Chaque fonction a sa propre portée, et puisque tout dans JS est un objet, même une fonction peut stocker des valeurs en elle-même en utilisant "this". La POO 101 enseigne que «ceci» n'est applicable qu'aux 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 de «ceci».
La plupart des gens sont confus lorsqu'ils essaient d'utiliser «this» dans des fonctions de fermeture anonymes comme:
(fonction (valeur) { this.value = valeur; $ ('. some-elements'). each (function (elt) { elt.innerHTML = this.value; // euh oh !! éventuellement indéfini }); }) (2);
Donc ici, à l'intérieur de chaque (), "this" ne contient pas la "valeur" que vous attendez (de
this.value = valeur;Au dessus de). Donc, pour surmonter ce problème (sans jeu de mots), un développeur pourrait:
(fonction (valeur) { var self = ceci; // petite monnaie self.value = valeur; $ ('. some-elements'). each (function (elt) { elt.innerHTML = self.value; // phew!! == 2 }); }) (2);
Essaye le; vous commencerez à aimer ce modèle de programmation
Depuis que ce fil de discussion a augmenté, j'ai compilé quelques points pour les lecteurs this
novices.
Comment la valeur de est-elle this
déterminée?
Nous utilisons cela de la même manière que nous utilisons les pronoms dans des langues naturelles comme l'anglais: "John court vite parce qu'il essaie de prendre le train." Au lieu de cela, nous aurions pu écrire «… John essaie 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 pas de valeur jusqu'à ce qu'un objet appelle la fonction où il est défini. Dans la portée globale, toutes les variables et fonctions globales sont définies sur l' window
objet. Par conséquent, this
dans une fonction globale fait référence à (et a la valeur de) l' window
objet global .
Quand use strict
, this
dans les fonctions globales et anonymes qui ne sont liées à aucun objet détient la valeur undefined
.
Le this
mot-clé est le plus mal compris lorsque: 1) nous empruntons une méthode qui utilise this
, 2) nous affectons une méthode qui utilise this
à une variable, 3) une fonction qui utilise this
est passée comme fonction de rappel, et 4) this
est utilisée à l'intérieur d'une fermeture - une fonction intérieure. (2)
Ce qui réserve l'avenir
Définies dans ECMA Script 6 , les fonctions fléchées adoptent la this
liaison de la portée englobante (fonction ou globale).
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 fléchées fournissent une alternative à l'utilisation bind()
, il est important de noter qu'elles désactivent essentiellement le this
mécanisme traditionnel en faveur d'une portée lexicale plus largement comprise. (1)
Les références:
- this & Object Prototypes , par Kyle Simpson. © 2014 Getify Solutions.
- javascriptissexy.com - http://goo.gl/pvl0GX
- Angus Croll - http://goo.gl/Z2RacU
this
en JavaScript se réfère toujours au «propriétaire» de la fonction 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 l'ai fait
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, pas la remise à l'élément. Par conséquent, this
fera référence à l'objet window.
Chaque contexte d'exécution en javascript a un paramètre this qui est défini par:
- Comment la fonction est appelée (y compris en tant que méthode objet, utilisation de call and apply , utilisation de new )
- Utilisation de bind
- Lexiquement pour les fonctions fléchées (ils adoptent le this de leur contexte d'exécution externe)
- Que le code soit en mode strict ou non strict
- Si le code a été appelé à l'aide de eval
Vous pouvez définir la valeur de this en utilisant func.call
, func.apply
ou func.bind
.
Par défaut, et ce qui déroute la plupart des débutants, lorsqu'un auditeur est appelé après qu'un événement est déclenché sur un élément DOM, la valeur this de la fonction est l'élément DOM.
jQuery rend ce changement trivial avec jQuery.proxy.
Daniel, super explication! Quelques mots à ce sujet et une bonne liste de this
pointeurs de contexte d'exécution dans le cas de gestionnaires d'événements.
En deux mots, this
en JavaScript pointe l'objet à partir duquel (ou à partir du contexte d'exécution duquel) la fonction actuelle a été exécutée et il est toujours en lecture seule, vous ne pouvez pas le définir de toute façon (une telle tentative se terminera par 'Invalid left-hand côté dans le message d'affectation.
Pour les gestionnaires d'événements: les gestionnaires d'événements en ligne, tels que <element onclick="foo">
, remplacent tous les autres gestionnaires attachés précédemment et avant, alors soyez prudent et il est préférable de rester à l'écart de 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)">
Voici une bonne source de this
in JavaScript
.
Voici le résumé:
global ce
Dans un navigateur, au niveau global,
this
est l'window
objet<script type="text/javascript"> console.log(this === window); // true var foo = "bar"; console.log(this.foo); // "bar" console.log(window.foo); // "bar"
En
node
utilisant le repl,this
est le premier espace de noms. Vous pouvez vous y référer commeglobal
.>this { ArrayBuffer: [Function: ArrayBuffer], Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 }, Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 }, ... >global === this true
Lors de l'
node
exécution à partir d'un script,this
à la portée globale commence comme un objet vide. Ce n'est pas la même chose queglobal
\\test.js console.log(this); \\ {} console.log(this === global); \\ fasle
faire fonctionner ça
Sauf dans le cas des gestionnaires d'événements DOM ou quand a thisArg
est fourni (voir plus bas), à la fois dans le nœud et dans un navigateur en utilisant this
dans une fonction qui n'est pas appelée avec des new
références la portée globale ...
<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;
, dans quel cas this
seraundefined
<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, elle ne référencera pas le global this
.
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
new testThis();
console.log(this.foo); //logs "bar"
console.log(new testThis().foo); //logs "foo"
</script>
- prototype ceci
Les fonctions que vous créez deviennent des objets de fonction. Ils obtiennent automatiquement une prototype
propriété spéciale , à laquelle vous pouvez attribuer 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 prototype
propriété. Vous accédez à ces valeurs en utilisant 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'attribuer des tableaux ou des objets sur le 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 []
- objectez ceci
Vous pouvez utiliser this
dans n'importe quelle fonction sur un objet pour faire référence à d'autres propriétés sur cet objet. Ce n'est pas la même chose qu'une instance créée avec new
.
var obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar"
- Événement DOM ce
Dans un gestionnaire d'événements HTML DOM, this
est toujours une référence à l'élément DOM auquel l'événement était attaché
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick);
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs "<div id="foo"></div>"
}
var listener = new Listener();
document.getElementById("foo").click();
Sauf si vous bind
le contexte
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs Listener {handleClick: function}
}
var listener = new Listener();
document.getElementById("foo").click();
- HTML ceci
À l'intérieur des attributs HTML dans lesquels vous pouvez mettre JavaScript, se this
trouve 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>
- évaluer cela
Vous pouvez utiliser eval
pour accéder this
.
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
eval("console.log(this.foo)"); //logs "bar"
}
var thing = new Thing();
thing.logFoo();
- avec ça
Vous pouvez utiliser with
pour ajouter this
à la portée actuelle pour lire et écrire sur des valeurs this
sans y faire référence this
explicitement.
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
with (this) {
console.log(foo);
foo = "foo";
}
}
var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
- jQuery ceci
le jQuery se this
référera à de nombreux endroits à 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 façon dont "ce" mot-clé est interprété en JavaScript. Espérons que cet article permettra à tous de se reposer une fois pour toutes. Et beaucoup plus. Veuillez lire attentivement l'intégralité de l'article. Soyez prévenu que cet article est long.
Quel que soit le contexte dans lequel il est utilisé, «this» fait toujours référence à «l'objet courant» en Javascript. Cependant, ce qu'est «l'objet courant» diffère selon le contexte . Le contexte peut être exactement l' un des 6 suivants:
- Global (c'est-à-dire en dehors de toutes les fonctions)
- Appel direct "Fonction non liée " à l'intérieur (c'est-à-dire une fonction qui n'a pas été liée en appelant functionName.bind )
- À l'intérieur Appel indirect "Fonction non liée" via functionName.call et functionName.apply
- À l'intérieur de l'appel "Bound Function" (c'est-à-dire une fonction qui a été liée en appelant functionName.bind )
- Pendant la création d'objet via "nouveau"
- Gestionnaire d'événements DOM Inline Inside
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), "l'objet courant" (et donc la valeur de "ceci" ) est toujours l' objet "fenêtre" pour les navigateurs.
Appel direct interne "Fonction non liée" :
À l'intérieur d'un appel direct de «fonction non liée», l'objet qui a appelé l'appel de fonction devient «l'objet courant» (et donc la valeur de «ceci» ). Si une fonction est appelée sans objet courant explicite , l' objet courant est soit l' objet "fenêtre" (pour le mode non strict), soit indéfini (pour le mode strict). Toute fonction (ou variable) définie dans le contexte global devient automatiquement une propriété de l'objet "fenêtre" . Par exemple, supposons que la fonction soit définie dans le contexte global comme
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 / invoquer cette fonction directement via "UserDefinedFunction ()" l'appellera / l'invoquera automatiquement comme "window.UserDefinedFunction ()" faisant "window" comme "objet courant" (et donc la valeur de " this " ) dans " UserDefinedFunction " .L'invocation de cette fonction en" Mode non strict "entraînera les résultats suivants
UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction()
En "Strict Mode", appeler / appeler la fonction directement via "UserDefinedFunction ()" "ne sera " PAS " automatiquement appeler / invoquer comme " window.UserDefinedFunction () ". Par conséquent, " l'objet courant " (et la valeur de " this " ) dans "UserDefinedFunction" ne doit pas être défini . L'appel de cette fonction en "Mode strict" entraînera les résultats suivants
UserDefinedFunction() // displays undefined
Cependant, l'invoquer explicitement en utilisant un objet window entraînera le résultat suivant
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 lorsque "UserDefinedFunction" a été invoqué via o1 , "this" prend la valeur de o1 et la valeur de ses propriétés "a" et "b" s'affiche. Les valeurs de "c" et "d" ont été affichées comme non définies car o1 ne définit pas ces propriétés
De même , lorsque « UserDefinedFunction » a été invoqué par o2 , « cette » prend valeur de o2 et la valeur de ses propriétés « c » et « d » obtenir affichée.Procédé valeur de « a » et « b » ont été présentés comme non défini comme o2 ne pas définir ces propriétés.
À l'intérieur de l'appel indirect "Fonction non liée" via functionName.call et functionName.apply :
Lorsqu'une "Fonction non liée" est appelée via functionName.call ou functionName.apply , "l'objet actuel" (et donc la valeur de "this" ) est défini sur la valeur du paramètre "this" (premier paramètre) passé à call / appliquer . Le code suivant illustre 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" pour toute "fonction NON Bound" peut être modifiée via call / apply . De plus, si le paramètre «this» n'est pas explicitement passé à call / apply , «current object» (et donc la valeur de «this») est défini sur «window» en mode non strict et «undefined» en mode strict.
Dans l'appel "Bound Function" (c'est-à-dire une fonction qui a été liée en appelant functionName.bind ):
Une fonction liée est une fonction dont la valeur "this" a été fixée. Le code suivant a montré comment «ceci» 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, "cette" valeur pour toute "fonction liée" NE PEUT PAS être modifiée par appel / application . De plus, si le paramètre "this" n'est pas explicitement passé à bind, "current object" (et donc la valeur de "this" ) est défini sur "window" en mode non strict et "undefined" en mode strict. Encore une chose. La liaison d'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'objets via "nouveau" :
Dans une fonction constructeur, l ' "objet courant" (et donc la valeur de "this" ) fait référence à l'objet qui est actuellement créé via "nouveau", quel que soit l'état de liaison de la fonction. Cependant, 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énements à l'intérieur du DOM en ligne :
Veuillez consulter 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 se réfère respectivement à l'élément "button" et à l'élément "div".
Dans le premier exemple, la couleur de police du bouton doit être définie sur blanc lorsque l'utilisateur clique dessus.
Dans le deuxième exemple, lorsque l' élément "div" est cliqué, il doit appeler la fonction OnDivClick avec son deuxième paramètre référençant l'élément div cliqué. Cependant, la valeur de "this" dans OnDivClick NE DOIT PAS faire référence à l' élément div cliqué . Il doit être défini comme "objet fenêtre" ou "non défini" dans les modes non strict et strict respectivement (si OnDivClick est une fonction non liée ) ou défini sur une valeur liée prédéfinie (si OnDivClick est une fonction liée )
Ce qui suit résume tout l'article
Dans le contexte global, "ceci" fait toujours référence à l' objet "fenêtre"
Chaque fois qu'une fonction est invoquée, elle est invoquée dans le contexte d'un objet ( "objet courant" ). Si l' objet courant n'est pas explicitement fourni, l' objet courant est «l'objet fenêtre» en 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 à l'objet dans le contexte duquel la fonction est appelée ( "objet courant" )
La valeur de "this" dans une fonction non liée peut être remplacée par des méthodes d' appel et d' application de la fonction.
La valeur de "this" est fixe pour une fonction liée et ne peut pas être remplacée par les méthodes d' appel et d' application 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 est l'objet qui est créé et initialisé
La valeur de "this" dans un gestionnaire d'événements DOM en ligne fait référence à l'élément pour lequel le gestionnaire d'événements est donné.
L'article le plus détaillé et complet sur this
est probablement le suivant:
Explication douce du mot-clé "this" en JavaScript
L'idée derrière this
est de comprendre que les types d'invocation de fonction ont une importance significative sur la définition de la this
valeur.
Lorsque vous rencontrez des problèmes d'identification this
, ne vous demandez pas:
Où est
this
pris à partir ?
mais ne demandez-vous:
Comment la fonction est-elle appelée ?
Pour une fonction de flèche (cas particulier de la transparence du contexte) posez-vous la question:
Quelle valeur a
this
là où la fonction de flèche est définie ?
Cet état d'esprit est correct lors du traitement this
et vous évitera des maux de tête.
C'est la meilleure explication que je l' ai vu: Comprendre JavaScripts ce avec clarté
La référence this fait TOUJOURS référence à (et contient la valeur) d'un objet - un objet singulier - et elle est généralement utilisée à l'intérieur d'une fonction ou d'une méthode, bien qu'elle puisse être utilisée en dehors d'une fonction dans la portée globale. Notez que lorsque nous utilisons le mode strict, cela contient la valeur d'indéfini dans les fonctions globales et dans les fonctions anonymes qui ne sont liées à aucun objet.
Il existe quatre scénarios où cela peut prêter à confusion:
- Lorsque nous transmettons une méthode (qui utilise ceci ) comme argument à utiliser comme fonction de rappel.
- Lorsque nous utilisons une fonction interne (une fermeture). Il est important de noter que les fermetures ne peuvent pas accéder à la variable this de la fonction externe en utilisant le mot-clé this car la variable this n'est accessible que par la fonction elle-même, pas par les fonctions internes.
- Lorsqu'une méthode qui repose sur cela est affectée à une variable dans différents contextes, auquel cas cela fait référence à un autre objet que celui initialement prévu.
- Lorsque vous utilisez ce ainsi que la liaison, appliquer et méthodes d'appel.
Il donne des exemples de code, des explications et des solutions, ce que j'ai trouvé très utile.
this
est l'un des concepts mal compris en JavaScript car il se comporte peu différemment d'un endroit à l'autre. Simplement, this
fait référence au "propriétaire" de la fonction que nous exécutons actuellement .
this
aide à obtenir l'objet courant (aka contexte d'exécution) avec lequel nous travaillons. Si vous comprenez dans quel objet la fonction en cours est CHAISE, vous pouvez comprendre ce que facilement en cours this
est -
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». Un dans un contexte global, un à l'intérieur de obj et l'autre à l'intérieur de innerMethod de obj. JavaScript résout les identifiants dans un contexte particulier en remontant la chaîne de portée du local au global.
Peu d'endroits où this
se différencier
Appeler une méthode d'un objet
var status = 1;
var helper = {
status : 2,
getStatus: function () {
return this.status;
}
};
var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2
var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1
Lorsque line1 est exécuté, JavaScript établit un contexte d'exécution (EC) pour l'appel de fonction, définissant this
l' objet référencé par tout ce qui précède le dernier "." . donc dans la dernière ligne, vous pouvez comprendre que cela a a()
été exécuté dans le contexte global qui est le window
.
Avec constructeur
this
peut être utilisé pour faire référence à l'objet en cours de création
function Person(name){
this.personName = name;
this.sayHello = function(){
return "Hello " + this.personName;
}
}
var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott
var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined
Lorsque new Person()
est exécuté, un objet complètement nouveau est créé. Person
est appelé et il this
est défini pour référencer ce nouvel objet.
Appel de fonction
function testFunc() {
this.name = "Name";
this.myCustomAttribute = "Custom Attribute";
return this;
}
var whatIsThis = testFunc();
console.log(whatIsThis); //window
var whatIsThis2 = new testFunc();
console.log(whatIsThis2); //testFunc() / object
console.log(window.myCustomAttribute); //Custom Attribute
Si nous manquons le new
mot-clé, fait whatIsThis
référence au contexte le plus global qu'il peut trouver ( window
)
Avec les gestionnaires d'événements
Si le gestionnaire d'événements est en ligne, this
fait référence à un 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>
Lors de l'ajout d'un gestionnaire d'événements via JavaScript, this
fait référence à l'élément DOM qui a généré l'événement.
- Vous pouvez également manipuler le contexte en utilisant
.apply()
.call()
et.bind()
- Le proxy JQuery est un autre moyen que vous pouvez utiliser pour vous assurer que cela dans une fonction sera la valeur que vous désirez. (Vérifiez Comprendre l'utilisation de $ .proxy () , jQuery.proxy () )
- Que var that = thissignifie en JavaScript
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;
La valeur de "this" dépend du "contexte" dans lequel la fonction est exécutée. Le contexte peut être n'importe quel objet ou l'objet global, c'est-à-dire une fenêtre.
Ainsi, la sémantique de «ceci» est différente des langages OOP traditionnels. 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 fermeture est appelée à partir d'une méthode membre d'une classe.
Dans les deux cas, il est défini sur window.
Qu'est- ce que cela peut aider? (La plupart de la confusion de `` ceci '' en javascript vient du fait qu'il n'est généralement pas lié à votre objet, mais à la portée d'exécution actuelle - ce n'est peut-être pas exactement comment cela fonctionne mais c'est toujours comme ça pour moi - voir l'article pour une explication complète)
Un peu d'informations sur ce mot clé
Enregistrons le this
mot-clé à la console dans une portée globale sans plus de code mais
console.log(this)
Dans Client / Browser, le this
mot clé est un objet global qui estwindow
console.log(this === window) // true
et
Dans Server / Node / Javascript runtime, le this
mot clé est également un objet global qui estmodule.exports
console.log(this === module.exports) // true
console.log(this === exports) // true
Gardez à l'esprit que ce exports
n'est qu'une référence àmodule.exports
cette utilisation pour Scope 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
J'ai une vision différente this
des autres réponses qui, je l'espère, sont utiles.
Une façon de regarder JavaScript est de voir qu'il n'y a qu'une seule façon d'appeler une fonction 1 . Il est
functionObject.call(objectForThis, arg0, arg1, arg2, ...);
Il y a toujours une valeur fournie pour objectForThis
.
Tout le reste est du sucre syntaxique pour functionObject.call
Donc, tout le reste peut être décrit par la façon dont cela se traduit functionObject.call
.
Si vous appelez simplement une fonction, alors this
est "l'objet global" qui dans le navigateur est la fenêtre
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
seraundefined
'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 comme +
et -
et *
. Il y a aussi l'opérateur point qui est.
L' .
opérateur lorsqu'il est utilisé avec une fonction à droite et un objet à gauche signifie en fait «passer l'objet this
à la fonction».
Exemple
const bar = {
name: 'bar',
foo() {
console.log(this);
},
};
bar.foo(); // this is bar
En d'autres termes se bar.foo()
traduit parconst temp = bar.foo; temp.call(bar);
Notez que peu importe comment la fonction a été créée (principalement ...). 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, ce 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 prototype. Lorsque vous utilisez a.b
JavaScript, commencez par rechercher l'objet référencé directement par a
la propriété b
. Si l'objet b
n'est pas trouvé, JavaScript cherchera 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 est le class
mot - clé. Pour les besoins, this
cela n'a pas d'importance. Ce qui compte, c'est que lorsqu'il recherche dans l'objet la a
propriété b
s'il trouve une propriété b
sur l'objet ou dans sa chaîne de prototype s'il b
finit par être une fonction, les mêmes règles que ci-dessus s'appliquent. Les b
références de fonction seront appelées en utilisant la call
méthode et en passant a
comme objectForThis comme indiqué en haut de cette réponse.
À présent. Imaginons que nous fassions une fonction qui définit explicitement this
avant d'appeler une autre fonction, puis que nous l'appelions 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();
Suite à la traduction à utiliser call
, obj.bar()
devient const temp = obj.bar; temp.call(obj);
. Lorsque nous entrons dans la bar
fonction que nous appelons foo
mais que nous passons explicitement un autre objet pour objectForThis, lorsque nous arrivons à foo, this
c'est cet objet interne.
C'est ce que les deux bind
et =>
fonctions font efficacement. Ce sont des sucres plus syntaxiques. Ils construisent effectivement 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, il this
est défini sur tout ce à quoi vous passez 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 s'il functionObject.bind
n'existait pas, nous pourrions créer le nôtre comme ça
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'});
Fonctions fléchées, les =>
opérateurs sont des sucres syntaxiques pour bind
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 qui appelle la fonction donnée avec une valeur liée pour objectForThis
mais contrairement à bind
l'objet à lier est implicite. C'est tout ce qui this
se passe 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()
traduit const temp = obj.foo; temp.call(obj);
ce qui signifie que l'opérateur de flèche à l'intérieur foo
se liera obj
à une nouvelle fonction invisible et renverra cette nouvelle fonction invisible à laquelle est assignée b
. b()
fonctionnera comme il l'a toujours fait b.call(window)
ou en b.call(undefined)
appelant la nouvelle fonction invisible foo
créée. Cette fonction invisible ignore le qui y est this
passé et passe 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 d'ES6, conceptuellement, vous pouvez même traduire cela en
functionName.call(objectForThis, ...arrayOfArgs);
Résumé this
Javascript:
- La valeur de
this
est déterminée par la façon dont la fonction n'est pas appelée, où elle a été créée! - Habituellement, la valeur de
this
est déterminée par l'objet qui se trouve à gauche du point. (window
dans l'espace mondial) - Dans les écouteurs d'événements, la valeur de
this
fait référence à l'élément DOM sur lequel l'événement a été appelé. - Lorsque in function est appelé avec le
new
mot - clé, la valeur dethis
fait référence à l'objet nouvellement créé - Vous pouvez manipuler la valeur
this
des fonctions:call
,apply
,bind
Exemple:
let object = {
prop1: function () {console.log(this);}
}
object.prop1(); // object is left of the dot, thus this is object
const myFunction = object.prop1 // We store the function in the variable myFunction
myFunction(); // Here we are in the global space
// myFunction is a property on the global object
// Therefore it logs the window object
Exemple d'écouteurs d'événements:
document.querySelector('.foo').addEventListener('click', function () {
console.log(this); // This refers to the DOM element the eventListener was invoked from
})
document.querySelector('.foo').addEventListener('click', () => {
console.log(this); // Tip, es6 arrow function don't have their own binding to the this v
}) // Therefore this will log the global object
.foo:hover {
color: red;
cursor: pointer;
}
<div class="foo">click me</div>
Exemple de constructeur:
function Person (name) {
this.name = name;
}
const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object
console.log(me.name);
// Therefore, the name property was placed on the object created with new keyword.
Pour bien comprendre «ceci», il faut comprendre le contexte, la portée et la différence entre eux.
Portée : en javascript, la portée est liée à la visibilité des variables, la portée atteint grâce à l'utilisation de la fonction. (En savoir plus sur la portée)
Contexte : le contexte est lié aux objets. Il fait référence à l'objet auquel appartient une fonction. Lorsque vous utilisez le mot-clé JavaScript «this», il fait référence à l'objet auquel appartient la fonction. Par exemple, à l'intérieur d'une fonction, lorsque vous dites: "this.accoutNumber", vous faites référence à la propriété "accoutNumber", qui appartient à l'objet auquel appartient cette fonction.
Si l'objet «myObj» a une méthode appelée «getMyName», lorsque le mot-clé JavaScript «this» est utilisé à l'intérieur de «getMyName», il fait référence à «myObj». Si la fonction «getMyName» a été exécutée dans la portée globale, alors «this» fait référence à l'objet window (sauf en mode strict).
Voyons maintenant un exemple:
<script>
console.log('What is this: '+this);
console.log(this);
</script>
Exécuter le code abobve dans la sortie du navigateur:
Selon la sortie que vous êtes à l'intérieur du contexte de l'objet window, il est également visible que le prototype de fenêtre fait référence à l'objet.
Essayons maintenant à l'intérieur d'une fonction:
<script>
function myFunc(){
console.log('What is this: '+this);
console.log(this);
}
myFunc();
</script>
Production:
Créons maintenant notre propre objet. En javascript, vous pouvez créer un objet de plusieurs manières.
<script>
var firstName = "Nora";
var lastName = "Zaman";
var myObj = {
firstName:"Lord",
lastName:'Baron',
printNameGetContext:function(){
console.log(firstName + " "+lastName);
console.log(this.firstName +" "+this.lastName);
return this;
}
}
var context = myObj.printNameGetContext();
console.log(context);
</script>
Production:
Ainsi, à partir de l'exemple ci-dessus, nous avons constaté que le mot-clé «this» fait référence à un nouveau contexte lié à myObj, et que myObject a également une chaîne prototype vers Object.
Allons jeter un autre exemple:
<body>
<button class="btn">Click Me</button>
<script>
function printMe(){
//Terminal2: this function declared inside window context so this function belongs to the window object.
console.log(this);
}
document.querySelector('.btn').addEventListener('click', function(){
//Terminal1: button context, this callback function belongs to DOM element
console.log(this);
printMe();
})
</script>
</body>
sortie: Ça a du sens, non? (lire les commentaires)
Si vous avez du mal à comprendre l'exemple ci-dessus, essayons avec notre propre rappel;
<script>
var myObj = {
firstName:"Lord",
lastName:'Baron',
printName:function(callback1, callback2){
//Attaching callback1 with this myObj context
this.callback1 = callback1;
this.callback1(this.firstName +" "+this.lastName)
//We did not attached callback2 with myObj so, it's reamin with window context by default
callback2();
/*
//test bellow codes
this.callback2 = callback2;
this.callback2();
*/
}
}
var callback2 = function (){
console.log(this);
}
myObj.printName(function(data){
console.log(data);
console.log(this);
}, callback2);
</script>
production:
Comprenons maintenant Scope, Self, IIFE et CECI comment se comporte
var color = 'red'; // property of window
var obj = {
color:'blue', // property of window
printColor: function(){ // property of obj, attached with obj
var self = this;
console.log('In printColor -- this.color: '+this.color);
console.log('In printColor -- self.color: '+self.color);
(function(){ // decleard inside of printColor but not property of object, it will executed on window context.
console.log(this)
console.log('In IIFE -- this.color: '+this.color);
console.log('In IIFE -- self.color: '+self.color);
})();
function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
console.log('nested fun -- this.color: '+this.color);
console.log('nested fun -- self.color: '+self.color);
}
nestedFunc(); // executed on window context
return nestedFunc;
}
};
obj.printColor()(); // returned function executed on window context
</script>
La sortie est assez géniale, non?