Jika Anda sudah lama memprogram menggunakan JavaScript, Anda pasti akan mengenali kata kunci ini. Ini telah membuatmu pusing berkali-kali.Dan sejak fungsi panah muncul di ES6, segalanya menjadi lebih rumit... atau lebih sederhana, tergantung bagaimana Anda melihatnya.
Dalam artikel ini kita akan melihat lebih dekat bagaimana cara kerjanya. Ini berlaku untuk fungsi tradisional dan fungsi panah.Mengapa terkadang fungsi panah (arrow function) menunjuk ke objek tertentu dan di lain waktu ke objek global, dan dalam situasi apa penggunaan fungsi panah masuk akal dan dalam situasi apa lebih baik untuk menghindarinya?
Apa tepatnya this dalam JavaScript
Kata yang dilindungi undang-undang this Ini merujuk pada konteks eksekusi. dari fungsi yang sedang dieksekusi. Tidak seperti bahasa pemrograman lain, di JavaScript keputusan tersebut tidak didasarkan pada di mana fungsi tersebut didefinisikan, melainkan pada eksekusi fungsi tersebut. cara memanggil.
Ini berarti bahwa fungsi yang sama dapat dipanggil dengan berbagai cara, dan dalam setiap cara tersebut, this dapat menunjuk ke objek yang berbedaIni bukan sesuatu yang bisa Anda ubah dengan penugasan langsung (Anda tidak bisa melakukan this = algo), tetapi Anda dapat memengaruhinya dengan mekanisme spesifik seperti call, apply y bind.
Selain itu, perilaku mereka bervariasi antara mode ketat dan mode tidak ketatDalam mode non-ketat, jika Anda memanggil fungsi "bare" (tanpa objek di depannya), this Biasanya itu adalah objek global (di browser, window), sedangkan dalam mode ketat bisa jadi undefinedPerbedaan ini penting ketika membandingkan contoh kode dari berbagai sumber.
Ini dalam konteks global dan dalam fungsi normal.
Di browser, ketika Anda tidak berada di dalam modul atau fungsi apa pun, konteks globalnya adalah objek tersebut. windowdan di sana this arahkan ke objek ituArtinya, jika Anda mengetikkan yang berikut ini ke dalam konsol:
console.log(this === window); // true en un entorno de navegador no estricto
Di dalam fungsi yang dideklarasikan dengan cara "klasik" (fungsi normal), nilai dari this Itu tergantung pada nama fungsi tersebut.Jika Anda memanggilnya tanpa objek sebelumnya, dalam mode non-ketat this Biasanya ini adalah yang berskala global, dan secara tegas memang akan demikian. undefinedItulah mengapa terkadang, saat memindahkan kode dari satu situs ke situs lain, Ini bukan lagi seperti yang Anda harapkan..
Ini dalam metode objek yang didefinisikan dengan fungsi normal.
Saat Anda mendefinisikan metode pada suatu objek menggunakan sintaks tradisional, this di dalam metode tersebut, referensi ke objek itu sendiri dari mana metode tersebut dipanggil.
Sebagai contoh, jika Anda memiliki sesuatu seperti:
const obj = {
speak() {
console.log(this);
}
};
obj.speak();
Panggilan obj.speak() membuat this dalam speak jadilah orangnya objInilah perilaku yang biasanya diharapkan orang secara intuitif: metode tersebut berbicara "atas nama" objek.
Jika Anda menggunakan fungsi klasik alih-alih sintaks yang disingkat, efeknya akan sama, karena Kuncinya terletak pada bagaimana metode tersebut dipanggil.Tidak masalah apakah Anda menggunakan singkatan metode atau kata kunci. function di dalam objek tersebut.
Ini dalam metode yang didefinisikan dengan fungsi panah
Segalanya berubah ketika Anda mendefinisikan metode dengan fungsi panah. Contohnya seperti ini:
const obj2 = {
speak: () => {
console.log(this);
}
};
obj2.speak();
Dalam hal ini, saat mengeksekusi obj2.speak() Anda akan melihat itu this Itu sudah tidak lagi obj2tetapi konteks leksikal eksternal ke objek tersebut, yang dalam skrip browser klasik biasanya adalah objek global. window.
Hal ini membingungkan saat pertama kali Anda melihatnya, karena Anda mengharapkan metode dari objek tersebut menunjuk ke objek itu sendiri. Namun, Fungsi panah tidak membuat fungsi panahnya sendiri. thisMereka mewarisi nilai dari this dari lingkup tempat mereka didefinisikan. Jika lingkup tersebut global, mereka mewarisi lingkup global; jika lingkupnya berbeda, mereka akan mewarisi lingkup yang lain.
Oleh karena itu, rekomendasi yang sering diulang dalam dokumentasi modern adalah: Jangan gunakan fungsi panah sebagai metode objek. saat Anda membutuhkannya this Arahkan ke objek itu.
Cakupan leksikal dari this fungsi panah
Perbedaan utama antara fungsi normal dan fungsi panah adalah bahwa yang terakhir memiliki tautan leksikal untuk thisSederhananya: mereka tidak memutuskan sendiri this bukan saat mereka saling menelepon, tetapi saat mereka membuat.
Bayangkan contoh ini:
const obj3 = {
speak() {
(() => {
console.log(this);
})();
}
};
obj3.speak();
Di sini mungkin tampak bahwa, seperti di dalam speak kita mengeksekusi fungsi panah, Ini seharusnya "diatur ulang" ke global.Namun justru kebalikannya yang terjadi: fungsi panah menangkap this dari fungsi yang mengelilinginyayang dalam hal ini adalah metodenya speak dipanggil sebagai obj3.speak()Oleh karena itu, nilai dari this Yang ditampilkan di konsol adalah yang berasal dari obj3.
Artinya, Fungsi panah tidak memiliki fungsi panahnya sendiri. thismelainkan menggunakan kembali apa yang ada di lingkungan sekitar mereka.Ini sangat berguna dalam callback bersarang, timer, promise, dan di mana pun, dengan fungsi klasik, Anda harus bergulat dengan .bind atau dengan trik seperti const that = this;.
Contoh praktis kehilangan dan pelestarian this
Salah satu masalah klasik dalam JavaScript adalah, ketika mendefinisikan fungsi di dalam sebuah metode, Anda kehilangan referensi ke this yang menunjuk ke objek tersebut dan Anda akhirnya mendapatkan yang global atau dengan undefined.
Mari kita ambil contoh kasus umum penggunaan setTimeout di dalam metode suatu objek dengan fungsi tradisional:
const persona = {
nombre: 'Agustin',
decirNombre: function() {
setTimeout(function() {
console.log(this.nombre);
}, 3000);
}
};
persona.decirNombre(); // Muestra undefined
Di sini ini di dalam fungsi yang diteruskan ke setTimeout Itu bukan lagi objeknya personaFungsi callback tersebut dieksekusi dalam konteks global (di browser, window), jadi this.nombre Kode tersebut mencoba membaca properti di variabel global, yang tidak ada, dan akhirnya menghasilkan kesalahan. undefined.
Sebelum fungsi panah ada, solusi umum adalah menyimpan nilai dari this dalam variabel 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);
}
};
Berkat variabel tersebut, referensi yang benar ke objek tetap terjaga. Namun, ini adalah trik yang agak kurang elegan dan berulang. Dengan fungsi panah (arrow function), masalah ini jauh lebih sederhana:
const persona = {
nombre: 'Agustin',
decirNombre: function() {
setTimeout(() => {
console.log(this.nombre);
}, 3000);
}
};
Di sini fungsi panah tidak menciptakan fungsi panahnya sendiri. this, jadi mewarisi this dari metode tersebut decirNombreyang merupakan objek personaHasilnya: “Agustin” ditampilkan dengan benar tanpa memerlukan variabel perantara atau .bind.
panggil, terapkan, dan ikat: mengontrol nilai dari this
Selain cara "alami" untuk menetapkan konteks dengan panggilan metode, JavaScript memberi kita alat untuk memaksa nilai dari this dalam fungsi normal: call, apply y bind.
Metode call() y apply() Mereka memanggil fungsi tersebut secara langsung, memungkinkan Anda untuk meneruskan objek yang ingin Anda gunakan sebagai this. Perbedaannya adalah itu call menerima argumen satu per satu, sementara apply Data tersebut diterima dalam bentuk array. bind(), sebaliknya, ia mengembalikan fungsi baru dengan this “terlampir” pada nilai yang telah Anda tunjukkanjadi kamu bisa menghubunginya nanti saat kamu merasa lebih nyaman.
Namun, dengan fungsi panah, metode ini tidak berguna untuk mengubah this karena nilainya terkait secara leksikal. Kamu bisa memakai call, apply o bind untuk meneruskan argumen, tetapi tidak untuk memodifikasi konteks fungsi panah, yang merupakan perbedaan yang sangat penting dengan fungsi biasa.
Sintaks dasar fungsi panah
Di luar perilaku thisFungsi panah menyediakan sintaksis yang lebih ringkas dan ekspresif untuk banyak situasi. Bentuk umumnya adalah:
(arg1, arg2, ..., argN) => expresion
Formulir ini secara otomatis mengembalikan hasil ekspresi di sebelah kanan tanda panah, jadi Tidak perlu menulis kata tersebut. return ketika Anda hanya memiliki satu ekspresi sederhana.
Beberapa poin sintaksis umum:
- Tanpa parameter:
() => 42atau bahkan_ => 42jika Anda tidak mempermasalahkan nama argumennya. - Dengan satu parameter:
Tanda kurung bersifat opsional; Anda dapat menulisx => x * 2o(x) => x * 2. - Dengan beberapa parameter:
Tanda kurung diperlukan:(x, y) => x + y.
Saat Anda membutuhkan beberapa pernyataan, Anda dapat menggunakan badan blok dengan kunci:
const sumar = (x, y) => {
const resultado = x + y;
return resultado;
};
Dalam hal ini, karena ada kunci, Tidak ada lagi pengembalian implisit.; jika Anda tidak memasukkan returnfungsi tersebut akan mengembalikan undefinedIni berlaku untuk fungsi panah maupun fungsi tradisional.
Mengembalikan objek literal dengan fungsi panah
Ada detail sintaksis kecil namun sangat umum: ketika fungsi panah mengembalikan sebuah objek literal secara langsungAnda harus mengapitnya dalam tanda kurung agar penerjemah tidak salah mengira itu sebagai blok.
Sebagai contoh:
x => ({ y: x })
Tanpa tanda kurung tersebut, JavaScript akan menginterpretasikan tanda kurung kurawal sebagai awal dari isi fungsi, bukan sebagai objek. Ini adalah trik sederhana, tetapi dapat menyebabkan banyak kesalahan konyol jika Anda melupakannya.
Fungsi panah: anonim dan tanpa prototipe
Fungsi panah adalah anonim secara sintaksisMereka tidak memiliki nama yang tepat, yang dapat sedikit mempersulit keadaan. pesan debug dan errorkarena dalam jejak (trace) Anda tidak melihat pengidentifikasi fungsi secara langsung, kecuali jika Anda telah menetapkannya ke konstanta dengan nama yang dapat dikenali.
Selain itu, fungsi panah Mereka tidak memiliki properti. prototype dan mereka tidak dapat digunakan sebagai perusahaan konstruksi.Jika Anda mencoba memanggil mereka dengan newAnda akan mendapatkan kesalahan. Untuk membuat objek menggunakan konstruktor atau kelas, Anda masih perlu menggunakan fungsi atau sintaksis biasa. class.
Konsekuensi lainnya adalah bahwa Pola-pola tersebut tidak cocok untuk pola yang memerlukan referensi internal diri sendiri., seperti beberapa bentuk rekursi atau penanganan kejadian yang perlu berhenti berlangganan menggunakan this atau nama fungsi itu sendiri.
Di sinilah fungsi panah bersinar.
Kekuatan utama dari fungsi panah justru terletak pada pengaitan leksikal dari thisFitur ini ideal dalam situasi di mana Anda ingin fungsi callback yang Anda berikan ke fungsi lain untuk mempertahankan this dari daerah sekitarnya.
Sebagai contoh, dalam sebuah objek dengan metode yang memulai timer dan perlu terus mengaksesnya. properti dari objek itu sendiri menggunakan this:
const contador = {
id: 42,
iniciar() {
setTimeout(() => {
console.log(this.id); // this es contador
}, 1000);
}
};
Di ES5, sudah umum untuk harus meletakkan .bind(this) ke fungsi callback atau simpan this pada variabel lain. Dengan fungsi panah, Kode menjadi lebih bersih dan lebih mendekati tujuan sebenarnya..
Mereka juga sangat praktis dengan metode array seperti map, filter, reduce dan perusahaan, karena mengurangi kebisingan sintaksis ketika logika fungsinya singkat:
const numeros = [1, 2, 3];
const dobles = numeros.map(n => n * 2);
Jika digunakan secukupnya, bentuk-bentuk yang ringkas ini membuat alur data lebih mudah diikuti sekilas.
Kapan harus menghindari fungsi panah?
Meskipun fungsi panah sangat berguna, fungsi tersebut bukanlah pengganti fungsi biasa. Ada beberapa kasus yang jelas di mana Sebaiknya jangan menggunakannya.:
- Metode objek yang bergantung pada
this:
Jika Anda mendefinisikan sebuah metode sebagaisaltos: () => { this.vidas--; }di dalam sebuah objekgato,thisIni tidak akan mengarah ke kucing, tetapi ke lingkungan luar, dan properti tersebut tidak akan diperbarui seperti yang Anda harapkan. - Fungsi callback event DOM yang dibutuhkan
thisdinamis:
Dalam penanganan sepertiboton.addEventListener('click', () => { this.classList.toggle('on'); });,thisBukan tombol yang ditekan, melainkan konteks yang lebih tinggi, yang kemungkinan besar akan menyebabkan kesalahan tipe. - Pembangun atau fungsi yang dibutuhkan
prototype:
Karena tidak dapat digunakan dengannewFungsi panah tidak cocok untuk membuat instance atau untuk pola berbasis prototipe.
Dalam semua kasus ini, sebuah Fungsi normal tetap menjadi alat yang tepat. karena hal itu memungkinkan this Hal ini terkait secara dinamis dengan cara Anda memanggil fungsi tersebut.
Jika Anda terbiasa secara sadar memilih antara fungsi normal dan fungsi panah tergantung pada apa yang Anda butuhkan. this dan dari konteksnya, Kode Anda akan lebih mudah diprediksi dan dibaca. untuk siapa pun yang menyimpannya setelahnya.
Pada akhirnya, memahami bagaimana nilai dari this dalam JavaScript, dan bagaimana fungsi panah mewarisi nilai tersebut. Kunci untuk berhenti kesulitan dengan hasil yang tidak terduga, memanfaatkan kemudahan sintaksis ES6, dan menulis metode, callback, dan event handler yang melakukan persis seperti yang Anda inginkan adalah memahami cakupan leksikal tempat semuanya dibuat.