Par rapport à d'autres langues, this 关键字在 JavaScript 中的行为有所不同。在面向对象语言中,this 关键字指的是该类的当前实例。在 JavaScript 中,this 的值由函数的调用上下文 (context.function()) et sa position d'appel sont déterminées. p>
1. Lorsqu'il est utilisé dans un contexte mondial
Quand on l'utilise dans un contexte global this 时,它会绑定到全局对象(浏览器中的window)
document.write(this); //[object Window]
Lorsque vous utilisez this 时,this dans une fonction définie dans le contexte global, vous êtes toujours lié à l'objet global car la fonction est en fait une méthode du contexte global.
function f1()
{
return this;
}
document.write(f1()); //[object Window]
Appelez-le sur l'objet f1是一个全局对象的方法。因此我们也可以在 window ci-dessus, comme ceci :
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. Lorsqu'il est utilisé dans une méthode objet
Lorsque vous utilisez this 关键字时,this à l'intérieur d'une méthode objet, il se lie à l'objet "direct" englobant.
var obj = {
name: "obj",
f: function () {
return this + ":" + this.name;
}
};
document.write(obj.f()); //[object Object]:obj
J'ai mis le mot "immédiatement" entre guillemets ci-dessus. Cela montre que si un objet est imbriqué dans un autre objet, this est lié à l'objet 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 en tant que méthode à l'objet, elle suit toujours les règles ci-dessus, c'est-à-dire que this pointe toujours vers l'objet parent direct.
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
Utilisé this 时,它会绑定到全局对象(浏览器中的window) lorsque vous l'appelez dans une fonction sans aucun contexte (c'est-à-dire pas sur un objet) (même si la fonction est définie à l'intérieur d'un 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
Essayez tout avec les fonctions
Nous pouvons également utiliser des fonctions pour essayer les points ci-dessus. Mais il existe encore quelques différences.
Ci-dessus, nous avons ajouté des membres à l'objet en utilisant la notation littérale d'objet. Nous pouvons ajouter des membres aux fonctions en utilisant this. pour les préciser.
La notation littérale d'objet crée une instance d'objet que nous pouvons utiliser immédiatement. Pour les fonctions, nous devrons peut-être d'abord en créer une instance à l'aide de l'opérateur new.
Également dans les méthodes littérales d'objet, nous pouvons ajouter explicitement des membres à l'objet défini à l'aide de l'opérateur point. Ceci n’est ajouté que dans des cas spécifiques. Cependant, j'ai ajouté la variable au prototype de fonction afin qu'elle soit reflétée dans toutes les instances de la fonction.
Ci-dessous, j'ai essayé tout ce que j'ai fait ci-dessus avec Object et this mais j'ai d'abord créé la fonction au lieu d'écrire directement l'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() + " "); //[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() + " "); //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() + " "); //v1
obj2.incrementVersion(); //incrementing version in obj2
//does not affect obj1 version
document.write(obj2.getVersion() + " "); //v2
document.write(obj1.getVersion() + " "); //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() + " "); //[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()+" ");//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 d'un constructeur .
Lorsqu'une fonction est utilisée comme constructeur (c'est-à-dire lorsqu'elle est appelée à l'aide du mot-clé new 关键字调用时),函数体内的 this), le 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 prototype 🎜
Si la méthode se trouve sur la chaîne de prototypes de l'objet, alors this au sein de la méthode fait référence à l'objet sur lequel la méthode est appelée, comme si la méthode était définie sur cet 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 seule fois et de l'appeler dans différents contextes. Autrement dit, ils permettent de préciser la valeur this qui sera utilisée lors de l'exécution de la fonction. Ils peuvent également transmettre n'importe quel argument à la fonction d'origine lors de son appel.
obj1 sur la valeur contenue dans code>fun() et appelez fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - 设置 obj1 作为 fun() 内 this 的值,并调用 fun()fun() , en passant des éléments de argsArray comme arguments.
fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - 返回对函数的引用fun,其中 fun 内的 this 绑定到 obj1,并且 fun 的参数绑定到指定的参数 arg1、arg2, arg3,... - Définit obj1 comme
fun() à l'intérieur de
value et appelle apply、call 和 bind 之间的区别一定已经很明显了。 apply 允许将参数指定为类似数组的对象,即具有数字 length 属性和相应的非负整数属性的对象。而 call 允许直接指定函数的参数。 apply 和 callfun() en passant
- Renvoie une référence à la fonction fun, où fun is Le 🎜 est lié à 🎜obj1, et les arguments de 🎜fun sont liés aux arguments spécifiés 🎜arg1, arg2, arg3,.... 🎜
🎜Maintenant, la différence entre 🎜apply, 🎜call et 🎜bind doit être évidente. 🎜apply permet de spécifier des arguments sous forme d'objets de type tableau, c'est-à-dire des objets avec une propriété numérique 🎜length et une propriété entière non négative correspondante. Et 🎜call permet de spécifier directement les paramètres de la fonction. 🎜apply et 🎜call appellent immédiatement la fonction dans le contexte spécifié et avec les paramètres spécifiés. bind, d'autre part, renvoie simplement la fonction liée à la valeur et aux arguments spécifiés. Nous pouvons capturer une référence à cette fonction renvoyée en l'attribuant à une variable, que nous pouvons ensuite appeler à tout moment. 🎜
🎜
function add(inc1, inc2)
{
return this.a + inc1 + inc2;
}
var o = { a : 4 };
document.write(add.call(o, 5, 6)+" "); //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]) + " "); //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()+" "); //15
var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + " "); //15
// 4 + 5 + 6 = 15
document.write(h() + " "); //NaN
//no parameter is passed to h()
//thus inc2 inside add() is `undefined`
//4 + 5 + undefined = NaN
🎜🎜7. 🎜🎜🎜 à l'intérieur du gestionnaire d'événements
Lorsque vous attribuez une fonction directement au gestionnaire d'événements d'un élément, cela se fait à l'aide de méthodes traditionnelles d'enregistrement d'événements telles que this 来引用相应的元素。这种直接的函数分配可以使用 addeventListener 方法或通过 onclick directement dans la fonction de gestionnaire d'événements.
De même, lorsque vous appelez directement l'attribut événement d'un élément comme )内使用 this , il fait référence à l'élément
.
Cependant, this 会解析为全局对象 window est utilisé indirectement via d'autres fonctions appelées dans les gestionnaires d'événements ou les propriétés d'événements.
Le même comportement que ci-dessus peut être obtenu lorsque nous utilisons l'approche du modèle d'enregistrement d'événements de Microsoft attachEvent pour attacher une fonction à un gestionnaire d'événements. Au lieu d'attribuer une fonction à un gestionnaire d'événement (créant ainsi une méthode fonction de l'élément), il appelle la fonction sur l'événement (l'appelant effectivement dans le contexte global).
Using `this` "directly" inside event handler or event property
Using `this` "indirectly" inside event handler or event property
IE only:
8. this
dans les fonctions fléchées ES6
Dans une fonction flèche, this 的行为类似于公共变量:它将从其词法范围继承。定义箭头函数的函数的 this 将是箭头函数的 this se comporte comme une variable publique : elle sera héritée de sa portée lexicale. Le
de la fonction qui définit la fonction flèche sera le
此 est un mot-clé en JavaScript qui est un attribut du contexte d'exécution. Son utilisation principale est dans les fonctions et les constructeurs.
this Les règles sont assez simples (si vous respectez les bonnes pratiques).
Description techniquethis dans le cahier des charges
GetThisEnvironment AO recherche le LexicalEnvironment du contexte d'exécution en cours actuel et trouve l'enregistrement d'environnement ascendant le plus proche (en itérant sur sa propriété [[OuterEnv]]) qui a une liaison this (c'est-à-dire que HasThisBinding renvoie true ) . Le processus se termine par l'un des trois types d'enregistrement d'environnement.
La valeur de
this dépend généralement du fait que le code soit en mode strict.
La valeur de retour de
GetThisBinding reflète la valeur this 值,因此每当建立新的执行上下文时,this du contexte d'exécution actuel, donc chaque fois qu'un nouveau contexte d'exécution est établi,
sera résolu en une valeur différente. Cela peut également se produire lorsque le contexte d'exécution actuel est modifié. Les sous-sections suivantes répertorient cinq scénarios dans lesquels cela pourrait se produire.
Il s'agit d'un code de script qui est évalué au niveau supérieur, par exemple directement dans 内:
.
thisDans le contexte d'exécution global initial du script, l'évaluation de amène GetThisBinding
à suivre les étapes suivantes : 🎜
La propriété [[GlobalThisValue]] de l'enregistrement d'environnement global est toujours définie sur l'objet global défini par l'hôte, accessible via globalThisglobalThis ( Web 上的 window,Node.js 上的 global ( fenêtre sur le Web , Node.js global ; Documentation sur MDN). Suivez les étapes de InitializeHostDefinedRealm pour savoir comment la propriété [[GlobalThisValue]] est générée.
Il existe deux types d'appels eval : directet indirect. Cette distinction existe depuis la cinquième édition d'ECMAScript.
Direct eval 调用通常类似于 eval(...); 或 (eval)(...); (或 ((eval))(…); etc.). 1 Il s'agit uniquement de direct (si l'expression appelante est conforme au modèle étroit). 2
est dans le code, GetThisEnvironment est appelé et sa valeur est renvoyée.
La fiche d'environnement déclarative
créée dépend si l'appel
eval
est direct ou indirect :
En évaluation directe, il sera basé sur l'environnement lexical actuel du
contexte d'exécution. Dans une évaluation indirecte, elle sera basée sur l'attribut [[GlobalEnv]] (l'enregistrement d'environnement global 李> du
enregistrement de domaine
qui effectue l'évaluation indirecte).
🎜
🎜Cela signifie : 🎜
En évaluation directe, la portée lexicale de this 值不会改变;它取自名为 eval.
En évaluation indirecte, this 值是全局对象 (globalThis).
新函数怎么样? — new Function 与evalSimilaire, mais il n'appelle pas le code immédiatement, il crée une fonction. this La liaison ne s'applique nulle part ici, sauf lors de l'appel de la fonction, qui fonctionne correctement comme décrit dans la sous-section suivante.
L'appel de fonction réel se produit au niveau de l'AO Call, qui est déterminé par le contexte de l'appel à l'aide de thisValue ; ce paramètre est transmis dans une longue liste d'appels liés à l'appel. Call appelle le slot interne [[Call]] de la fonction. Cela appelle PrepareForOrdinaryCall, où un nouvel enregistrement d'environnement de fonction a été créé :
De plus, il existe également un champ [[ThisValue]] dans l'enregistrement de l'environnement de la fonction :
L'appel
NewFunctionEnvironment définit également la propriété [[ThisBindingStatus]] de l'environnement de fonction.
Après confirmation, la méthode BindThisValue de l'enregistrement d'environnement de fonction nouvellement créé est finalement appelée pour définir réellement le champ [[ThisValue]] à ajouter à thisArgument.
Encore une fois, la détermination précise de la valeur de this dépend de nombreux facteurs ; il ne s'agit que d'un aperçu général ; Forts de ce bagage technique, regardons tous les exemples concrets.
Lors du calcul de la fonction flèche, la propriété de l'objet de fonction de slot interne [[ThisMode]] est définie sur "lexicale" dans OrdinaryFunctionCreate. p>
Dans l'un des appels de fonction suivants, func 内的 this 值将为 refObj. 1
refObj.func()
refObj["func"]()
refObj?.func()
refObj.func?.()
refObj.func``
Si la fonction appelée est syntaxiquement une propriété d'un objet de base, alors cet objet de base sera la "référence" de l'appel, qui dans le cas habituel sera la valeur de this 的值。上面链接的评估步骤对此进行了解释;例如,在 refObj.func() (或 refObj["func"]())中,CallMemberExpression 是整个表达式 refObj.func(),它由 MemberExpressionrefObj.func 和 参数()this. Les étapes d'évaluation liées ci-dessus expliquent cela ; par exemple, dans
Ce sont toutes des références, etCe sont toutes des valeurs. refObj.func 时为 refObj;或 foo.bar code> 当应用于 foo.bar.bazReliure. Les exemples facultatifs de modèles de liens et de balises fonctionnent de manière très similaire : en gros, la référence est précédée de
const o = {
a: 1,
b: this.a, // Is `globalThis.a`.
[this.a]: 2 // Refers to `globalThis.a`.
};
🎜sans référence de base, mode strict et 🎜🎜avec🎜🎜🎜
🎜Un appel sans référence de base est généralement une fonction non appelée en tant qu'attribut. Par exemple : 🎜
func(); // As opposed to `refObj.func();`.
🎜Cela se produit également lors du 🎜passage ou attribution de méthodes🎜, ou lors de l'utilisation de l'🎜opérateur virgule🎜. C'est là que la différence entre l'enregistrement de référence et la valeur est pertinente. 🎜
Notez que la fonction j:按照规范,您会注意到j只能返回函数对象(Value)本身,而不能返回引用记录。因此,基本引用 refObj est manquante.
const g = (f) => f(); // No base ref.
const h = refObj.func;
const j = () => refObj.func;
g(refObj.func);
h(); // No base ref.
j()(); // No base ref.
(0, refObj.func)(); // Another common pattern to remove the base ref.
Remarque : L'étape 5 définit la valeur réelle de this 的实际值设置为严格模式下提供的 thisArgument - 在本例中为 undefined。在“草率模式”下,未定义或 null thisArgument 会导致 this sur le thisArgument fourni en mode strict - dans ce cas, undefined. En "mode bâclé", un
🎜OrdinaryCallBindThis🎜, contrairement à l'étape 6.2 (dans la spécification), est que la valeur originale 🎜this🎜 est en mode "bâclé" 🎜 uniquement 🎜 convertie en un objet. 🎜
Pour vérifier cela, introduisons une autre source de valeur this : trois méthodes qui remplacent la liaison this : 4
pour créer une fonction liée. Ils ont leur propre méthode
[[Call ]]
, qui recherche l'emplacement interne [[BoundThis]] de l'objet fonction.
Exemple de définition d'une valeur
thisObject("s") 或 new String("s") personnalisée :
function f(){
console.log(this);
}
const myObj = {},
g = f.bind(myObj),
h = (m) => m();
// All of these log `myObj`.
g();
f.bind(myObj)();
f.call(myObj);
h(g);
Pour les objets, c'est la même chose en modes strict et non strict.
Maintenant, essayez de fournir une valeur brute : this
En mode non strict, les primitives sont forcées à prendre leur forme de wrapper d'objet. C'est le même type d'objet que vous obtenez lorsque vous appelez
. En mode strict vous pouvez utiliser des primitives :
$("button").click(function(){
console.log(this); // Logs the clicked button.
});
Constructeur, new 运算符将函数作为构造函数调用时,EvaluateNew 调用 Construct,它调用 [[Construct]] 方法。如果函数是基本构造函数(即不是 class extends...{...}),它会设置 thisArgument到从构造函数的原型创建的新对象。构造函数中 this 上设置的属性最终将出现在生成的实例对象上。 thisClass
new 行为的例外是 class extends...{...},如上所述。派生类在调用时不会立即设置其 this 值;它们只有在通过一系列 super 调用到达基类后才会这样做(在没有自己的构造函数的情况下隐式发生)。不允许在调用 super 之前使用 this.
Call supersuper 调用具有调用的词法范围(函数环境记录)的 this 值的超级构造函数。 GetThisValue 对于 super 调用有一个特殊的规则。它使用 BindThisValue 将 this Appelle le super constructeur avec la valeur de
this
à partir de la portée lexicale (enregistrement d'environnement de fonction) de l'appel. GetThisValue
Il existe une règle spéciale pour les appels super. Il utilise BindThisValue
sont actuellement une thisproposition TC39 Phase 3
. Les blocs statiques fonctionnent de la même manière que les champs et méthodes statiques : le 🎜 à l'intérieur d'eux fait référence à la classe elle-même. 🎜
🎜Notez que dans les méthodes et les getters/setters, 🎜 fonctionne de la même manière que dans les propriétés normales des fonctions. 🎜
class Demo{
a = this;
b(){
return this;
}
static c = this;
static d(){
return this;
}
// Getters, setters, private modifiers are also possible.
}
const demo = new Demo;
console.log(demo.a, demo.b()); // Both log `demo`.
console.log(Demo.c, Demo.d()); // Both log `Demo`.
2 : Il doit s'agir d'une MemberExpression em>, ne peut pas être une propriété, doit avoir [[ReferencedName]] avec exactement "eval" et doit être un objet intrinsèque %eval%.
3 : Chaque fois que la spécification dit « que ref soit le résultat de l'évaluation de X », X est une expression dont vous devez trouver les étapes d'évaluation. Par exemple, l'évaluation de MemberExpression ou CallExpression sont ces algorithmes. Certains d'entre eux génèrent des fiches de référence.
4 : Il existe plusieurs autres méthodes natives et hôtes qui permettent de fournir des valeurs this, notamment Array.prototype.map, Array.prototype.forEach, etc. Accepte Array.prototype.map、Array.prototype.forEach 等接受 thisArg 作为第二个参数。任何人都可以创建自己的方法来更改 this,例如 (func, thisArg) => func.bind(thisArg)、(func, thisArg) => func。 call(thisArg)thisArg comme deuxième paramètre. N'importe qui peut créer ses propres méthodes pour modifier , telles que (func, thisArg) => func.bind(thisArg), (func, thisArg) => func. appeler(thisArg) etc. Comme toujours,
MDN fournit une excellente documentation de service.
Juste pour vous amuser, testez votre compréhension avec quelques exemplesthisPour chaque extrait de code, répondez à la question suivante : "Quelle est la valeur de
à la ligne marquée ? Pourquoi ?"
Pour révéler la réponse, cliquez sur la case grise.
if(true){
console.log(this); // What is `this` here?
}
globalThis. La ligne marquée est évaluée dans le contexte d'exécution global initial.
const obj = {};
function myFun(){
return { // What is `this` here?
"is obj": this === obj,
"is globalThis": this === globalThis
};
}
obj.method = myFun;
console.log(obj.method());
Par rapport à d'autres langues,
this
关键字在 JavaScript 中的行为有所不同。在面向对象语言中,this
关键字指的是该类的当前实例。在 JavaScript 中,this
的值由函数的调用上下文 (context.function()
) et sa position d'appel sont déterminées. p>1. Lorsqu'il est utilisé dans un contexte mondial
Quand on l'utilise dans un contexte global
this
时,它会绑定到全局对象(浏览器中的window
)Lorsque vous utilisez
this
时,this
dans une fonction définie dans le contexte global, vous êtes toujours lié à l'objet global car la fonction est en fait une méthode du contexte global.Appelez-le sur l'objet
f1
是一个全局对象的方法。因此我们也可以在window
ci-dessus, comme ceci :2. Lorsqu'il est utilisé dans une méthode objet
Lorsque vous utilisez
this
关键字时,this
à l'intérieur d'une méthode objet, il se lie à l'objet "direct" englobant.J'ai mis le mot "immédiatement" entre guillemets ci-dessus. Cela montre que si un objet est imbriqué dans un autre objet,
this
est lié à l'objet parent immédiat.Même si vous ajoutez explicitement une fonction en tant que méthode à l'objet, elle suit toujours les règles ci-dessus, c'est-à-dire que
this
pointe toujours vers l'objet parent direct.3. Lors de l'appel d'une fonction sans contexte
Utilisé
this
时,它会绑定到全局对象(浏览器中的window
) lorsque vous l'appelez dans une fonction sans aucun contexte (c'est-à-dire pas sur un objet) (même si la fonction est définie à l'intérieur d'un objet).Essayez tout avec les fonctions
Nous pouvons également utiliser des fonctions pour essayer les points ci-dessus. Mais il existe encore quelques différences.
this
. pour les préciser.new
.Ci-dessous, j'ai essayé tout ce que j'ai fait ci-dessus avec Object et
this
mais j'ai d'abord créé la fonction au lieu d'écrire directement l'objet.4. Lorsqu'il est utilisé à l'intérieur d'un constructeur .
Lorsqu'une fonction est utilisée comme constructeur (c'est-à-dire lorsqu'elle est appelée à l'aide du mot-clé
new
关键字调用时),函数体内的this
), le dans le corps de la fonction pointe vers le nouvel objet en cours de construction.Si la méthode se trouve sur la chaîne de prototypes de l'objet, alors
this
au sein de la méthode fait référence à l'objet sur lequel la méthode est appelée, comme si la méthode était définie sur cet objet.6. Fonctions internes call(), apply() et bind()
Function.prototype
.this
qui sera utilisée lors de l'exécution de la fonction. Ils peuvent également transmettre n'importe quel argument à la fonction d'origine lors de son appel.fun.apply(obj1 [, argsArray])
将obj1
设置为this
内的值code>fun() 并调用fun()
,传递argsArray
fun.apply(obj1 [, argsArray])fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- 设置 obj1 作为fun()
内this
的值,并调用fun()
fun() , en passant des éléments deargsArray
comme arguments.fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- 返回对函数的引用fun
,其中 fun 内的this
绑定到obj1
,并且fun
的参数绑定到指定的参数arg1、arg2, arg3,...
- Définit obj1 commeapply
、call
和bind
之间的区别一定已经很明显了。apply
允许将参数指定为类似数组的对象,即具有数字length
属性和相应的非负整数属性的对象。而call
允许直接指定函数的参数。apply
和call
fun() en passantthis
fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])fun
, où fun is Le 🎜 est lié à 🎜obj1, et les arguments de 🎜fun sont liés aux arguments spécifiés 🎜arg1, arg2, arg3,.... 🎜 🎜Maintenant, la différence entre 🎜apply, 🎜call et 🎜bind doit être évidente. 🎜apply permet de spécifier des arguments sous forme d'objets de type tableau, c'est-à-dire des objets avec une propriété numérique 🎜length et une propriété entière non négative correspondante. Et 🎜call permet de spécifier directement les paramètres de la fonction. 🎜apply et 🎜call appellent immédiatement la fonction dans le contexte spécifié et avec les paramètres spécifiés. bind, d'autre part, renvoie simplement la fonction liée à la valeur et aux arguments spécifiés. Nous pouvons capturer une référence à cette fonction renvoyée en l'attribuant à une variable, que nous pouvons ensuite appeler à tout moment. 🎜 🎜 🎜🎜7. 🎜🎜🎜 à l'intérieur du gestionnaire d'événementsthis
来引用相应的元素。这种直接的函数分配可以使用addeventListener
方法或通过onclick
directement dans la fonction de gestionnaire d'événements.)内使用
this
, il fait référence à l'élémentthis
会解析为全局对象window
est utilisé indirectement via d'autres fonctions appelées dans les gestionnaires d'événements ou les propriétés d'événements.attachEvent
pour attacher une fonction à un gestionnaire d'événements. Au lieu d'attribuer une fonction à un gestionnaire d'événement (créant ainsi une méthode fonction de l'élément), il appelle la fonction sur l'événement (l'appelant effectivement dans le contexte global).Je recommande JSFiddle中更好地尝试此操作>.
8.
dans les fonctions fléchées ES6this
Dans une fonction flèche,
de la fonction qui définit la fonction flèche sera lethis
的行为类似于公共变量:它将从其词法范围继承。定义箭头函数的函数的this
将是箭头函数的this
se comporte comme une variable publique : elle sera héritée de sa portée lexicale. Lede la fonction flèche.
C'est donc le même comportement que :
🎜Voir le code ci-dessous : 🎜此
est un mot-clé en JavaScript qui est un attribut du contexte d'exécution. Son utilisation principale est dans les fonctions et les constructeurs.this
Les règles sont assez simples (si vous respectez les bonnes pratiques).Description technique
this
dans le cahier des chargesStandard ECMAScriptdéfinition
Lesthis
via des opérations abstraites (en abrégé AO) ResolveThisBinding :Enregistrements d'environnement globaux, Enregistrements d'environnement de module et Enregistrements d'environnement de fonction ont chacun leur propre méthode GetThisBinding.
GetThisEnvironment AO recherche le LexicalEnvironment du contexte d'exécution en cours actuel et trouve l'enregistrement d'environnement ascendant le plus proche (en itérant sur sa propriété [[OuterEnv]]) qui a une liaison this (c'est-à-dire que HasThisBinding renvoie true ) . Le processus se termine par l'un des trois types d'enregistrement d'environnement.
La valeur de
La valeur de retour dethis
dépend généralement du fait que le code soit en mode strict.GetThisBinding reflète la valeur
sera résolu en une valeur différente. Cela peut également se produire lorsque le contexte d'exécution actuel est modifié. Les sous-sections suivantes répertorient cinq scénarios dans lesquels cela pourrait se produire.this
值,因此每当建立新的执行上下文时,this
du contexte d'exécution actuel, donc chaque fois qu'un nouveau contexte d'exécution est établi,Vous pouvez placer des échantillons de code dans AST Explorer
pour suivre les détails des spécifications.Il s'agit d'un code de script qui est évalué au niveau supérieur, par exemple directement dans
内:eval
调用通常类似于eval(
...);
或(eval)(
...); (或((eval))(
…);
etc.). 1 Il s'agit uniquement de direct (si l'expression appelante est conforme au modèle étroit). 2eval
调用涉及以任何其他方式调用函数引用eval
。它可以是eval?.(
...)
,(
..., eval)(
...),
,调用window.eval(
...)
,eval.call(
...,
...)给定 const aliasEval1 = eval; 等。 window.aliasEval2 = eval;
,也可以是aliasEval1(
…)
、aliasEval2(
…)
代码>.分别给出 const originalEval = eval; window.eval = (x) => originalEval(x);eval(
…)
est également indirect.Voir la réponse de chuckj à "(1, eval)('this') vs eval('this') en JavaScript ?" et Détails ECMA-262-5 de Dmitry Soshnikov – Chapitre 2 : Mode strict (Archivé), pour les cas où vous pourriez utiliser des appels
eval()
indirects.PerformEval exécute le code
enregistrement d'environnement déclaratifeval
代码。它创建一个新的 声明性环境记录 作为其 LexicalEnvironment,这是 GetThisEnvironment 从中获取this
eval. Il crée un nouvelen tant que LexicalEnvironment, qui est GetThisEnvironment
Ensuite, sithis
出现在eval
pour obtenir this from > value.est dans le code, GetThisEnvironment est appelé et sa valeur est renvoyée.
créée dépend si l'appelLa fiche d'environnement déclarative
eval- est direct ou indirect :
En évaluation directe, il sera basé sur l'environnement lexical actuel du - contexte d'exécution.
Dans une évaluation indirecte, elle sera basée sur l'attribut [[GlobalEnv]] (l'enregistrement d'environnement global 李> du
enregistrement de domainequi effectue l'évaluation indirecte).
🎜 🎜Cela signifie : 🎜this
值不会改变;它取自名为eval
.this
值是全局对象 (globalThis
).新函数
怎么样? —new Function
与eval
Similaire, mais il n'appelle pas le code immédiatement, il crée une fonction. this La liaison ne s'applique nulle part ici, sauf lors de l'appel de la fonction, qui fonctionne correctement comme décrit dans la sous-section suivante.4. Entrez le fonctioncode
Entrez le code de la fonction lorsque appelle la fonction .
Il existe quatre catégories de syntaxe pour appeler des fonctions.
L'appel de fonction réel se produit au niveau de l'AO Call, qui est déterminé par le contexte de l'appel à l'aide de thisValue ; ce paramètre est transmis dans une longue liste d'appels liés à l'appel. Call appelle le slot interne [[Call]] de la fonction. Cela appelle PrepareForOrdinaryCall, où un nouvel enregistrement d'environnement de fonction a été créé :
De plus, il existe également un champ [[ThisValue]] dans l'enregistrement de l'environnement de la fonction :
L'appelNewFunctionEnvironment définit également la propriété [[ThisBindingStatus]] de l'environnement de fonction.
[[Call]] appelle également OrdinaryCallBindThis, où le thisArgument approprié est déterminé en fonction de :
Après confirmation, la méthode BindThisValue de l'enregistrement d'environnement de fonction nouvellement créé est finalement appelée pour définir réellement le champ [[ThisValue]] à ajouter à thisArgument.
Enfin, ce champ est l'enregistrement d'environnement de fonction GetThisBinding AO obtient la valeur de
this
à partir de l'emplacement suivant :Encore une fois, la détermination précise de la valeur de this dépend de nombreux facteurs ; il ne s'agit que d'un aperçu général ; Forts de ce bagage technique, regardons tous les exemples concrets.
Fonction flèche
Lors du calcul de la fonction flèche, la propriété de l'objet de fonction de slot interne [[ThisMode]] est définie sur "lexicale" dans OrdinaryFunctionCreate. p>
À OrdinaryCallBindThis il prend une fonction F :
Cela signifie simplement que le reste de la liaison de l'algorithme this est ignoré. Les fonctions fléchées ne lient pas leur propre valeur this.
Alors, qu'est-ce que
this
dans les fonctions fléchées ? Pour examiner ResolveThisBinding et GetThisEnvironment, la méthode HasThisBinding renvoie explicitement false.Nous recherchons donc de manière itérative l’environnement externe. Le processus se terminera dans l'un des trois environnements avec la liaison this.
Cela signifie simplement que, dans le corps d'une fonction flèche,
this
vient de la portée lexicale de la fonction flèche , ou en d'autres termes (de Fonctions flèche vs. déclarations/expressions de fonction : sont-elles équivalentes/commutatives ? ) :FonctionPropriétés
Dans les fonctions ordinaires (
.function
, méthodesfunction
、方法),this
) , est déterminé par la méthode d'appel de la fonctionDans l'un des appels de fonction suivants,
func
内的this
值将为refObj
. 1refObj.func()
refObj["func"]()
refObj?.func()
refObj.func?.()
refObj.func``
Si la fonction appelée est syntaxiquement une propriété d'un objet de base, alors cet objet de base sera la "référence" de l'appel, qui dans le cas habituel sera la valeur de
(outhis
的值。上面链接的评估步骤对此进行了解释;例如,在refObj.func()
(或refObj["func"]()
)中,CallMemberExpression 是整个表达式refObj.func()
,它由 MemberExpressionrefObj.func
和 参数()
this. Les étapes d'évaluation liées ci-dessus expliquent cela ; par exemple, dans),
refObj.func
和refObj
CallMemberExpressionest l'expression entière.- , qui se compose de
MemberExpression-
- refObj.func et
paramètres
refObj.func
作为值是可调用的函数对象;相应的引用用于确定this
().De plus,
Ce sont toutes des expressions,?.()
之前、``
joue trois rôles : 代码>Ce sont toutes des références, et Ce sont toutes des valeurs.
ourefObj.func
时为refObj
;或foo.bar
code> 当应用于foo.bar.baz
Reliure. Les exemples facultatifs de modèles de liens et de balises fonctionnent de manière très similaire : en gros, la référence est précédée de().
EvaluateCallthis
。简单属性不会影响执行上下文,例如这里,this
utilise IsPropertyReference
obtiendra cette propriété [[Base]] et l'utilisera comme valeurpour déterminer s'il s'agit syntaxiquement d'une propriété de l'objet. Il tente d'obtenir l'attribut [[Base]] de la référence (par exemple lorsqu'il est appliqué à ). Si vous l'écrivez en tant que propriété,
GetThisValuethis
.Remarque : Comment fonctionnent les Getters/Setters, concernant à l'échelle mondiale :
🎜sans référence de base, mode strict et 🎜🎜avec🎜🎜🎜 🎜Un appel sans référence de base est généralement une fonction non appelée en tant qu'attribut. Par exemple : 🎜 🎜Cela se produit également lors du 🎜passage ou attribution de méthodes🎜, ou lors de l'utilisation de l'🎜opérateur virgule🎜. C'est là que la différence entre l'enregistrement de référence et la valeur est pertinente. 🎜Notez que la fonction
j
:按照规范,您会注意到j
只能返回函数对象(Value)本身,而不能返回引用记录。因此,基本引用refObj
est manquante.EvaluateCall appelle calls, où thisValue est indéfini. C'est différent dans OrdinaryCallBindThis (F : objet fonction ; thisArgument : thisValue transmis à Call) :
Remarque : L'étape 5 définit la valeur réelle de
thisArgumentthis
的实际值设置为严格模式下提供的 thisArgument - 在本例中为undefined
。在“草率模式”下,未定义或 null thisArgument 会导致this
sur le thisArgument fourni en mode strict - dans ce cas,undefined
. En "mode bâclé", unindéfini ou nul fait que devienne la valeur this globale. Si IsPropertyReference
renvoiefalse, alors EvaluateCall suit les étapes suivantes : Ceci n'est pas défini thisValue Peut provenir de : refEnv sec-with-statement-runtime-semantics-evaluation" rel="noreferrer">
Aussi
-
Exemple de définition d'une valeur
En mode non strict, les primitives sont forcées à prendre leur forme de wrapper d'objet. C'est le même type d'objet que vous obtenez lorsque vous appelezinstruction . Dans ce cas,
sera l'objet de liaison.Symbol.unscopables
(MDN 上的文档)来控制with
thisValue
( Documentation sur MDNSymbol.unscopables
) pour contrôler le
this
comportement de liaison. Pour résumer, jusqu'à présent :et :
.call
,.apply
,.bind
Notez que lors du calcul peu importe où une fonction normale est définie.
🎜OrdinaryCallBindThis🎜, contrairement à l'étape 6.2 (dans la spécification), est que la valeur originale 🎜this🎜 est en mode "bâclé" 🎜 uniquement 🎜 convertie en un objet. 🎜.call
,.apply
,.bind
, thisArg et primitif Une autre conséquence de l'étape 5 dePour vérifier cela, introduisons une autre source de valeur this : trois méthodes qui remplacent la liaison this : 4
Function.prototype.apply(thisArg, argArray)
Function.prototype.
{调用
,绑定
}(thisArg, ...args)
李>
Appelle immédiatement la fonction et définit.bind
.bind
创建一个绑定函数,其this 绑定已设置为 thisArg 并且无法再次更改。.call
和.apply
crée une fonction de liaison dont la liaison this est définie sur thisArg et ne peut plus être modifiée..call
et.apply
this
, Utilisez le.call
和.apply
直接映射到 Call ,使用指定的thisArg。.bind
pour qu'il soit lié à thisArg..call
et.apply
correspondent directement à AppelerthisArg spécifié.
pour créer une fonction liée. Ils ont leur propre méthode.bind
Utilisez BoundFunctionCreate[[Call ]]
, qui recherche l'emplacement interne [[BoundThis]] de l'objet fonction.this
Object("s")
或new String("s")
personnalisée : Pour les objets, c'est la même chose en modes strict et non strict.Maintenant, essayez de fournir une valeur brute :
this
. En mode strict vous pouvez utiliser des primitives :
新
Les bibliothèques utilisant ces méthodes telles que jQuery définissent l'élément DOM sélectionné ici :Constructeur,
et 🎜🎜🎜🎜 🎜Lors de l'appel d'une fonction en tant que constructeur à l'aide de l'opérateurnew
运算符将函数作为构造函数调用时,EvaluateNew 调用 Construct,它调用 [[Construct]] 方法。如果函数是基本构造函数(即不是class extends
...{
...}
),它会设置 thisArgument到从构造函数的原型创建的新对象。构造函数中this
上设置的属性最终将出现在生成的实例对象上。this
Classnew
, EvaluateNew est appelé Construct🎜, qui appelle [[Construct]] 🎜. Si la fonction est un constructeur de base (c'est-à-dire pasclass extends
...{
...}
), elle définira 🎜thisArgument🎜 sur la valeur du nouvel objet créé par le prototype du constructeur. Les propriétés définies sur 🎜 dans le constructeur finiront par apparaître sur l'objet instance généré. 🎜 est renvoyé implicitement, sauf si vous renvoyez explicitement votre propre valeur non primitive. 🎜class
est une nouvelle façon de créer des constructeurs, introduite dans ECMAScript 2015.Les définitions de classes sont implicitement en mode strict :
超级
H4>new
行为的例外是class extends
...{
...}
,如上所述。派生类在调用时不会立即设置其 this 值;它们只有在通过一系列super
调用到达基类后才会这样做(在没有自己的构造函数
的情况下隐式发生)。不允许在调用super
之前使用this
.Call
thissuper
super
调用具有调用的词法范围(函数环境记录)的 this 值的超级构造函数。 GetThisValue 对于super
调用有一个特殊的规则。它使用 BindThisValue 将this
Appelle le super constructeur avec la valeur deà partir de la portée lexicale (enregistrement d'environnement de fonction) de l'appel. GetThisValue
Il existe une règle spéciale pour les appelssuper
. Il utilise BindThisValuepour définir
sur cet enregistrement d'environnement.class
5. Champs de classe d'évaluation Les champs d'instance et les champs statiques ont été introduits dans ECMAScript 2022. Lors de l'évaluation de , ClassDefinitionEvaluation est exécutée, modifiant le contexte d'exécution en cours. Pour chaquethis
this
#x
Si le champ n'est pas statique,Des champs privés (par exemple ) et des méthodes sont ajoutés à l'environnement privé. Les
blocs statiquesthis
sont actuellement une
. Les blocs statiques fonctionnent de la même manière que les champs et méthodes statiques : le 🎜 à l'intérieur d'eux fait référence à la classe elle-même. 🎜 🎜Notez que dans les méthodes et les getters/setters, 🎜 fonctionne de la même manière que dans les propriétés normales des fonctions. 🎜this
proposition TC39 Phase 31:
(o.f)()
等价于o.f()
;(f)()
相当于f()
. Cet article sur la 2alité (Archivé). Voir notamment Comment évaluer ParenthesizedExpression.2 : Il doit s'agir d'une MemberExpression em>, ne peut pas être une propriété, doit avoir [[ReferencedName]] avec exactement "eval" et doit être un objet intrinsèque %eval%.
3 : Chaque fois que la spécification dit « que ref soit le résultat de l'évaluation de X », X est une expression dont vous devez trouver les étapes d'évaluation. Par exemple, l'évaluation de MemberExpression ou CallExpression sont ces algorithmes. Certains d'entre eux génèrent des fiches de référence.
4 : Il existe plusieurs autres méthodes natives et hôtes qui permettent de fournir des valeurs this, notamment
MDNArray.prototype.map
,Array.prototype.forEach
, etc. AccepteArray.prototype.map
、Array.prototype.forEach 等接受 thisArg 作为第二个参数。任何人都可以创建自己的方法来更改this
,例如(func, thisArg) => func.bind(thisArg)
、(func, thisArg) => func。 call(thisArg)
thisArg comme deuxième paramètre. N'importe qui peut créer ses propres méthodes pour modifier , telles que(func, thisArg) => func.bind(thisArg)
,(func, thisArg) => func. appeler(thisArg)
etc. Comme toujours,fournit une excellente documentation de service.
Juste pour vous amuser, testez votre compréhension avec quelques exemples
à la ligne marquée ? Pourquoi ?"this
Pour chaque extrait de code, répondez à la question suivante : "Quelle est la valeur dePour révéler la réponse, cliquez sur la case grise.