Apa yang harus Anda ketahui this
this(alias "konteks") adalah kata kunci khusus di dalam setiap fungsi dan nilainya hanya tergantung pada bagaimana fungsi itu dipanggil, bukan bagaimana / kapan / di mana ia didefinisikan. Itu tidak dipengaruhi oleh lingkup leksikal seperti variabel lain (kecuali untuk fungsi panah, lihat di bawah). Berikut ini beberapa contohnya:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Untuk mempelajari lebih lanjut this, lihat dokumentasi MDN .
Cara merujuk ke yang benar this
Jangan gunakan this
Anda sebenarnya tidak ingin mengakses thissecara khusus, tetapi objek yang dimaksud . Itu sebabnya solusi mudah adalah dengan membuat variabel baru yang juga merujuk ke objek itu. Variabel dapat memiliki nama apa saja, tetapi yang umum adalah selfdan that.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Karena selfmerupakan variabel normal, ia mematuhi aturan lingkup leksikal dan dapat diakses di dalam callback. Ini juga memiliki keuntungan bahwa Anda dapat mengakses thisnilai dari panggilan balik itu sendiri.
Atur thispanggilan balik secara eksplisit - bagian 1
Mungkin terlihat seperti Anda tidak memiliki kontrol atas nilai thiskarena nilainya diatur secara otomatis, tetapi sebenarnya tidak demikian.
Setiap fungsi memiliki metode .bind [docs] , yang mengembalikan fungsi baru yang thisterikat ke suatu nilai. Fungsi ini memiliki perilaku yang persis sama dengan yang Anda panggil .bind, hanya itu thisyang Anda tetapkan. Tidak peduli bagaimana atau kapan fungsi itu dipanggil, thisakan selalu merujuk pada nilai yang diteruskan.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
Dalam hal ini, kami mengikat panggilan balik thiske nilai MyConstructor's this.
Catatan: Saat mengikat konteks untuk jQuery, gunakan jQuery.proxy [docs] sebagai gantinya. Alasan untuk melakukan ini adalah agar Anda tidak perlu menyimpan referensi ke fungsi tersebut saat melepaskan ikatan peristiwa. jQuery menanganinya secara internal.
ECMAScript 6 memperkenalkan fungsi panah , yang dapat dianggap sebagai fungsi lambda. Mereka tidak memiliki thisikatan sendiri . Sebaliknya, thisdilihat dalam lingkup seperti variabel normal. Itu berarti Anda tidak perlu menelepon .bind. Itu bukan satu-satunya perilaku khusus yang mereka miliki, silakan lihat dokumentasi MDN untuk informasi lebih lanjut.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
Set thispanggilan balik - bagian 2
Beberapa fungsi / metode yang menerima panggilan balik juga menerima nilai yang menjadi thisacuan panggilan balik itu . Ini pada dasarnya sama dengan mengikatnya sendiri, tetapi fungsi / metode melakukannya untuk Anda. Array#map [Docs] adalah metode semacam itu. Tanda tangannya adalah:
array.map(callback[, thisArg])
Argumen pertama adalah callback dan argumen kedua adalah nilai yang thisharus dirujuk. Berikut adalah contoh yang dibuat-buat:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
Catatan: Apakah Anda dapat memberikan nilai atau tidak thisbiasanya disebutkan dalam dokumentasi fungsi / metode tersebut. Misalnya, metode jQuery [docs]$.ajax menjelaskan opsi yang disebut context:
Objek ini akan dijadikan konteks semua panggilan balik terkait Ajax.
Masalah umum: Menggunakan metode objek sebagai callback / event handler
Manifestasi umum lain dari masalah ini adalah ketika metode objek digunakan sebagai pemanggil balik / penangan kejadian. Fungsinya adalah warga negara kelas satu dalam JavaScript dan istilah "metode" hanyalah istilah sehari-hari untuk fungsi yang merupakan nilai properti objek. Tetapi fungsi itu tidak memiliki tautan spesifik ke objek "mengandung" nya.
Perhatikan contoh berikut:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
Fungsi this.methodditugaskan sebagai pengendali event klik, tetapi jika document.bodydiklik, nilai yang dicatat akan undefined, karena di dalam pengendali event, thismerujuk pada document.body, bukan instance dari Foo.
Seperti yang telah disebutkan di awal, apa yang thismerujuk tergantung pada bagaimana fungsi dipanggil , bukan bagaimana itu didefinisikan .
Jika kodenya seperti berikut ini, mungkin lebih jelas bahwa fungsi tersebut tidak memiliki referensi implisit ke objek:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
Solusinya sama dengan yang disebutkan di atas: Jika tersedia, gunakan .binduntuk secara eksplisit mengikat thiske nilai tertentu
document.body.onclick = this.method.bind(this);
atau secara eksplisit memanggil fungsi sebagai "metode" objek, dengan menggunakan fungsi anonim sebagai callback / event handler dan menetapkan objek ( this) ke variabel lain:
var self = this;
document.body.onclick = function() {
self.method();
};
atau gunakan fungsi panah:
document.body.onclick = () => this.method();