Jika anda telah lama mengaturcara dalam JavaScript, anda pasti akan mengenali kata kunci tersebut Ini telah memberi anda lebih daripada satu sakit kepalaDan memandangkan fungsi anak panah muncul dalam ES6, keadaan menjadi lebih rumit... atau lebih mudah, bergantung pada cara anda melihatnya.
Dalam artikel ini kita akan melihat dengan lebih dekat bagaimana ia berfungsi Ini terpakai kepada fungsi tradisional dan fungsi anak panah.Mengapakah ia kadangkala seolah-olah menunjuk kepada objek tertentu dan pada masa lain kepada objek global, dan dalam situasi apakah masuk akal untuk menggunakan fungsi anak panah dan dalam situasi apakah lebih baik untuk mengelakkannya?
Apa sebenarnya this dalam JavaScript
Perkataan terpelihara this Ia merujuk kepada konteks pelaksanaan fungsi yang sedang dilaksanakan. Tidak seperti bahasa lain, dalam JavaScript keputusan tidak berdasarkan di mana fungsi ditakrifkan, tetapi sebaliknya pada pelaksanaan fungsi. cara memanggil.
Ini bermakna fungsi yang sama boleh dipanggil dengan cara yang berbeza, dan dalam setiap satunya, this boleh menunjuk ke objek yang berbezaIa bukan sesuatu yang anda boleh ubah dengan tugasan langsung (anda tidak boleh lakukan this = algo), tetapi anda boleh mempengaruhinya dengan mekanisme tertentu seperti call, apply y bind.
Tambahan pula, tingkah laku mereka berbeza-beza antara mod ketat dan mod tidak ketatDalam mod tidak ketat, jika anda memanggil fungsi "bare" (tanpa objek di hadapannya), this Ia biasanya objek global (dalam pelayar, window), semasa dalam mod ketat ia boleh jadi undefinedPerbezaan ini penting apabila membandingkan contoh kod daripada sumber yang berbeza.
Ini dalam konteks global dan dalam fungsi normal
Dalam pelayar, apabila anda tidak berada di dalam mana-mana modul atau fungsi, konteks global ialah objek windowdan di sana this tunjukkan kepada objek ituIaitu, jika anda menaip yang berikut ke dalam konsol:
console.log(this === window); // true en un entorno de navegador no estricto
Dalam fungsi yang diisytiharkan dengan cara "klasik" (fungsi normal), nilai this Ia bergantung pada apa fungsi itu dipanggil.Jika anda memanggilnya tanpa objek terdahulu, dalam mod tidak ketat this Ia biasanya bersifat global, dan secara tepatnya ia akan menjadi undefinedItulah sebabnya kadangkala, apabila memindahkan kod dari satu laman web ke laman web yang lain, Ini bukan lagi apa yang anda harapkan..
Ini dalam kaedah objek yang ditakrifkan dengan fungsi normal
Apabila anda mentakrifkan kaedah pada objek menggunakan sintaks tradisional, this dalam kaedah, merujuk kepada objek itu sendiri dari mana kaedah itu telah digunakan.
Contohnya, jika anda mempunyai sesuatu seperti:
const obj = {
speak() {
console.log(this);
}
};
obj.speak();
Panggilan obj.speak() jenama this dalam speak jadilah satu-satunya objInilah tingkah laku yang biasanya dijangkakan oleh orang ramai secara intuitif: kaedah tersebut bercakap "bagi pihak" objek.
Jika anda menggunakan fungsi klasik dan bukannya sintaks yang disingkatkan, kesannya adalah sama, kerana Kuncinya terletak pada bagaimana kaedah itu digunakanTidak kira sama ada anda menggunakan singkatan kaedah atau kata kunci function di dalam objek tersebut.
Ini dalam kaedah yang ditakrifkan dengan fungsi anak panah
Keadaan berubah apabila anda mentakrifkan kaedah dengan fungsi anak panah. Sesuatu seperti:
const obj2 = {
speak: () => {
console.log(this);
}
};
obj2.speak();
Dalam kes ini, semasa melaksanakan obj2.speak() anda akan melihat itu this Ia tidak lagi obj2tetapi konteks leksikal luaran kepada objek itu, yang dalam skrip pelayar klasik biasanya merupakan objek global window.
Ini membingungkan pada kali pertama anda melihatnya, kerana anda menjangkakan kaedah objek itu akan menunjukkan objek itu sendiri. Walau bagaimanapun, fungsi anak panah tidak mencipta fungsinya sendiri thisMereka mewarisi nilai this skop tempat ia ditakrifkan. Jika skop itu global, mereka mewarisi skop global; jika ia adalah skop lain, mereka akan mewarisi skop lain itu.
Oleh itu, cadangan yang sering diulang dalam dokumentasi moden ialah: Jangan gunakan fungsi anak panah sebagai kaedah objek apabila anda perlu this sasarkan ke arah objek tersebut.
Skop leksikal bagi this fungsi anak panah
Perbezaan utama antara fungsi normal dan fungsi anak panah ialah fungsi anak panah mempunyai pautan leksikal untuk thisSecara ringkasnya: mereka tidak memutuskan apa yang mereka this bukan apabila mereka memanggil antara satu sama lain, tetapi apabila mereka buat.
Bayangkan contoh ini:
const obj3 = {
speak() {
(() => {
console.log(this);
})();
}
};
obj3.speak();
Di sini mungkin kelihatan bahawa, seperti dalam speak kita melaksanakan fungsi anak panah, Ini sepatutnya "ditetapkan semula" kepada globalTetapi sebaliknya berlaku: fungsi anak panah menangkap this fungsi yang mengelilinginyayang dalam kes ini adalah kaedah speak dipanggil sebagai obj3.speak()Oleh itu, nilai this Yang ditunjukkan pada konsol ialah yang dari obj3.
Maksud saya, fungsi anak panah tidak mempunyai fungsinya sendiri thistetapi sebaliknya menggunakan semula persekitaran terdekat merekaIni sangat berguna dalam panggilan balik bersarang, pemasa, janji dan di mana-mana sahaja di mana, dengan fungsi klasik, anda perlu bergelut dengannya .bind atau dengan helah seperti const that = this;.
Contoh praktikal kehilangan dan pemeliharaan this
Salah satu masalah klasik dalam JavaScript ialah, apabila mentakrifkan fungsi di dalam kaedah, anda kehilangan rujukan kepada this yang menunjuk ke arah objek dan anda berakhir dengan yang global atau dengan undefined.
Mari kita ambil kes biasa penggunaan setTimeout dalam kaedah objek dengan fungsi tradisional:
const persona = {
nombre: 'Agustin',
decirNombre: function() {
setTimeout(function() {
console.log(this.nombre);
}, 3000);
}
};
persona.decirNombre(); // Muestra undefined
di sini ini dalam fungsi yang diserahkan kepada setTimeout Ia bukan lagi objek personaFungsi panggil balik itu dilaksanakan dalam konteks global (dalam pelayar, window, begitu this.nombre Ia cuba membaca sifat dalam global, yang tidak wujud, dan akhirnya menjadi undefined.
Sebelum fungsi anak panah wujud, penyelesaian biasa adalah untuk menyimpan nilai this dalam pembolehubah bantu untuk "menyeretnya" ke dalam fungsi:
const persona = {
nombre: 'Agustin',
decirNombre: function() {
let that = this; // aquí this es persona
setTimeout(function() {
console.log(that.nombre);
}, 3000);
}
};
Terima kasih kepada pembolehubah itu, rujukan yang betul kepada objek dikekalkan. Tetapi ia merupakan helah yang agak hodoh dan berulang. Dengan fungsi anak panah, masalah ini dipermudahkan dengan ketara:
const persona = {
nombre: 'Agustin',
decirNombre: function() {
setTimeout(() => {
console.log(this.nombre);
}, 3000);
}
};
Di sini fungsi anak panah tidak mencipta fungsinya sendiri this, begitu mewarisi this kaedah tersebut decirNombreyang manakah objek itu personaHasilnya: “Agustin” dipaparkan dengan betul tanpa memerlukan pembolehubah perantaraan atau .bind.
panggil, guna dan ikat: mengawal nilai this
Selain cara "semula jadi" untuk menetapkan konteks dengan panggilan kaedah, JavaScript memberi kita alat untuk memaksa nilai this dalam fungsi biasa: call, apply y bind.
Kaedah call() y apply() Mereka akan menggunakan fungsi tersebut dengan segera, membolehkan anda menghantar objek yang anda ingin gunakan sebagai this. Perbezaannya ialah call menerima hujah satu persatu, manakala apply Mereka diterima dalam satu tatasusunan. bind(), sebaliknya, ia mengembalikan fungsi baharu dengan this "dilampirkan" pada nilai yang telah anda nyatakansupaya awak boleh hubungi dia nanti bila sesuai.
Walau bagaimanapun, dengan fungsi anak panah, kaedah ini tidak berguna untuk mengubah this kerana nilainya dikaitkan secara leksikal. Anda boleh menggunakan call, apply o bind untuk menyampaikan argumen, tetapi bukan untuk mengubah konteks fungsi anak panah, yang merupakan perbezaan yang sangat penting dengan fungsi biasa.
Sintaks asas fungsi anak panah
Di luar tingkah laku thisFungsi anak panah menyediakan sintaksis yang lebih padat dan ekspresif untuk pelbagai situasi. Bentuk amnya ialah:
(arg1, arg2, ..., argN) => expresion
Borang ini secara automatik mengembalikan hasil ungkapan di sebelah kanan anak panah, jadi Tidak perlu menulis perkataan itu return apabila anda hanya mempunyai satu ungkapan mudah.
Beberapa perkara umum sintaksis:
- Tanpa parameter:
() => 42atau bahkan_ => 42jika anda tidak peduli dengan nama argumen itu. - Dengan satu parameter:
Kurungan adalah pilihan; anda boleh menulisx => x * 2o(x) => x * 2. - Dengan berbilang parameter:
Kurungan diperlukan:(x, y) => x + y.
Apabila anda memerlukan berbilang pernyataan, anda boleh menggunakannya badan blok dengan kunci:
const sumar = (x, y) => {
const resultado = x + y;
return resultado;
};
Dalam kes ini, memandangkan terdapat kunci, Tiada lagi pulangan tersirat; jika anda tidak meletakkan returnfungsi tersebut akan kembali undefinedIni terpakai kepada kedua-dua fungsi anak panah dan fungsi tradisional.
Kembalikan objek literal dengan fungsi anak panah
Terdapat perincian sintaksis kecil tetapi sangat biasa: apabila fungsi anak panah mengembalikan objek literal secara langsungAnda mesti sertakannya dalam kurungan supaya penterjemah tidak tersilap menganggapnya sebagai blok.
Sebagai contoh:
x => ({ y: x })
Tanpa kurungan tersebut, JavaScript akan mentafsirkan kurungan kerinting sebagai permulaan badan fungsi, bukan sebagai objek. Ia adalah helah mudah, tetapi ia menyebabkan banyak kesilapan bodoh jika anda terlupa.
Fungsi anak panah: tanpa nama dan tanpa prototaip
Fungsi anak panah ialah tanpa nama secara sintaksisMereka tidak mempunyai nama yang tepat, yang boleh merumitkan sedikit sebanyak. mesej debug dan ralatkerana dalam jejak anda tidak melihat pengecam fungsi secara langsung, melainkan anda telah menetapkannya kepada pemalar dengan nama yang boleh dikenali.
Selain itu, anak panah berfungsi Mereka tidak memiliki harta prototype dan mereka tidak boleh digunakan sebagai syarikat pembinaanJika anda cuba memanggil mereka dengan newAnda akan mendapat ralat. Untuk mencipta objek menggunakan pembina atau kelas, anda masih perlu menggunakan fungsi atau sintaks biasa. class.
Akibat lain ialah Ia tidak sesuai untuk corak yang memerlukan rujukan kendiri dalaman, seperti beberapa bentuk rekursi atau pengendali peristiwa yang perlu berhenti melanggan sendiri menggunakan this atau nama fungsi itu sendiri.
Di mana fungsi anak panah bersinar
Kekuatan hebat fungsi anak panah terletak tepat pada perkaitan leksikal bagi thisIa sesuai dalam situasi di mana anda mahu panggilan balik anda serahkan kepada fungsi lain untuk mengekalkan this kawasan sekitarnya.
Contohnya, dalam objek dengan kaedah yang memulakan pemasa dan perlu terus mengakses sifat objek itu sendiri menggunakan this:
const contador = {
id: 42,
iniciar() {
setTimeout(() => {
console.log(this.id); // this es contador
}, 1000);
}
};
Dalam ES5, adalah perkara biasa untuk meletakkan .bind(this) ke panggilan balik atau simpan this dalam pembolehubah lain. Dengan fungsi anak panah, Kod menjadi lebih bersih dan lebih dekat dengan niat sebenar..
Ia juga sangat praktikal dengan kaedah tatasusunan seperti map, filter, reduce dan syarikat, kerana mengurangkan hingar sintaksis apabila logik fungsi adalah ringkas:
const numeros = [1, 2, 3];
const dobles = numeros.map(n => n * 2);
Apabila digunakan dengan berhati-hati, bentuk padat ini menjadikan aliran data lebih mudah untuk diikuti dengan pantas.
Bila hendak mengelakkan fungsi anak panah
Walaupun fungsi anak panah sangat berguna, ia bukanlah pengganti fungsi biasa. Terdapat beberapa kes yang jelas di mana Sebaiknya jangan gunakannya.:
- Kaedah objek yang bergantung kepada
this:
Jika anda mentakrifkan kaedah sebagaisaltos: () => { this.vidas--; }di dalam sesuatu objekgato,thisIa tidak akan menghala ke kucing, tetapi ke persekitaran luar, dan hartanah itu tidak akan dikemas kini seperti yang anda jangkakan. - Panggilan balik peristiwa DOM yang memerlukan
thisdinamik:
Dalam pengendali sepertiboton.addEventListener('click', () => { this.classList.toggle('on'); });,thisIa bukan butang yang ditekan, tetapi konteks yang lebih tinggi, yang mungkin akan memberi anda ralat jenis. - Pembina atau fungsi yang memerlukan
prototype:
Oleh kerana ia tidak boleh digunakan dengannewFungsi anak panah tidak sesuai untuk mencipta tika atau corak berasaskan prototaip.
Dalam semua kes ini, seorang Fungsi normal kekal sebagai alat yang sesuai kerana ia membenarkan perkara itu this Ia dikaitkan secara dinamik dengan cara anda menggunakan fungsi tersebut.
Jika anda terbiasa memilih secara sedar antara fungsi normal dan fungsi anak panah bergantung pada apa yang anda perlukan this dan dari konteksnya, Kod anda akan lebih mudah diramal dan dibaca. bagi sesiapa yang menyimpannya selepas itu.
Akhirnya, memahami bagaimana nilai this dalam JavaScript, dan bagaimana fungsi anak panah mewarisi nilai tersebut Kunci untuk berhenti bergelut dengan hasil yang tidak dijangka, memanfaatkan kecanggihan sintaksis ES6, dan kaedah penulisan, panggilan balik dan pengendali peristiwa yang melakukan apa yang anda fikirkan adalah memahami skop leksikal di mana ia dicipta.