Comprendre la fonction et l'utilisation appropriée du mot-clé « this »
P粉155551728
P粉155551728 2023-10-12 15:50:58
0
2
617

J'espérais trouver une explication claire de ce que fait le mot-clé "this" et comment l'utiliser correctement.

Il semble se comporter étrangement et je ne comprends pas vraiment pourquoi.

thisComment ça marche et quand faut-il l'utiliser ?

P粉155551728
P粉155551728

répondre à tous(2)
P粉087951442

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.
  • fun.apply(obj1 [, argsArray])obj1 设置为 this 内的值code>fun() 并调用 fun(),传递 argsArrayfun.apply(obj1 [, argsArray])
  • Définissez
  • 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 applycallbind 之间的区别一定已经很明显了。 apply 允许将参数指定为类似数组的对象,即具有数字 length 属性和相应的非负整数属性的对象。而 call 允许直接指定函数的参数。 applycallfun() en passant
  • arg1, arg2, arg3, ...
comme arguments.

thisfun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])

- 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).

Je recommande JSFiddle中更好地尝试此操作>.

sssccc

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

de la fonction flèche.

C'est donc le même comportement que :

(function(){}).bind(this)
🎜Voir le code ci-dessous : 🎜
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 
P粉156532706

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

Standard ECMAScriptdéfinitionthis via des opérations abstraites (en abrégé AO) ResolveThisBinding :

Les

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

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.

Vous pouvez placer des échantillons de code dans AST Explorer

pour suivre les détails des spécifications.

1. Contexte d'exécution global dans les scripts

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.

2. Contexte d'exécution global dans module

Les modules ont été introduits dans ECMAScript 2015.

Cela fonctionne pour les modules, par exemple directement à l'intérieur 内部时,而不是简单的 .

Dans le contexte d'exécution global initial d'un module, l'évaluation de this amène GetThisBinding à suivre les étapes suivantes :

Dans un module, la valeur de this 的值在全局上下文中始终是未定义 est toujours indéfini dans le contexte global. Les modules sont implicitement en mode strict.

3. Entrez le evalcode

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
  • Indirecteval调用涉及以任何其他方式调用函数引用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 eval 代码。它创建一个新的 声明性环境记录 作为其 LexicalEnvironment,这是 GetThisEnvironment 从中获取 thiseval. Il crée un nouvel

enregistrement d'environnement déclaratif

en tant que LexicalEnvironment, qui est GetThisEnvironmentthis出现在eval pour obtenir this from > value.

Ensuite, si

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 FunctionevalSimilaire, 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'appel

NewFunctionEnvironment 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 :

  • Référence originale,
  • Le type de fonction, et
  • Si le code est en mode strict.

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éthodes function方法),this ) , est déterminé par la méthode d'appel de la fonction

.

C'est là que ces « variations grammaticales » sont utiles.

Considérons cet objet contenant une fonction :

const refObj = {
    func: function(){
      console.log(this);
    }
  };
ou : 🎜
const refObj = {
    func(){
      console.log(this);
    }
  };

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(),它由 MemberExpression refObj.func参数 ()this. Les étapes d'évaluation liées ci-dessus expliquent cela ; par exemple, dans

(ou

), refObj.funcrefObjCallMemberExpression

refObj.func作为是可调用的函数对象;相应的引用用于确定this().

De plus, ?.() 之前、`` joue trois rôles : 代码>

Ce sont toutes des expressions,

Ce sont toutes des références, et Ce sont toutes des valeurs. refObj.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

ou

(). this。简单属性不会影响执行上下文,例如这里,this

EvaluateCall

utilise IsPropertyReference pour 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é, GetThisValue

obtiendra cette propriété [[Base]] et l'utilisera comme valeur

this

.

Remarque : Comment fonctionnent les Getters/Setters, concernant à l'échelle mondiale :

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.

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 this 的实际值设置为严格模式下提供的 thisArgument - 在本例中为 undefined。在“草率模式”下,未定义或 null thisArgument 会导致 this sur le thisArgument fourni en mode strict - dans ce cas, undefined. En "mode bâclé", un

thisArgument

indéfini ou nul fait que devienne la valeur this globale. Si IsPropertyReference

renvoie

false, 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">

instruction . Dans ce cas, Symbol.unscopables (MDN 上的文档)来控制 withthisValue

sera l'objet de liaison.

Aussi

Symbol.unscopables

( Documentation sur MDN

) pour contrôler le thiscomportement de liaison. Pour résumer, jusqu'à présent :

function f1(){
  console.log(this);
}

function f2(){
  console.log(this);
}

function f3(){
  console.log(this);
}

const o = {
    f1,
    f2,
    [Symbol.unscopables]: {
      f2: true
    }
  };

f1(); // Logs `globalThis`.

with(o){
  f1(); // Logs `o`.
  f2(); // `f2` is unscopable, so this logs `globalThis`.
  f3(); // `f3` is not on `o`, so this logs `globalThis`.
}

et :
"use strict";

function f(){
  console.log(this);
}

f(); // Logs `undefined`.

// `with` statements are not allowed in strict-mode code.
.call
, .apply.bindNotez que lors du calcul peu importe où une fonction normale est définie.

.call, .apply, .bind, thisArg et primitif Une autre conséquence de l'étape 5 de

🎜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

  • Function.prototype.apply(thisArg, argArray)
  • Function.prototype. {调用, 绑定} (thisArg, ...args)李>

.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

Appelle immédiatement la fonction et définit

this.call.apply 直接映射到 Call ,使用指定的thisArg.bind pour qu'il soit lié à thisArg. .call et .apply correspondent directement à Appeler

, Utilisez le

thisArg spécifié. .bind Utilisez BoundFunctionCreate

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

function f(){
  console.log(this);
}

const myString = "s",
  g = f.bind(myString);

g();              // Logs `String { "s" }`.
f.call(myString); // Logs `String { "s" }`.

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 :
"use strict";

function f(){
  console.log(this);
}

const myString = "s",
  g = f.bind(myString);

g();              // Logs `"s"`.
f.call(myString); // Logs `"s"`.
Les bibliothèques utilisant ces méthodes telles que jQuery définissent
l'élément DOM sélectionné ici :

$("button").click(function(){
  console.log(this); // Logs the clicked button.
});

Constructeur, new 运算符将函数作为构造函数调用时,EvaluateNew 调用 Construct,它调用 [[Construct]] 方法。如果函数是基本构造函数(即不是 class extends...{...}),它会设置 thisArgument到从构造函数的原型创建的新对象。构造函数中 this 上设置的属性最终将出现在生成的实例对象上。 thisClass

et 🎜🎜🎜🎜 🎜Lors de l'appel d'une fonction en tant que constructeur à l'aide de l'opérateur new, EvaluateNew est appelé Construct🎜, qui appelle [[Construct]] 🎜. Si la fonction est un constructeur de base (c'est-à-dire pas class 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.

function Old(a){
  this.p = a;
}

const o = new Old(1);

console.log(o);  // Logs `Old { p: 1 }`.

class New{
  constructor(a){
    this.p = a;
  }
}

const n = new New(1);

console.log(n); // Logs `New { p: 1 }`.

Les définitions de classes sont implicitement en mode strict :

class A{
  m1(){
    return this;
  }
  m2(){
    const m1 = this.m1;
    
    console.log(m1());
  }
}

new A().m2(); // Logs `undefined`.

超级 H4>

new 行为的例外是 class extends...{...},如上所述。派生类在调用时不会立即设置其 this 值;它们只有在通过一系列 super 调用到达基类后才会这样做(在没有自己的构造函数的情况下隐式发生)。不允许在调用 super 之前使用 this.

Call supersuper 调用具有调用的词法范围(函数环境记录)的 this 值的超级构造函数。 GetThisValue 对于 super 调用有一个特殊的规则。它使用 BindThisValuethis 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

pour définir

sur cet enregistrement d'environnement.

class DerivedNew extends New{
  constructor(a, a2){
    // Using `this` before `super` results in a ReferenceError.
    super(a);
    this.p2 = a2;
  }
}

const n2 = new DerivedNew(1, 2);

console.log(n2); // Logs `DerivedNew { p: 1, p2: 2 }`.
class5. 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 chaque
  • ClassElementthis
  •  :
  • this
  • Si le champ est statique,
fait référence à la classe elle-même,

#xSi le champ n'est pas statique,

fait référence à l'instance.

Des champs privés (par exemple ) et des méthodes sont ajoutés à l'environnement privé. Les this

blocs statiques

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`.

1:(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 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 exemples thisPour 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.

  1. 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.

  2. const obj = {};
    
    function myFun(){
      return { // What is `this` here?
        "is obj": this === obj,
        "is globalThis": this === globalThis
      };
    }
    
    obj.method = myFun;
    
    console.log(obj.method());
    
       
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal