Apakah 'Fungsi Panah' dan 'Fungsi' setara / dapat dipertukarkan?

Dec 19 2015

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

817 FelixKling Dec 19 2015 at 00:58

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, argumentsdan 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 thisdanarguments

Fungsi panah tidak memiliki thisatau argumentsmengikatnya sendiri . Sebaliknya, pengidentifikasi tersebut diselesaikan dalam lingkup leksikal seperti variabel lainnya. Itu berarti bahwa di dalam fungsi panah, thisdan argumentsmerujuk ke nilai-nilai dari thisdan argumentsdi 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, thismengacu pada objek yang dibuat di dalam createObject. Dalam kasus panah fungsi, thismengacu thisdari createObjectitu sendiri.

Ini membuat fungsi panah berguna jika Anda perlu mengakses thislingkungan 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 thisdengan .bindatau .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. classkonstruktor 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 thisatau arguments.
  • 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 thisuntuk mengakses instance. Jika tidak digunakan this, maka Anda dapat menggantinya. Namun, jika Anda mengutamakan sintaks ringkas, gunakan classdengan 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 thisatau menggunakan .bind(this):

// old
setTimeout(function() {
  // ...
}.bind(this), 500);

// new
setTimeout(() => {
  // ...
}, 500);

Tetapi: Jika kode yang memanggil callback secara eksplisit disetel thiske 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:

Sumber lebih lanjut:

17 Ashutosh Jan 10 2020 at 03:22

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 thismana 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:

  1. Mereka tidak memiliki this

    Ini menggunakan "pelingkupan leksikal" untuk mencari tahu apa nilai " this" seharusnya. Sederhananya, lexical scoping menggunakan “ this” dari dalam tubuh fungsi.

  2. Mereka tidak memiliki arguments

    Fungsi panah tidak memiliki argumentsobjek. 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 `

  3. Mereka tidak dapat digunakan dengan new

    Fungsi panah tidak bisa menjadi konstruktor karena tidak memiliki properti prototipe.

Kapan menggunakan fungsi panah dan kapan tidak:

  1. Jangan gunakan untuk menambahkan fungsi sebagai properti dalam literal objek karena kita tidak dapat mengaksesnya.
  2. Ekspresi fungsi paling baik untuk metode objek. Panah fungsi yang terbaik untuk callback atau metode seperti map, reduce, atau forEach.
  3. Gunakan deklarasi fungsi untuk fungsi yang Anda panggil dengan nama (karena mereka diangkat).
  4. Gunakan fungsi panah untuk panggilan balik (karena cenderung lebih singkat).
2 toddmo May 16 2020 at 08:56

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