Apakah 'Fungsi Panah' dan 'Fungsi' setara / dapat dipertukarkan?
Fungsi panah di ES2015 memberikan sintaks yang lebih ringkas.
- Bisakah saya mengganti semua deklarasi / ekspresi fungsi saya dengan fungsi panah sekarang?
- Apa yang harus saya perhatikan?
Contoh:
Fungsi konstruktor
function User(name) {
this.name = name;
}
// vs
const User = name => {
this.name = name;
};
Metode prototipe
User.prototype.getName = function() {
return this.name;
};
// vs
User.prototype.getName = () => this.name;
Metode objek (literal)
const obj = {
getName: function() {
// ...
}
};
// vs
const obj = {
getName: () => {
// ...
}
};
Panggilan balik
setTimeout(function() {
// ...
}, 500);
// vs
setTimeout(() => {
// ...
}, 500);
Fungsi variadic
function sum() {
let args = [].slice.call(arguments);
// ...
}
// vs
const sum = (...args) => {
// ...
};
Jawaban
tl; dr: Tidak! Fungsi panah dan deklarasi / ekspresi fungsi tidak setara dan tidak dapat diganti secara membabi buta.
Jika fungsi yang ingin Anda ganti tidak digunakan this
, arguments
dan tidak dipanggil dengan new
, maka ya.
Seringkali: tergantung . Fungsi panah memiliki perilaku yang berbeda dengan deklarasi / ekspresi fungsi, jadi mari kita lihat perbedaannya terlebih dahulu:
1. Leksikal this
danarguments
Fungsi panah tidak memiliki this
atau arguments
mengikatnya sendiri . Sebaliknya, pengidentifikasi tersebut diselesaikan dalam lingkup leksikal seperti variabel lainnya. Itu berarti bahwa di dalam fungsi panah, this
dan arguments
merujuk ke nilai-nilai dari this
dan arguments
di lingkungan, fungsi panah didefinisikan (yaitu "di luar" fungsi panah):
// Example using a function expression
function createObject() {
console.log('Inside `createObject`:', this.foo);
return {
foo: 42,
bar: function() {
console.log('Inside `bar`:', this.foo);
},
};
}
createObject.call({foo: 21}).bar(); // override `this` inside createObject
// Example using a arrow function
function createObject() {
console.log('Inside `createObject`:', this.foo);
return {
foo: 42,
bar: () => console.log('Inside `bar`:', this.foo),
};
}
createObject.call({foo: 21}).bar(); // override `this` inside createObject
Dalam kasus ekspresi fungsi, this
mengacu pada objek yang dibuat di dalam createObject
. Dalam kasus panah fungsi, this
mengacu this
dari createObject
itu sendiri.
Ini membuat fungsi panah berguna jika Anda perlu mengakses this
lingkungan saat ini:
// currently common pattern
var that = this;
getData(function(data) {
that.data = data;
});
// better alternative with arrow functions
getData(data => {
this.data = data;
});
Perhatikan bahwa ini juga berarti bahwa tidak mungkin menyetel fungsi panah this
dengan .bind
atau .call
.
Jika Anda tidak terlalu paham this
, pertimbangkan untuk membaca
2. Fungsi panah tidak bisa dipanggil dengan new
ES2015 membedakan antara fungsi yang dipanggil dapat dan fungsi yang dapat dibangun . Jika suatu fungsi dapat dibangun, itu dapat dipanggil dengan new
, yaitu new User()
. Jika suatu fungsi dapat dipanggil, ia dapat dipanggil tanpa new
(yaitu panggilan fungsi normal).
Fungsi yang dibuat melalui deklarasi / ekspresi fungsi dapat dibangun dan dipanggil.
Fungsi panah (dan metode) hanya dapat dipanggil.
class
konstruktor hanya dapat dibangun.
Jika Anda mencoba memanggil fungsi yang tidak dapat dipanggil atau untuk membuat fungsi yang tidak dapat dibangun, Anda akan mendapatkan kesalahan waktu proses.
Mengetahui hal ini, kami dapat menyatakan yang berikut ini.
Tergantikan:
- Fungsi yang tidak menggunakan
this
atauarguments
. - Fungsi yang digunakan dengan
.bind(this)
Tidak dapat diganti:
- Fungsi konstruktor
- Fungsi / metode ditambahkan ke prototipe (karena biasanya digunakan
this
) - Fungsi variadic (jika digunakan
arguments
(lihat di bawah))
Mari kita lihat lebih dekat ini menggunakan contoh Anda:
Fungsi konstruktor
Ini tidak akan berfungsi karena fungsi panah tidak dapat dipanggil dengan new
. Tetap gunakan deklarasi / ekspresi fungsi atau gunakan class
.
Metode prototipe
Kemungkinan besar tidak, karena metode prototipe biasanya digunakan this
untuk mengakses instance. Jika tidak digunakan this
, maka Anda dapat menggantinya. Namun, jika Anda mengutamakan sintaks ringkas, gunakan class
dengan sintaks metode ringkasnya:
class User {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
Metode objek
Demikian pula untuk metode dalam suatu objek literal. Jika metode ingin mereferensikan objek itu sendiri melalui this
, tetap gunakan ekspresi fungsi, atau gunakan sintaks metode baru:
const obj = {
getName() {
// ...
},
};
Panggilan balik
Tergantung. Anda pasti harus menggantinya jika Anda menggunakan aliasing bagian luar this
atau menggunakan .bind(this)
:
// old
setTimeout(function() {
// ...
}.bind(this), 500);
// new
setTimeout(() => {
// ...
}, 500);
Tetapi: Jika kode yang memanggil callback secara eksplisit disetel this
ke nilai tertentu, seperti yang sering terjadi pada event handler, terutama dengan jQuery, dan callback menggunakan this
(atau arguments
), Anda tidak dapat menggunakan fungsi panah!
Fungsi variadic
Karena fungsi panah tidak memiliki fungsinya sendiri arguments
, Anda tidak bisa begitu saja menggantinya dengan fungsi panah. Namun, ES2015 memperkenalkan alternatif untuk menggunakan arguments
: parameter rest .
// old
function sum() {
let args = [].slice.call(arguments);
// ...
}
// new
const sum = (...args) => {
// ...
};
Pertanyaan terkait:
- Kapan saya harus menggunakan fungsi Panah di ECMAScript 6?
- Apakah fungsi panah ES6 memiliki argumennya sendiri atau tidak?
- Apa perbedaan (jika ada) antara fungsi panah ES6 dan fungsi yang terikat dengan Function.prototype.bind?
- Bagaimana cara menggunakan fungsi panah (bidang kelas publik) sebagai metode kelas?
Sumber lebih lanjut:
Fungsi panah => fitur ES6 terbaik sejauh ini. Mereka adalah tambahan yang sangat kuat untuk ES6, yang saya gunakan terus-menerus.
Tunggu, Anda tidak dapat menggunakan fungsi panah di mana pun dalam kode Anda, ini tidak akan berfungsi di semua kasus seperti di this
mana fungsi panah tidak dapat digunakan. Tanpa ragu, fungsi panah adalah tambahan yang bagus karena memberikan kesederhanaan kode.
Tetapi Anda tidak dapat menggunakan fungsi panah saat konteks dinamis diperlukan: mendefinisikan metode, membuat objek dengan konstruktor, mendapatkan target dari ini saat menangani peristiwa.
Fungsi panah TIDAK boleh digunakan karena:
Mereka tidak memiliki
this
Ini menggunakan "pelingkupan leksikal" untuk mencari tahu apa nilai "
this
" seharusnya. Sederhananya, lexical scoping menggunakan “this
” dari dalam tubuh fungsi.Mereka tidak memiliki
arguments
Fungsi panah tidak memiliki
arguments
objek. Tetapi fungsionalitas yang sama dapat dicapai dengan menggunakan parameter istirahat.let sum = (...args) => args.reduce((x, y) => x + y, 0)
sum(3, 3, 1) // output - 7
`Mereka tidak dapat digunakan dengan
new
Fungsi panah tidak bisa menjadi konstruktor karena tidak memiliki properti prototipe.
Kapan menggunakan fungsi panah dan kapan tidak:
- Jangan gunakan untuk menambahkan fungsi sebagai properti dalam literal objek karena kita tidak dapat mengaksesnya.
- Ekspresi fungsi paling baik untuk metode objek. Panah fungsi yang terbaik untuk callback atau metode seperti
map
,reduce
, atauforEach
. - Gunakan deklarasi fungsi untuk fungsi yang Anda panggil dengan nama (karena mereka diangkat).
- Gunakan fungsi panah untuk panggilan balik (karena cenderung lebih singkat).
Untuk menggunakan fungsi panah dengan function.prototype.call
, saya membuat fungsi pembantu pada prototipe objek:
// Using
// @func = function() {use this here} or This => {use This here}
using(func) {
return func.call(this, this);
}
pemakaian
var obj = {f:3, a:2}
.using(This => This.f + This.a) // 5
Edit
Anda tidak MEMBUTUHKAN pembantu. Anda bisa melakukan:
var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5