Saya memiliki fungsi konstruktor yang mendaftarkan pengendali acara:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', function () {
alert(this.data);
});
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
Namun, saya tidak dapat mengakses data
properti objek yang dibuat di dalam callback. Sepertinya this
tidak merujuk ke objek yang dibuat tetapi ke yang lain.
Saya juga mencoba menggunakan metode objek alih-alih fungsi anonim:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', this.alert);
}
MyConstructor.prototype.alert = function() {
alert(this.name);
};
tapi itu menunjukkan masalah yang sama.
Bagaimana saya bisa mengakses objek yang benar?
javascript
callback
this
Felix Kling
sumber
sumber
Jawaban:
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:Untuk mempelajari lebih lanjut
this
, lihat dokumentasi MDN .Cara merujuk ke yang benar
this
Jangan gunakan
this
Anda sebenarnya tidak ingin mengakses
this
secara 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 adalahself
danthat
.Karena
self
merupakan variabel normal, ia mematuhi aturan lingkup leksikal dan dapat diakses di dalam callback. Ini juga memiliki keuntungan bahwa Anda dapat mengaksesthis
nilai dari panggilan balik itu sendiri.Atur
this
panggilan balik secara eksplisit - bagian 1Mungkin terlihat seperti Anda tidak memiliki kontrol atas nilai
this
karena nilainya diatur secara otomatis, tetapi sebenarnya tidak demikian.Setiap fungsi memiliki metode
.bind
[docs] , yang mengembalikan fungsi baru yangthis
terikat ke suatu nilai. Fungsi ini memiliki perilaku yang persis sama dengan yang Anda panggil.bind
, hanya ituthis
yang Anda tetapkan. Tidak peduli bagaimana atau kapan fungsi itu dipanggil,this
akan selalu merujuk pada nilai yang diteruskan.Dalam hal ini, kami mengikat panggilan balik
this
ke nilaiMyConstructor
'sthis
.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: Gunakan fungsi panah
ECMAScript 6 memperkenalkan fungsi panah , yang dapat dianggap sebagai fungsi lambda. Mereka tidak memiliki
this
ikatan sendiri . Sebaliknya,this
dilihat 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.Set
this
panggilan balik - bagian 2Beberapa fungsi / metode yang menerima panggilan balik juga menerima nilai yang menjadi
this
acuan 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:Argumen pertama adalah callback dan argumen kedua adalah nilai yang
this
harus dirujuk. Berikut adalah contoh yang dibuat-buat:Catatan: Apakah Anda dapat memberikan nilai atau tidak
this
biasanya disebutkan dalam dokumentasi fungsi / metode tersebut. Misalnya, metode jQuery [docs]$.ajax
menjelaskan opsi yang disebutcontext
: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:
Fungsi
this.method
ditugaskan sebagai pengendali event klik, tetapi jikadocument.body
diklik, nilai yang dicatat akanundefined
, karena di dalam pengendali event,this
merujuk padadocument.body
, bukan instance dariFoo
.Seperti yang telah disebutkan di awal, apa yang
this
merujuk 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:
Solusinya sama dengan yang disebutkan di atas: Jika tersedia, gunakan
.bind
untuk secara eksplisit mengikatthis
ke nilai tertentuatau secara eksplisit memanggil fungsi sebagai "metode" objek, dengan menggunakan fungsi anonim sebagai callback / event handler dan menetapkan objek (
this
) ke variabel lain:atau gunakan fungsi panah:
sumber
self
danthat
merujukthis
. Saya merasakan hal ini karenathis
merupakan variabel kelebihan beban yang digunakan dalam konteks yang berbeda; sedangkanself
biasanya sesuai dengan instance lokal danthat
biasanya merujuk ke objek lain. Saya tahu Anda tidak menetapkan aturan ini, seperti yang saya lihat muncul di beberapa tempat lain, tetapi juga mengapa saya mulai menggunakan_this
, tetapi saya tidak yakin bagaimana perasaan orang lain, kecuali untuk praktik yang tidak seragam yang telah menghasilkan.Function.prototype.call ()
danFunction.prototype.apply ()
. Terutama denganapply ()
saya mendapatkan banyak jarak tempuh. Saya kurang cenderung untuk menggunakanbind ()
mungkin hanya karena kebiasaan meskipun saya sadar (tetapi tidak yakin) bahwa mungkin ada sedikit kelebihan biaya overhead untuk menggunakan bind atas opsi lain.() => this.clicked()
;)Berikut adalah beberapa cara untuk mengakses konteks orang tua di dalam konteks anak -
bind()
fungsi.1. Gunakan
bind()
fungsiJika Anda menggunakan
underscore.js
- http://underscorejs.org/#bind2 Simpan referensi ke konteks / ini di dalam variabel lain
3 Fungsi panah
sumber
Semuanya dalam sintaks "ajaib" memanggil metode:
Ketika Anda mendapatkan properti dari objek dan memanggilnya dalam sekali jalan, objek akan menjadi konteks untuk metode ini. Jika Anda memanggil metode yang sama, tetapi dalam langkah-langkah terpisah, konteksnya adalah ruang lingkup global (jendela) sebagai gantinya:
Ketika Anda mendapatkan referensi metode, itu tidak lagi melekat pada objek, itu hanya referensi ke fungsi polos. Hal yang sama terjadi ketika Anda mendapatkan referensi untuk digunakan sebagai panggilan balik:
Di situlah Anda akan mengikat konteks ke fungsi:
Jika Anda menggunakan jQuery, Anda harus menggunakan
$.proxy
metode ini, karenabind
tidak didukung di semua browser:sumber
Masalah dengan "konteks"
Istilah "konteks" kadang-kadang digunakan untuk merujuk ke objek yang dirujuk oleh ini . Penggunaannya tidak tepat karena tidak cocok baik secara semantik maupun teknis dengan ECMAScript's ini .
"Konteks" berarti keadaan di sekitar sesuatu yang menambah makna, atau informasi sebelumnya dan berikut yang memberikan makna tambahan. Istilah "konteks" digunakan dalam ECMAScript untuk merujuk ke konteks eksekusi , yang merupakan semua parameter, cakupan, dan ini dalam lingkup beberapa kode pelaksana.
Ini ditunjukkan dalam ECMA-262 bagian 10.4.2 :
yang jelas menunjukkan bahwa ini adalah bagian dari konteks eksekusi.
Konteks eksekusi memberikan informasi di sekitarnya yang menambahkan makna pada kode yang sedang dieksekusi. Ini mencakup lebih banyak informasi dari pada sekadar Binding ini .
Jadi nilai ini bukan "konteks", itu hanya satu bagian dari konteks eksekusi. Ini pada dasarnya variabel lokal yang dapat diatur oleh panggilan ke objek apa pun dan dalam mode ketat, ke nilai apa pun.
sumber
this
tetapi tidak ada yang ditawarkan di sini, dan ini sudah terlambat untuk menutup pintu pada "konteks".Anda harus tahu tentang kata kunci "ini".
Sesuai pandangan saya Anda dapat menerapkan "ini" dalam tiga cara (fungsi Self / Arrow / Metode Bind)
Fungsi kata kunci ini berperilaku sedikit berbeda dalam JavaScript dibandingkan dengan bahasa lain.
Ini juga memiliki beberapa perbedaan antara mode ketat dan mode non-ketat.
Dalam kebanyakan kasus, nilai ini ditentukan oleh bagaimana suatu fungsi dipanggil.
Itu tidak dapat diatur oleh tugas selama eksekusi, dan mungkin berbeda setiap kali fungsi dipanggil.
ES5 memperkenalkan metode bind () untuk mengatur nilai fungsi ini terlepas dari bagaimana namanya,
dan ES2015 memperkenalkan fungsi panah yang tidak menyediakan pengikatannya sendiri (ini mempertahankan nilai konteks leksikal terlampir ini).
Metode 1: Self - Self digunakan untuk mempertahankan referensi ke aslinya bahkan ketika konteksnya sedang berubah. Ini adalah teknik yang sering digunakan dalam event handler (terutama pada penutupan).
Referensi : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Metode2 : Fungsi panah - Ekspresi fungsi panah adalah alternatif yang ringkas secara sintaksis untuk ekspresi fungsi biasa,
meskipun tanpa ikatan sendiri dengan ini, argumen, kata kunci super, atau new.target.
Ekspresi fungsi panah tidak cocok sebagai metode, dan mereka tidak dapat digunakan sebagai konstruktor.
Referensi : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Method3 : Bind- The bind () method menciptakan fungsi baru yang,
ketika dipanggil, kata kunci ini disetel ke nilai yang disediakan,
dengan urutan argumen tertentu sebelum diberikan ketika fungsi baru dipanggil.
Referensi: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
sumber
Pertama, Anda harus memiliki pemahaman
scope
dan perilakuthis
kata kunci yang jelas dalam konteksscope
.this
&scope
:singkatnya, lingkup global mengacu pada objek jendela. Variabel yang dideklarasikan dalam lingkup global dapat diakses dari mana saja. Di lain pihak, ruang lingkup fungsi berada di dalam suatu fungsi. Variabel yang dideklarasikan di dalam suatu fungsi tidak dapat diakses dari dunia luar secara normal.
this
kata kunci dalam lingkup global mengacu pada objek jendela.this
fungsi dalam juga merujuk ke objek jendela. Jadithis
akan selalu merujuk ke jendela sampai kita menemukan cara untuk memanipulasithis
untuk menunjukkan konteks yang kita pilih sendiri.Berbagai cara untuk memanipulasi
this
fungsi panggilan balik di dalam:Di sini saya memiliki fungsi konstruktor bernama Person. Ia memiliki sifat yang disebut
name
dan empat metode yang disebutsayNameVersion1
,sayNameVersion2
,sayNameVersion3
,sayNameVersion4
. Keempatnya memiliki satu tugas khusus. Terima panggilan balik dan aktifkan panggilan itu. Panggilan balik memiliki tugas khusus yaitu mencatat properti nama dari instance fungsi konstruktor Person.Sekarang mari kita membuat instance dari person constructor dan memanggil versi yang berbeda dari
sayNameVersionX
(X merujuk ke 1,2,3,4) metode denganniceCallback
untuk melihat berapa banyak cara kita dapat memanipulasithis
callback dalam untuk merujuk keperson
instance.mengikat:
Apa yang mengikat lakukan adalah membuat fungsi baru dengan
this
kata kunci diatur ke nilai yang disediakan.sayNameVersion1
dansayNameVersion2
gunakan bind untuk memanipulasithis
fungsi callback.yang pertama mengikat
this
dengan callback di dalam metode itu sendiri. Dan untuk yang kedua callback dilewatkan dengan objek terikat padanya.hubungi:
The
first argument
daricall
metode yang digunakan sebagaithis
dalam fungsi yang dipanggil dengancall
melekat padanya.sayNameVersion3
gunakancall
untuk memanipulasithis
untuk merujuk ke objek orang yang kita buat, bukan objek jendela.dan itu disebut seperti berikut:
menerapkan :
Mirip dengan
call
, argumen pertamaapply
merujuk pada objek yang akan ditunjukkan olehthis
kata kunci.sayNameVersion4
gunakanapply
untuk memanipulasithis
untuk merujuk ke objek orangdan itu disebut seperti berikut ini. Hanya panggilan balik yang dilewati,
sumber
Kami tidak dapat mengikat ini
setTimeout()
, karena selalu dijalankan dengan objek global (Jendela) , jika Anda ingin mengaksesthis
konteks dalam fungsi panggilan balik maka dengan menggunakanbind()
ke fungsi panggilan balik kita dapat mencapai sebagai:sumber
Pertanyaannya berkisar bagaimana
this
perilaku kata kunci dalam javascript.this
berperilaku berbeda seperti di bawah ini,this
biasanya ditentukan oleh konteks eksekusi fungsi.this
mengacu pada objek global (window
objek).this
akanundefined
seperti dalam mode ketat, objek global mengacuundefined
pada tempatwindow
objek.call()
,bind()
, danapply()
new
kata kunci digunakan (konstruktor), ini terikat ke objek baru yang sedang dibuat.this
- sebagai gantinya,this
terikat secara leksikal (yaitu berdasarkan pada konteks asli)Seperti yang disarankan sebagian besar jawaban, kita dapat menggunakan fungsi Panah atau
bind()
Metode atau var Diri . Saya akan mengutip poin tentang lambdas (fungsi Panah) dari Panduan Gaya JavaScript GoogleGoogle jelas merekomendasikan untuk menggunakan lambdas daripada mengikat atau
const self = this
Jadi solusi terbaik adalah dengan menggunakan lambdas seperti di bawah ini,
Referensi:
sumber
this
kata kunci itulah sebabnya saya membagi jawaban saya menjadi dua bagian, satu tentangthis
dan kedua tentang menggunakan fungsi / metode sebagai panggilan balik. Jangan ragu untuk mengedit jawabannya.Saat ini ada pendekatan lain yang mungkin jika kelas digunakan dalam kode.
Dengan dukungan bidang kelas dimungkinkan untuk membuatnya dengan cara berikutnya:
Pasti di bawah tenda itu semua fungsi panah baik tua yang mengikat konteks tetapi dalam bentuk ini terlihat jauh lebih jelas bahwa pengikatan eksplisit.
Karena itu Proposal Tahap 3 Anda akan memerlukan babel dan plugin babel yang sesuai untuk memprosesnya seperti untuk saat ini (08/2018).
sumber
public methodName = (params) => { body }
di dalam kelas.Pendekatan lain, yang merupakan cara standar sejak DOM2 untuk mengikat
this
dalam pendengar acara, yang memungkinkan Anda selalu menghapus pendengar (di antara manfaat lainnya), adalahhandleEvent(evt)
metode dariEventListener
antarmuka:Informasi terperinci tentang penggunaan
handleEvent
dapat ditemukan di sini: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38sumber
this
dalam JS:Nilai
this
dalam JS adalah 100% ditentukan oleh bagaimana suatu fungsi dipanggil, dan bukan bagaimana itu didefinisikan. Kita dapat dengan relatif mudah menemukan nilaithis
oleh 'left of the dot rule' :this
adalah objek yang tersisa dari titik fungsi yang disebutthis
di dalam suatu fungsi sering merupakan objek global (global
dalam node,window
di browser). Saya tidak akan merekomendasikan menggunakanthis
kata kunci di sini karena kurang eksplisit daripada menggunakan sesuatu sepertiwindow
!Function.prototype.bind()
fungsi yang dapat memperbaiki nilaithis
. Ini adalah pengecualian dari aturan tetapi sangat membantu untuk memperbaiki nilaithis
.Contoh dalam nodeJS
Keluaran:
Biarkan saya memandu Anda melalui output 1 oleh 1 (mengabaikan log pertama mulai dari yang kedua):
this
adalahobj2
karena di sebelah kiri titik aturan, kita dapat melihat bagaimanatest1
disebutobj2.test1();
.obj2
yang tersisa dari titik dan dengan demikianthis
nilainya.obj2
dibiarkan di titik,test2
terikatobj1
melaluibind()
metode. Jadithis
nilainyaobj1
.obj2
yang tersisa dari dot dari fungsi yang disebut:obj2.test3()
. Karena ituobj2
akan menjadi nilaithis
.obj2.test4()
obj2
berada di sebelah kiri titik. Namun fungsi panah tidak memilikithis
ikatan sendiri . Oleh karena itu akan mengikatthis
nilai lingkup luar yang merupakanmodule.exports
objek yang dicatat di awal.this
dengan menggunakancall
fungsi. Di sini kita dapat memberikan nilai yang diinginkanthis
sebagai argumen, yangobj2
dalam hal ini.sumber