Fungsi anak panah dan kata kunci ini dalam JavaScript

Kemaskini terakhir: 02/10/2026
Pengarang C SourceTrail
  • Fungsi anak panah menyediakan sintaks dan tangkapan yang ringkas this secara leksikal daripada skop sekelilingnya, dan bukannya mewujudkan ikatannya sendiri.
  • Nilai this dalam fungsi biasa bergantung pada bagaimana ia dipanggil, yang mempengaruhi fungsi, kaedah, pembina, kelas dan panggilan balik.
  • Fungsi anak panah sesuai untuk panggilan balik dan kaedah tatasusunan, tetapi merupakan pilihan yang buruk untuk kaedah objek, pengendali peristiwa DOM dan pembina.
  • Memahami bila this dinamik berbanding leksikal adalah penting untuk mengelakkan pepijat yang halus dan untuk memilih antara fungsi anak panah dan tradisional.

Fungsi anak panah dan ini dalam JavaScript

Jika anda pernah log masuk this dalam fungsi JavaScript yang berbeza dan mendapat hasil yang sangat berbeza, anda tidak keseorangan. Ramai pembangun menghadapi kes di mana kaedah mencetak objek yang dijangkakan, fungsi anak panah mencetak window, dan anak panah bersarang tiba-tiba "secara ajaib" menghala kembali ke objek di sekeliling. Memahami mengapa perkara itu berlaku adalah kunci untuk menulis kod yang boleh diramal dan bebas pepijat.

Fungsi anak panah dan this kata kunci membentuk salah satu kombinasi yang paling penting (dan disalahertikan) dalam JavaScript moden. Fungsi anak panah kelihatan seperti sintaks yang lebih pendek, tetapi di sebalik itu ia mengubah cara this dikendalikan, bagaimana panggilan balik bertindak, dan juga bila anda patut atau tidak patut menggunakannya sebagai kaedah. Mari kita lihat semuanya langkah demi langkah, daripada sintaks kepada konteks pelaksanaan, menggunakan bahasa Inggeris biasa dan banyak contoh praktikal.

Sintaks fungsi anak panah tanpa kekeliruan

Fungsi anak panah ialah ungkapan fungsi yang ditulis dengan => sintaks dan bukannya function kata kunci. Secara konseptual, anda boleh menganggapnya sebagai cara padat untuk menulis: "ambil parameter ini, nilaikan ungkapan atau blok kod ini dan kembalikan nilai." Di bawahnya, ia masih merupakan fungsi, tetapi ia bertindak berbeza dalam beberapa cara penting.

Fungsi anak panah yang paling asas memetakan terus kepada ungkapan fungsi biasa. Contohnya, ungkapan fungsi klasik ini:

const multiplyByTwo = function (value) { return value * 2; };

Boleh ditulis semula sebagai fungsi anak panah seperti ini:

const multiplyByTwo = (value) => { return value * 2; };

Fungsi anak panah menyerlah apabila badan merupakan satu ungkapan tunggal. Jika isi hanya satu pernyataan yang mengembalikan sesuatu, anda boleh menggugurkan kedua-dua kurung kurawal dan kurung eksplisit return, membolehkan pulangan tersirat:

const multiplyByTwo = value => value * 2;

Apabila terdapat tepat satu parameter, anda boleh meninggalkan kurungan di sekelilingnya, tetapi hanya dalam kes khusus itu. So x => x * 2 adalah sah, tetapi jika anda mempunyai sifar atau berbilang parameter, anda mesti menyimpan kurungan:

  • Parameter sifar: () => 42
  • Satu parameter: x => x * 2 or (x) => x * 2
  • Dua atau lebih parameter: (x, y) => x + y

Apabila anda memerlukan lebih daripada satu pernyataan dalam badan, anda mesti menggunakan kurung kurawal dan tanda eksplisit return. Dalam situasi itu, fungsi anak panah bertindak seperti fungsi biasa mengenai pulangan: tidak return, tiada nilai dikembalikan.

const feedCat = (status) => {
if (status === 'hungry') {
return 'Feed the cat';
} else {
return 'Do not feed the cat';
}
};

Berhati-hati semasa mengembalikan literal objek daripada fungsi anak panah, kerana pendakap objek boleh dikelirukan dengan badan fungsi. Untuk mengelakkan kekaburan itu, balut objek literal dalam kurungan supaya JavaScript tahu ia adalah ungkapan yang akan dikembalikan:

const toObject = value => ({ result: value });

Satu lagi perkara: fungsi anak panah sentiasa merupakan ungkapan, bukan sekali-kali pengisytiharan. Ini bermakna ia mesti diberikan kepada pembolehubah, sifat atau diluluskan sebagai argumen; ia tidak boleh berdiri sendiri seperti function myFunc() {}, dan ia tidak diangkat dengan cara yang sama seperti deklarasi fungsi, jadi anda tidak boleh memanggilnya sebelum ia ditakrifkan.

Apa sebenarnya this dalam JavaScript?

Kata kunci this ialah pengikatan dinamik yang dicipta oleh JavaScript untuk anda apabila ia melaksanakan fungsi atau kaedah kelas. Anda boleh menganggapnya sebagai parameter halimunan yang nilainya bergantung pada bagaimana dan di mana fungsi itu dipanggil. Ini menjadikannya berkuasa dan fleksibel, tetapi juga merupakan sumber kekeliruan yang besar.

Dalam fungsi yang tidak ketat, this sentiasa menyelesaikan kepada beberapa jenis objek; dalam mod ketat ia boleh menjadi sebarang nilai, termasuk undefined. JavaScript memutuskan nilai tersebut berdasarkan konteks pelaksanaan: fungsi biasa, panggilan kaedah, panggilan pembina, kelas, skop global atau fungsi anak panah.

Di peringkat atas skrip klasik (bukan modul), this merujuk kepada globalThis, yang biasanya merupakan pelayar window objek. Jadi perbandingan berikut dalam pelayar akan menjadi benar:

console.log(this === window); // true

Dalam fungsi yang bukan anak panah, this ditentukan sepenuhnya oleh tapak panggilan. Sekiranya anda menelefon obj.method(), kemudian di dalam method nilai this is objJika anda mengambil fungsi yang sama dan memanggilnya secara berasingan sebagai fn() dalam mod ketat, this menjadi undefined; dalam mod tidak ketat, JavaScript "menggantikan" this bersama globalThis.

Yang penting, apa yang penting bukanlah di mana fungsi itu ditakrifkan, tetapi bagaimana ia dipanggil. Kaedah boleh hidup pada rantaian prototaip atau ditugaskan semula kepada objek yang berbeza dan masih melihat this seperti apa sahaja objek yang sebenarnya digunakan pada masa panggilan. Menyampaikan kaedah sering mengubahnya this melainkan anda membetulkannya secara eksplisit.

Terdapat juga alat untuk mengawal this secara jelas: call, apply, bind, dan Reflect.apply. Ini membolehkan anda "menyuntik" yang dikehendaki this nilai: fn.call(obj, arg1, arg2) akan melaksanakan fn bersama this bersedia untuk objPeraturan penggantian yang sama terpakai dalam mod tidak ketat: jika anda lulus null or undefined as this, mereka digantikan dengan globalThis; primitif dimasukkan ke dalam objek pembalutnya.

Panggilan balik menambah satu lagi lapisan tipu daya, kerana this dikawal oleh sesiapa sahaja yang menghubungi panggilan balik anda. Kaedah lelaran tatasusunan, yang Promise pembina, dan API yang serupa biasanya memanggil panggilan balik dengan this bersedia untuk undefined (atau objek global dalam mod ceroboh). Sesetengah API, seperti Array.prototype.forEach or Set.prototype.forEach, terima yang berasingan thisArg parameter yang boleh anda gunakan untuk menetapkan panggilan balik this.

API lain sengaja memanggil panggilan balik dengan tersuai this nilai-nilai. Sebagai contoh, reviver hujah untuk JSON.parse dan juga replacer khususnya JSON.stringify menerima this terikat pada objek yang memiliki sifat yang sedang diproses. Pengendali peristiwa dalam DOM terikat pada elemen yang dilampirkan kepadanya apabila ditulis dengan cara "klasik".

Idea teras: fungsi anak panah tidak mencipta fungsinya sendiri this

Ciri yang menentukan fungsi anak panah ialah ia tidak pernah mencipta yang baharu this mengikat. Sebaliknya, mereka menutup (atau "menangkap") this daripada persekitaran leksikal sekitar pada saat ia dicipta. Apabila anak panah dilaksanakan kemudian, ia hanya menggunakan semula nilai yang ditangkap itu, tanpa mengira bagaimana anda memanggilnya.

Dalam praktiknya, fungsi anak panah bertindak seolah-olah ia terikat secara automatik secara kekal kepada this daripada skop luarannya. Inilah sebabnya mengapa kaedah seperti call, apply, dan bind tidak boleh berubah this untuk fungsi anak panah: thisArg argumen diabaikan begitu sahaja. Anda masih boleh menghantar parameter biasa melaluinya, tetapi this nilai dikunci.

Pertimbangkan coretan ini dalam skop global fail skrip:

const arrow = () => console.log(this);
arrow();

Oleh kerana anak panah ditakrifkan dalam kod global, ia this adalah global this (biasanya window dalam skrip pelayar), dan itu tidak pernah berubah. Memanggil arrow sebagai fungsi biasa, menugaskannya kepada sesuatu sifat, atau menyebarkannya akan sentiasa mencatat objek global yang sama apabila dipanggil dalam konteks ini.

Tingkah laku yang sangat menarik muncul apabila anda meletakkan fungsi anak panah di dalam fungsi atau kaedah biasa. Oleh kerana anak panah menangkap fungsi luar this, ia menjadi alat yang ampuh untuk panggilan balik yang perlu merujuk kembali kepada objek yang mengandunginya tanpa perkara biasa .bind(this) majlis.

const counter = {
id: 42,
start() {
setTimeout(() => {
console.log(this.id); // uses counter.id
}, 1000);
},
};

If start menggunakan fungsi tanpa nama tradisional di dalam setTimeout, anda perlu mengikat secara manual this atau simpannya ke pembolehubah. Dengan anak panah, panggilan balik secara semula jadi mewarisi this dari start, Yang merupakan counter, Jadi this.id cetakan 42 seperti yang dimaksudkan.

Pengikatan leksikal ini juga menjelaskan perkataan klasik "mengapa this soalan" perubahan apabila menggunakan anak panah dalam literal objek. Lihat dua objek ini:

const obj1 = {
speak() {
console.log(this);
}
};

const obj2 = {
speak: () => {
console.log(this);
}
};

Memanggil obj1.speak() cetakan obj1, Kerana speak merupakan kaedah yang biasa dan this ditetapkan berdasarkan tapak panggilan. Sebaliknya, obj2.speak() log bahagian luar this (selalunya window dalam pelayar), kerana anak panah tidak menggunakan objek tersebut sebagai thisObjek literal itu sendiri tidak mencipta yang baharu this skop; hanya badan fungsi yang melakukan itu, dan fungsi anak panah melangkau langkah itu.

Sekarang pertimbangkan kaedah objek yang mencipta dan segera memanggil anak panah dalaman:

const obj3 = {
speak() {
(() => {
console.log(this);
})();
}
};

obj3.speak();

Dalam situasi ini, fungsi anak panah dalam mewarisi this dari speak, Yang merupakan obj3 apabila dipanggil sebagai obj3.speak(). Walaupun anak panah merupakan fungsi bersarang yang dipanggil serta-merta, ia masih menunjukkan obj3, bukan objek global. Itulah intipati leksikal this: ia mengikuti skop sekeliling, bukan tapak panggilan anak panah itu sendiri.

this merentasi fungsi, objek dan pembina

Untuk benar-benar menguasai fungsi anak panah dan this, ia membantu untuk melihat bagaimana this berfungsi dalam setiap konteks utama: fungsi biasa, kaedah, pembina, kelas dan skop global. Sebaik sahaja peraturan tersebut jelas, tingkah laku anak panah lebih mudah untuk dipertimbangkan.

Dalam fungsi biasa (bukan anak panah), this bergantung 100% pada bagaimana fungsi itu dipanggil. Sekiranya anda menelefon fn() dalam mod ketat, this is undefined; dalam mod ceroboh, penggantian menjadikan this menjadi globalThisJika anda menghubungi obj.fn(), Maka this is obj. Bergerak fn kepada objek yang berbeza atau kepada pembolehubah dan nilai bagi this akan bergerak sewajarnya.

Dalam kaedah yang ditakrifkan pada objek literal, this ialah objek yang digunakan untuk mengakses kaedah, tidak semestinya objek di mana kaedah tersebut pada asalnya ditakrifkan. If obj.__proto__ memegang kaedah dan anda memanggil obj.method(), kemudian di dalam method, this is obj, bukan prototaip.

Pembina adalah satu lagi kes khas: apabila anda memanggil fungsi dengan new, this terikat pada contoh objek yang baru dicipta. Sebagai contoh, dalam function User(name) { this.name = name; }, memanggil new User('Alex') set this kepada yang baru User objek. Jika pembina secara eksplisit mengembalikan objek bukan primitif, objek yang dikembalikan itu akan menggantikan this sebagai nilai akhir bagi new ungkapan.

Sintaks kelas dibina berdasarkan peraturan ini dengan dua konteks utama: contoh dan statik. Di dalam pembina atau kaedah contoh, this menunjuk ke tika kelas yang anda sedang gunakan. Di dalam kaedah statik atau blok permulaan statik, this merujuk kepada kelas itu sendiri (atau kelas terbitan apabila dipanggil melalui pewarisan). Medan contoh dinilai dengan this terikat pada tika baharu; medan statik lihat this sebagai pembina kelas.

Pembina kelas terbitan bertindak sedikit berbeza: sehingga anda memanggil super(), tiada yang boleh digunakan this. Menyerang super() memulakan this dengan mendelegasikan kepada pembina asas; pengembalian sebelum melakukan itu dalam pembina terbitan hanya dibenarkan jika anda secara eksplisit mengembalikan objek yang berbeza.

Dalam konteks global, this bergantung pada bagaimana persekitaran JavaScript membungkus dan melaksanakan kod anda. Dalam skrip pelayar klasik, peringkat atasan this ialah objek global; dalam modul ES, peringkat atasan this sentiasa ada undefinedModul CommonJS Node.js dibungkus secara dalaman dan biasanya dilaksanakan dengan this bersedia untuk module.exportsAtribut pengendali peristiwa sebaris dalam HTML dilaksanakan dengan this ditetapkan pada elemen yang dilampirkan kepadanya.

Satu perincian yang halus tetapi penting: literal objek itu sendiri tidak memperkenalkan yang baharu this skop. Penulisan const obj = { value: this }; di dalam skrip akan membuat obj.value sama dengan bahagian luar this, bukan objek. Hanya badan fungsi (dan badan kelas) yang mencipta this pengikatan; anak panah sengaja melangkau langkah ini dan mewarisi.

Mengapa fungsi anak panah bagus untuk panggilan balik (dan apabila tidak)

Kerana anak panah berfungsi menutup this, ia sangat sesuai untuk banyak senario panggilan balik yang mana anda mahu panggilan balik terus merujuk kepada objek atau konteks di sekeliling. Ini amat berguna dengan pemasa, janji dan kaedah tatasusunan seperti map, filter, dan reduce.

Bayangkan satu kaedah yang perlu mengemas kini beberapa sifat berulang kali menggunakan setInterval. Menggunakan fungsi tradisional, this di dalam panggilan balik akan menjadi lalai kepada objek global (atau menjadi undefined dalam mod ketat), jadi this.count tidak akan menunjuk ke contoh anda. Dengan fungsi anak panah, panggilan balik secara semula jadi menggunakan this daripada kaedah luaran.

function Counter() {
this.count = 0;

setInterval(() => {
this.count++;
}, 1000);
}

Terima kasih kepada anak panah itu, this di dalam panggilan balik selang masa merujuk kepada Counter contohnya, bukan window. Jika panggilan balik itu merupakan fungsi biasa, anda sama ada perlu .bind(this) atau pembolehubah perantaraan seperti const self = this; untuk menyimpan rujukan tersebut.

Fungsi anak panah juga memudahkan kod menggunakan kaedah tatasusunan, di mana anda sering tidak peduli tentang this pada semua. Apabila anda lulus fungsi tradisional sebagai panggilan balik, fungsi tersirat this biasanya undefined, dan anda mungkin terlupa tentang itu. Anak panah menjadikannya jelas secara visual bahawa fungsi tersebut hanyalah pemetaan tulen antara input dan output.

const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);

Walau bagaimanapun, terdapat kes-kes penting di mana fungsi anak panah merupakan pilihan yang salah, terutamanya apabila anda memerlukan fungsi dinamik this. Dua anti-corak klasik menggunakan fungsi anak panah sebagai kaedah objek dan sebagai pengendali peristiwa DOM yang bergantung pada this menjadi elemen tersebut.

Pertimbangkan satu objek yang menjejaki kehidupan seekor kucing:

const cat = {
lives: 9,
jump: () => {
this.lives--; // bug: this is not cat
},
};

cat.jump();

Sejak jump ialah anak panah, this tidak merujuk kepada cat tetapi untuk apa sahaja this adalah tempat objek literal dicipta (selalunya objek global). Yang dimaksudkan this.lives-- sama ada melontar (dalam mod ketat) atau secara senyap-senyap mengubah sesuatu yang tidak berkaitan. Menggunakan sintaks kaedah biasa di sini adalah langkah yang betul.

Pendengar peristiwa DOM adalah serupa: corak standard this.classList.toggle('on') di dalam panggilan balik peristiwa bergantung pada this menjadi elemen yang mencetuskan peristiwa tersebut. Dengan fungsi anak panah, this tidak lagi menunjuk ke elemen, jadi kod tersebut rosak.

const button = document.getElementById('press');

button.addEventListener('click', () => {
this.classList.toggle('on'); // this is not button
});

Dalam situasi ini, pengendali haruslah berfungsi normal supaya this terikat oleh pelayar kepada elemen butang. Fungsi anak panah tidak berfungsi sebagai pengganti drop-in jika logik anda menjangkakan this untuk menjadi sasaran peristiwa dinamik.

Satu lagi kelemahan halus ialah fungsi anak panah secara sintaksisnya tanpa nama. Mereka biasanya tidak mempunyai nama mereka sendiri (selain daripada sebarang pembolehubah yang diberikan kepada mereka), yang boleh menjadikan jejak tindanan sedikit kurang deskriptif dan rekursi sedikit lebih rumit. Dalam kebanyakan kod dunia sebenar, itu adalah pertukaran yang boleh diurus, tetapi ia perlu diingat.

Kes khas: getter, setter, kaedah terikat dan sudut ganjil

Getter dan setter mengikuti peraturan "tapak panggilan" yang sama: this ialah objek yang diakses oleh harta tersebut, bukan objek di mana ia ditakrifkan pada asalnya. Jika getter diwarisi daripada prototaip dan anda memanggilnya pada objek terbitan, this di dalam getter merujuk kepada objek yang diperoleh.

Kaedah terikat yang dicipta dengan Function.prototype.bind memberikan anda tingkah laku yang agak serupa dengan fungsi anak panah, tetapi pada tahap fungsi normal. Semasa anda memanggil f.bind(obj), anda mencipta fungsi baharu yang this ditetapkan secara kekal kepada obj, tidak kira bagaimana ia dipanggil. Ini boleh berguna dalam kelas apabila anda perlu mengekalkan this walaupun sesuatu kaedah itu terpisah.

class Example {
constructor() {
this.handleClick = this.handleClick.bind(this);
}

handleClick() {
console.log(this); // always the instance
}
}

Kelemahan kedua-dua kaedah terikat dan fungsi anak panah yang digunakan sebagai medan contoh ialah setiap contoh mendapat salinan fungsinya sendiri, yang boleh meningkatkan penggunaan memori. Pertukaran ini biasanya boleh diterima apabila anda hanya mengikat sebilangan kecil kaedah yang kerap dipisahkan, tetapi ia adalah sesuatu yang perlu diberi perhatian dalam kod kritikal prestasi.

Terdapat juga beberapa kes sudut legasi di mana this berkelakuan berbeza, seperti dalam lingkungan yang tidak digunakan lagi with kenyataan. Di dalam a with (obj) { ... } blok, memanggil fungsi yang merupakan sifat bagi obj berkelakuan secara berkesan seolah-olah anda telah menulis obj.method(), Jadi this terikat dengan objKod moden harus dielakkan with, tetapi memahami pengecualian ini menjelaskan bahawa this masih bergantung pada bagaimana panggilan fungsi dibentuk.

Pengendali peristiwa sebaris dalam HTML juga mempunyai peraturan khas: kod pengendali sebaris di sekeliling melihat this sebagai elemen, tetapi fungsi dalaman yang ditakrifkan di dalam pengendali itu kembali kepada biasa this peraturan. Jadi fungsi tradisional dalaman, yang tidak terikat dengan apa-apa, biasanya akan melihat this as globalThis (Atau undefined dalam mod ketat), bukan elemen.

Akhir sekali, ingat bahawa fungsi anak panah tidak mempunyai prototype sifat dan tidak boleh digunakan sebagai pembina dengan new. Percubaan new MyArrow() akan melontarkan TypeError. Jika anda memerlukan fungsi yang boleh bertindak sebagai pembina, anda mesti menggunakan fungsi biasa atau kelas.

Dengan mengingati butiran ini, lebih mudah untuk memilih antara fungsi anak panah dan fungsi tradisional. Gunakan anak panah di tempat yang anda inginkan leksikal this dan sintaks yang ringkas, dan kembali kepada fungsi biasa apabila anda memerlukan fungsi dinamik, dipacu tapak panggilan this semantik tingkah laku atau pembina.

Sebaik sahaja anda menghayati bagaimana this terikat dalam setiap situasi, fungsi anak panah menjadi sekutu yang kuat dan bukannya sumber pepijat yang mengejutkan. Mereka menyelaraskan corak biasa seperti panggilan balik dan transformasi mudah, manakala fungsi biasa terus mengendalikan peranan yang bergantung pada peranan mereka sendiri this pengikatan, seperti kaedah, pembina dan pengendali peristiwa dinamik.

Related posts: