Fahami fungsi dan penggunaan kata kunci "ini" yang sesuai
P粉155551728
P粉155551728 2023-10-12 15:50:58
0
2
593

Saya berharap dapat mencari penjelasan yang jelas tentang perkara yang dilakukan oleh kata kunci "ini" dan cara menggunakannya dengan betul.

Nampaknya berkelakuan pelik dan saya tidak faham sepenuhnya mengapa.

thisBagaimana ia berfungsi dan bila anda perlu menggunakannya?

P粉155551728
P粉155551728

membalas semua(2)
P粉087951442

Berbanding dengan bahasa lain, this 关键字在 JavaScript 中的行为有所不同。在面向对象语言中,this 关键字指的是该类的当前实例。在 JavaScript 中,this 的值由函数的调用上下文 (context.function()) dan kedudukan panggilannya ditentukan. p>

1. Apabila digunakan dalam konteks global

Apabila anda menggunakannya dalam konteks global this 时,它会绑定到全局对象(浏览器中的window)

document.write(this);  //[object Window]

Apabila anda menggunakan this 时,this di dalam fungsi yang ditakrifkan dalam konteks global anda masih terikat dengan objek global kerana fungsi itu sebenarnya adalah kaedah konteks global.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

Panggil pada objek f1是一个全局对象的方法。因此我们也可以在 window di atas, seperti ini:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. Apabila digunakan di dalam kaedah objek

Apabila anda menggunakan this 关键字时,this di dalam kaedah objek ia mengikat objek "terus" yang melampirkan.

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

Saya telah meletakkan perkataan "segera" dalam petikan berganda di atas. Ini adalah untuk menunjukkan bahawa jika objek bersarang dalam objek lain, this terikat pada objek induk terdekat.

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

Walaupun anda menambah fungsi sebagai kaedah pada objek secara eksplisit, ia masih mengikut peraturan di atas, iaitu this masih menunjuk kepada objek induk langsung.

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. Apabila memanggil fungsi tanpa konteks

Digunakan this 时,它会绑定到全局对象(浏览器中的window) apabila anda memanggilnya di dalam fungsi tanpa sebarang konteks (iaitu bukan pada sebarang objek) (walaupun jika fungsi itu ditakrifkan di dalam objek).

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

Cuba semua dengan fungsi

Kita juga boleh menggunakan fungsi untuk mencuba perkara di atas. Tetapi masih terdapat beberapa perbezaan.

  • Di atas kami menambah ahli pada objek menggunakan notasi literal objek. Kita boleh menambah ahli ke fungsi menggunakan this. untuk menentukan mereka.
  • Notasi literal objek mencipta contoh objek yang boleh kami gunakan serta-merta. Untuk fungsi, kita mungkin perlu mencipta instance menggunakan operator new dahulu.
  • Juga dalam kaedah literal objek, kita boleh menambah ahli secara eksplisit pada objek yang ditentukan menggunakan pengendali titik. Ini hanya ditambahkan pada keadaan tertentu. Walau bagaimanapun, saya telah menambah pembolehubah pada prototaip fungsi supaya ia ditunjukkan dalam semua keadaan fungsi.

Di bawah saya mencuba semua yang saya lakukan di atas dengan Object dan this tetapi mula-mula mencipta fungsi dan bukannya menulis objek secara langsung.

/********************************************************************* 
  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. Apabila digunakan di dalam pembina .

Apabila fungsi digunakan sebagai pembina (iaitu, apabila dipanggil menggunakan kata kunci new 关键字调用时),函数体内的 this), dalam badan fungsi menghala ke objek baharu yang sedang dibina.

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. Apabila digunakan di dalam fungsi yang ditakrifkan pada rantai prototaip 🎜

Jika kaedah berada pada rantai prototaip objek, maka this dalam kaedah merujuk kepada objek yang kaedah dipanggil, seolah-olah kaedah itu ditakrifkan pada objek itu.

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. Fungsi panggilan dalaman(), apply() dan bind()

  • Semua kaedah ini ditakrifkan pada Function.prototype.
  • Kaedah ini membenarkan menulis fungsi sekali dan memanggilnya dalam konteks yang berbeza. Dalam erti kata lain, mereka membenarkan menentukan nilai this yang akan digunakan semasa melaksanakan fungsi. Mereka juga boleh menghantar sebarang hujah kepada fungsi asal apabila ia dipanggil.
  • fun.apply(obj1 [, argsArray])obj1 设置为 this 内的值code>fun() 并调用 fun(),传递 argsArrayfun.apply(obj1 [, argsArray])
  • Tetapkan
  • obj1 kepada nilai dalam code>fun() dan panggil fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - 设置 obj1 作为 fun()this 的值,并调用 fun()fun() , menghantar elemen argsArray sebagai hujahnya.
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - 返回对函数的引用fun,其中 fun 内的 this 绑定到 obj1,并且 fun 的参数绑定到指定的参数 arg1、arg2, arg3,... - Tetapkan obj1 sebagai
  • fun() di dalam
  • nilai, dan memanggil applycallbind 之间的区别一定已经很明显了。 apply 允许将参数指定为类似数组的对象,即具有数字 length 属性和相应的非负整数属性的对象。而 call 允许直接指定函数的参数。 applycallfun() menghantar
  • arg1, arg2, arg3, ...
sebagai hujahnya.

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

- Mengembalikan rujukan kepada fungsi fun, di mana menyeronokkan ialah 🎜 terikat kepada 🎜obj1 dan hujah 🎜fun terikat kepada hujah yang ditentukan 🎜arg1, arg2, arg3,.... 🎜 🎜Kini, perbezaan antara 🎜apply, 🎜call dan 🎜bind mestilah jelas. 🎜apply membenarkan hujah ditentukan sebagai objek seperti tatasusunan, iaitu objek dengan sifat 🎜length angka dan sifat integer bukan negatif yang sepadan. Dan 🎜panggilan membolehkan parameter fungsi ditentukan secara langsung. Kedua-dua 🎜apply dan 🎜call segera panggil fungsi dalam konteks yang ditentukan dan dengan parameter yang ditentukan. bind, sebaliknya, hanya mengembalikan fungsi terikat kepada nilai dan argumen ini yang ditentukan. Kita boleh menangkap rujukan kepada fungsi yang dikembalikan ini dengan memberikannya kepada pembolehubah, yang kemudiannya boleh kita panggil pada bila-bila masa. 🎜 🎜
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. 🎜🎜🎜 di dalam pengendali acara
  • Apabila anda menetapkan fungsi terus kepada pengendali acara elemen, ini dilakukan menggunakan kaedah pendaftaran acara tradisional seperti this 来引用相应的元素。这种直接的函数分配可以使用 addeventListener 方法或通过 onclick terus dalam fungsi pengendali acara.
  • Begitu juga, apabila anda memanggil atribut acara elemen seperti )内使用 this , ia merujuk kepada elemen
  • Walau bagaimanapun, this 会解析为全局对象 window digunakan secara tidak langsung melalui fungsi lain yang dipanggil dalam pengendali acara atau sifat acara.
  • Tingkah laku yang sama seperti di atas boleh dicapai apabila kami menggunakan pendekatan model pendaftaran acara Microsoft attachEvent untuk melampirkan fungsi pada pengendali acara. Daripada memberikan fungsi kepada pengendali acara (dengan itu mencipta kaedah fungsi elemen), ia memanggil fungsi pada acara (dengan berkesan memanggilnya dalam konteks global).

Saya syorkan JSFiddle中更好地尝试此操作>.

sssccc

Using `this` "directly" inside event handler or event property



Using `this` "indirectly" inside event handler or event property



IE only:

8. this

dalam fungsi anak panah ES6

Dalam fungsi anak panah, this 的行为类似于公共变量:它将从其词法范围继承。定义箭头函数的函数的 this 将是箭头函数的 this berkelakuan seperti pembolehubah awam: ia akan diwarisi daripada skop leksikalnya.

fungsi yang mentakrifkan fungsi anak panah akan menjadi

fungsi anak panah.

Jadi, ini adalah kelakuan yang sama seperti:

(function(){}).bind(this)
🎜Lihat kod di bawah: 🎜
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

ialah kata kunci dalam JavaScript yang merupakan atribut konteks pelaksanaan. Penggunaan utamanya adalah dalam fungsi dan pembina. this Peraturannya agak mudah (jika anda berpegang kepada amalan terbaik).

Penerangan teknikalthis dalam spesifikasi

ECMAScript standarddefinisithis melalui operasi abstrak (disingkatkan sebagai AO) ResolveThisBinding:

Rekod persekitaran global, Rekod persekitaran modul, dan Rekod persekitaran fungsi masing-masing mempunyai kaedah GetThisBinding mereka sendiri.

GetThisEnvironment AO mencari LexicalEnvironment bagi konteks pelaksanaan menjalankan semasa dan mencari rekod persekitaran menaik yang paling hampir (dengan mengulangi sifat [[OuterEnv]]nya) yang mempunyai ini mengikat ini mengikat

ini

. . Proses ini berakhir dengan satu daripada tiga jenis rekod persekitaran. this Nilai biasanya bergantung pada sama ada kod berada dalam

mod ketat

. this 值,因此每当建立新的执行上下文时,this Nilai pulangan

GetThisBinding mencerminkan nilai

konteks pelaksanaan semasa, jadi setiap kali konteks pelaksanaan baharu diwujudkan, akan menyelesaikan kepada nilai yang berbeza. Ini juga boleh berlaku apabila konteks pelaksanaan semasa diubah suai. Subseksyen berikut menyenaraikan lima senario di mana ini mungkin berlaku.

Anda boleh meletakkan sampel kod ke dalam

AST Explorer

untuk mengikuti butiran spesifikasi.

1. Konteks pelaksanaan global dalam skrip

Ini ialah kod skrip yang dinilai di peringkat teratas, mis this Apabila dalam konteks pelaksanaan global awal skrip, menilai menyebabkan

GetThisBinding🎜 mengambil langkah berikut: 🎜

Harta [[GlobalThisValue]] rekod persekitaran global sentiasa ditetapkan kepada objek global yang ditentukan hos, boleh diakses melalui globalThisglobalThis ( Web 上的 window,Node.js 上的 global (tetingkap di web , Node.js global Dokumentasi di MDN). Ikuti langkah InitializeHostDefinedRealm untuk mengetahui cara sifat [[GlobalThisValue]] dijana.

2. Konteks pelaksanaan global dalam modul

Modul telah diperkenalkan dalam ECMAScript 2015.

Ini berfungsi untuk modul cth. 内部时,而不是简单的

Apabila dalam konteks pelaksanaan global awal modul, menilai

menyebabkan thisGetThisBinding mengambil langkah berikut:

Dalam modul, nilai

sentiasa tidak ditentukan

dalam konteks global. Modul secara tersirat dalam this 的值在全局上下文中始终是未定义mod ketat.

3. Masukkan

evalkod

Terdapat dua jenis

panggilan: evallangsungdan tidak langsung. Perbezaan ini telah wujud sejak edisi kelima ECMAScript.

  • Langsung eval 调用通常类似于 eval(...);(eval)(...); (或 ((eval))(); dll.). 1 Ini hanya langsung (jika ungkapan panggilan menepati corak sempit). 2
  • Tidak langsungeval调用涉及以任何其他方式调用函数引用eval。它可以是 eval?.(...), (..., eval)(...), window.eval(...), eval.call(...,...)给定 const aliasEval1 = eval; 等。 window.aliasEval2 = eval;,也可以是 aliasEval1()aliasEval2()代码>.分别给出 const originalEval = eval; window.eval = (x) => originalEval(x);,调用 eval() juga tidak langsung.

Lihat jawapan chuckj untuk "(1, eval)('this') vs eval('this') dalam JavaScript?" dan Dmitry Soshnikov ECMA-262- 5 butiran – Bab 2: Mod Ketat (Arkib), untuk kes di mana anda mungkin menggunakan panggilan eval() tidak langsung.

PerformEval melaksanakan kod eval 代码。它创建一个新的 声明性环境记录 作为其 LexicalEnvironment,这是 GetThisEnvironment 从中获取 thiseval. Ia mencipta

rekod persekitaran deklaratif

baharu sebagai LexicalEnvironmentnya, iaitu GetThisEnvironmentthis出现在eval untuk mendapatkan ini daripada > nilai.

Kemudian, jika

dalam kod, GetThisEnvironment dipanggil dan nilainya dikembalikan. dicipta

rekod persekitaran deklaratif daripada

rekod alam

yang melaksanakan penilaian tidak langsung). 🎜 🎜 🎜Ini bermaksud: 🎜
  • Dalam penilaian langsung, skop leksikal this 值不会改变;它取自名为 eval.
  • Dalam eval tidak langsung, this 值是全局对象 (globalThis).

新函数怎么样? — new FunctionevalSerupa, tetapi ia tidak memanggil kod dengan serta-merta; ini Pengikatan tidak terpakai di mana-mana di sini kecuali apabila memanggil fungsi, yang berfungsi dengan baik seperti yang diterangkan dalam subseksyen seterusnya.

4. Masukkan fungsikod

Masukkan kod fungsi apabila memanggil fungsi .

Terdapat empat kategori sintaks untuk fungsi panggilan.

Panggilan fungsi sebenar berlaku di Panggilan AO, yang ditentukan oleh konteks panggilan menggunakan ThisValue parameter ini diluluskan dalam senarai panjang panggilan yang berkaitan dengan panggilan. Panggil memanggil [[Panggil]] slot dalaman fungsi. Ini memanggil PrepareForOrdinaryCall, di mana rekod persekitaran fungsi baharu telah dibuat:

Selain itu, terdapat juga medan [[ThisValue]] dalam rekod persekitaran fungsi:

Panggilan

NewFunctionEnvironment juga menetapkan sifat [[ThisBindingStatus]] bagi persekitaran fungsi.

[[Panggil]] juga memanggil OrdinaryCallBindThis, di mana thisArgument yang sesuai ditentukan berdasarkan:

  • Rujukan asal,
  • Jenis fungsi, dan
  • Sama ada kod dalam mod ketat.

Selepas pengesahan, kaedah BindThisValue rekod persekitaran fungsi yang baru dicipta akhirnya dipanggil untuk benar-benar menetapkan medan [[ThisValue]] untuk ditambahkan pada thisArgument.

Akhir sekali, medan ini ialah rekod persekitaran fungsi GetThisBinding AO mendapat nilai this dari lokasi berikut:

Sekali lagi, penentuan tepat nilai ini bergantung kepada banyak faktor; ini hanyalah gambaran umum. Dengan latar belakang teknikal ini, mari kita lihat semua contoh konkrit.

Fungsi anak panah

Apabila mengira fungsi anak panah, sifat objek fungsi slot dalaman [[ThisMode]] ditetapkan kepada "leksikal" dalam OrdinaryFunctionCreate. p>

Di OrdinaryCallBindThis ia memerlukan fungsi F:

Ini hanya bermakna bahawa baki algoritma yang mengikat ini dilangkau. Fungsi anak panah tidak mengikat nilai ini mereka sendiri.

Jadi, apakah this dalam fungsi anak panah? Untuk menyemak ResolveThisBinding dan GetThisEnvironment, kaedah HasThisBinding secara eksplisit mengembalikan false.

Jadi kami secara berulang mencari persekitaran luaran. Proses ini akan berakhir dalam satu daripada tiga persekitaran dengan pengikatan ini.

Ini hanya bermaksud bahawa, dalam badan fungsi anak panah, this berasal daripada skop leksikal fungsi anak panah , atau dengan kata lain (dari Fungsi anak panah vs. pengisytiharan/ungkapan fungsi: adakah ia setara/komutatif? ):

FungsiSifat

Dalam fungsi biasa (fungsi, kaedah function方法),this ) , ditentukan oleh kaedah panggilan fungsi

.

Di sinilah "variasi tatabahasa" ini berguna.

Pertimbangkan objek ini yang mengandungi fungsi:

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

Dalam mana-mana panggilan fungsi berikut, func 内的 this 值将为 refObj. 1

  • refObj.func()
  • refObj["func"]()
  • refObj?.func()
  • refObj.func?.()
  • refObj.func``

Jika fungsi yang dipanggil secara sintaksis adalah sifat objek asas, maka objek asas itu akan menjadi "rujukan" panggilan, yang dalam kes biasa ialah nilai this 的值。上面链接的评估步骤对此进行了解释;例如,在 refObj.func() (或 refObj["func"]())中,CallMemberExpression 是整个表达式 refObj.func(),它由 MemberExpression refObj.func参数 ()ini. Langkah penilaian yang dipautkan di atas menerangkan perkara ini; contohnya, dalam

(atau

), refObj.funcrefObjCallMemberExpression

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

Selain itu, ?.() 之前、`` memainkan tiga peranan: 代码>

Mereka semua adalah ungkapan,

Semuanya adalah rujukan, dan Semuanya adalah nilai. refObj.func 时为 refObj;或 foo.bar code> 当应用于 foo.bar.baz Mengikat. Pautan pilihan dan contoh templat teg berfungsi sangat serupa: pada asasnya, rujukan didahului dengan

atau

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

EvaluateCall

menggunakan IsPropertyReference untuk menentukan sama ada ia secara sintaksis merupakan sifat objek. Ia cuba mendapatkan atribut [[Base]] rujukan (cth. apabila digunakan pada ). Jika anda menulisnya sebagai harta, GetThisValue

akan mendapatkan harta [[Base]] ini dan menggunakannya sebagai nilai

this

.

Nota: Cara Penetap/Penetap berfungsi, berkenaan dalam skop global:

const o = {
    a: 1,
    b: this.a, // Is `globalThis.a`.
    [this.a]: 2 // Refers to `globalThis.a`.
  };
🎜tanpa rujukan asas, mod ketat dan 🎜🎜dengan🎜🎜🎜 🎜Panggilan tanpa rujukan asas biasanya merupakan fungsi yang tidak dipanggil sebagai atribut. Contohnya: 🎜
func(); // As opposed to `refObj.func();`.
🎜Ini juga berlaku apabila 🎜lulus atau menetapkan kaedah🎜, atau apabila menggunakan 🎜 pengendali koma🎜. Di sinilah perbezaan antara rekod rujukan dan nilai adalah relevan. 🎜

Perhatikan bahawa fungsi j:按照规范,您会注意到j只能返回函数对象(Value)本身,而不能返回引用记录。因此,基本引用 refObj tiada.

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 panggilan panggilan, di mana thisValue adalah undefined. Ini berbeza dalam OrdinaryCallBindThis (F: fungsi objek; thisArgument: thisValue dihantar ke Panggil):

Nota: Langkah 5 menetapkan nilai sebenar this 的实际值设置为严格模式下提供的 thisArgument - 在本例中为 undefined。在“草率模式”下,未定义或 null thisArgument 会导致 this kepada thisArgument yang disediakan dalam mod ketat - dalam kes ini, undefined. Dalam "mod ceroboh", tidak ditentukan atau batal

Argumen ini

menyebabkan menjadi nilai ini global. Jika IsPropertyReference

mengembalikan

false, maka EvaluateCall mengambil langkah berikut: Ini tidak ditentukan Nilai ini Boleh datang daripada: refEnv sec-with-statement-runtime-semantics-evaluation" rel="noreferrer">

. Dalam kes ini, thisValueSymbol.unscopables (MDN 上的文档)来控制 with akan menjadi objek pengikat.

Juga

Symbol.unscopables

( Dokumentasi tentang MDN

) untuk mengawal

kelakuan yang mengikat. this Untuk meringkaskan, setakat ini:

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

dan:

"use strict";

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

f(); // Logs `undefined`.

// `with` statements are not allowed in strict-mode code.
Perhatikan bahawa apabila mengira .call, .apply.bind ia tidak penting di mana fungsi normal ditakrifkan.

.call, .apply, .bind, thisArg dan primitif Satu lagi akibat daripada langkah 5

OrdinaryCallBindThis🎜, tidak seperti langkah 6.2 (dalam spesifikasi), ialah nilai 🎜ini🎜 asal berada dalam mod "ceroboh" 🎜 sahaja 🎜 dilemparkan ke objek. 🎜

Untuk menyemak ini, mari perkenalkan satu lagi sumber nilai ini: tiga kaedah yang mengatasi pengikatan ini: 4

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

.bind.bind 创建一个绑定函数,其this 绑定已设置为 thisArg 并且无法再次更改。 .call.apply mencipta fungsi mengikat yang pengikatan ini sudah ditetapkan kepada Arg ini dan tidak boleh ditukar lagi. .call dan .apply

Panggil fungsi dengan segera dan tetapkan

ini.call.apply 直接映射到 Call ,使用指定的thisArg.bind untuk terikat kepada Arg ini. .call dan .apply peta terus ke Panggil

, Gunakan

thisArg yang dinyatakan. .bind Gunakan BoundFunctionCreate

untuk mencipta fungsi terikat. Mereka mempunyai kaedah

[[Panggil ]] sendiri

, yang mencari slot dalaman [[BoundThis]] bagi objek fungsi.

Contoh menetapkan nilai tersuai

iniObject("s")new String("s"):

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);
Untuk objek, ini adalah sama dalam mod ketat dan tidak ketat.

Sekarang, cuba berikan nilai mentah: this

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

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

g();              // Logs `String { "s" }`.
f.call(myString); // Logs `String { "s" }`.
Dalam mod tidak ketat, primitif dipaksa ke bentuk pembalut objeknya. Ia adalah jenis objek yang sama yang anda dapat semasa memanggil

. Dalam mod ketat anda boleh menggunakan primitif:
"use strict";

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

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

g();              // Logs `"s"`.
f.call(myString); // Logs `"s"`.
Perpustakaan yang menggunakan kaedah ini seperti set jQuery
ke elemen DOM yang dipilih di sini:

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

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

dan 🎜🎜🎜🎜 🎜Apabila memanggil fungsi sebagai pembina menggunakan operator baharu, EvaluateNew ialah dipanggil Construct🎜, yang memanggil kaedah [[Construct]] 🎜. Jika fungsi itu ialah pembina asas (iaitu bukan class extends...{...}), ia akan menetapkan 🎜thisArgument🎜 kepada nilai daripada Objek baru yang dicipta oleh prototaip pembina. Sifat yang ditetapkan pada 🎜 dalam pembina akhirnya akan muncul pada objek contoh yang dijana. 🎜 dikembalikan secara tersirat melainkan anda secara eksplisit mengembalikan nilai bukan primitif anda sendiri. 🎜

class ialah cara baharu mencipta pembina, yang diperkenalkan dalam 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 }`.

Takrifan kelas secara tersirat dalam mod ketat:

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.

Panggil supersuper 调用具有调用的词法范围(函数环境记录)的 this 值的超级构造函数。 GetThisValue 对于 super 调用有一个特殊的规则。它使用 BindThisValuethis Memanggil super constructor dengan nilai

ini

daripada skop leksikal (rekod persekitaran fungsi) panggilan. GetThisValue

Terdapat peraturan khas untuk panggilan super. Ia menggunakan BindThisValue

untuk menetapkan

kepada rekod persekitaran tersebut.

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. Medan kelas penilaian
Medan contoh dan medan statik telah diperkenalkan dalam ECMAScript 2022. Apabila menilai , ClassDefinitionEvaluation dilaksanakan, mengubah suai konteks pelaksanaan yang sedang berjalan. Untuk setiap
  • Elemen Kelasthis
  • :
  • this
  • Jika medan statik,
merujuk kepada kelas itu sendiri,

#xJika medan tidak statik,

merujuk kepada contoh.

Medan peribadi (cth. ) dan kaedah ditambahkan pada persekitaran peribadi. this

Blok Statik

adalah cadangan thisTC39 Fasa 3

. Blok statik berfungsi dengan cara yang sama seperti medan dan kaedah statik: 🎜 di dalamnya merujuk kepada kelas itu sendiri. 🎜 🎜Perhatikan bahawa dalam kaedah dan getter/setter, 🎜 berfungsi sama seperti dalam sifat fungsi biasa. 🎜
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(). Artikel 2ality ini (Arkib). Lihat terutamanya Cara menilai ParenthesizedExpression.

2: Ia mestilah MemberExpression em>, tidak boleh menjadi harta, mesti mempunyai [[ReferencedName]] dengan tepat "eval", dan mestilah objek intrinsik %eval%.

3: Setiap kali spesifikasi mengatakan "biar ref menjadi hasil menilai X", X ialah beberapa ungkapan yang langkah penilaiannya perlu anda cari. Contohnya, menilai MemberExpression atau CallExpression ialah algoritma ini. Sebahagian daripada mereka menjana rekod rujukan.

4: Terdapat beberapa kaedah asli dan hos lain yang membenarkan menyediakan nilai ini, terutamanya Array.prototype.map, Array.prototype.forEach, dsb. Menerima Array.prototype.map、Array.prototype.forEach 等接受 thisArg 作为第二个参数。任何人都可以创建自己的方法来更改 this,例如 (func, thisArg) => func.bind(thisArg)(func, thisArg) => func。 call(thisArg)Arg ini sebagai hujah kedua. Sesiapa sahaja boleh mencipta kaedah mereka sendiri untuk menukar , seperti (func, thisArg) => func.bind(thisArg), (func, thisArg) => func. call(thisArg) dsb. Seperti biasa,

MDN
menyediakan dokumentasi perkhidmatan yang hebat.

Hanya untuk keseronokan, uji pemahaman anda dengan beberapa contoh thisUntuk setiap coretan kod, jawab soalan berikut: "Apakah nilai

pada baris yang ditanda? Mengapa?"

Untuk mendedahkan jawapan, klik pada kotak kelabu.

  1. if(true){
      console.log(this); // What is `this` here?
    }
    

    globalThis. Garis yang ditanda dinilai dalam konteks pelaksanaan global awal.

  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());
    
       
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan