Arrow function vs function declaration/ expressions: czy są równoważne / wymienne?

Canonical question Jeśli znajdziesz pytanie dotyczące problemów po zastąpieniu deklaracji / wyrażenia funkcji funkcją strzałki, zamknij je jako DUPLIKAT tej.

Funkcje strzałek w ES2015 zapewniają bardziej zwięzłą składnię. Czy mogę teraz zastąpić wszystkie deklaracje / wyrażenia funkcji funkcjami strzałek? Na co mam uważać?

Przykłady:

Funkcja konstruktora

function User(name) {
  this.name = name;
}

// vs

const User = name => {
  this.name = name;
};

Prototyp metody

User.prototype.getName = function() {
  return this.name;
};

// vs

User.prototype.getName = () => this.name;

Metody obiektowe (dosłowne)

const obj = {
  getName: function() {
    // ...
  }
};

// vs

const obj = {
  getName: () => {
    // ...
  }
};

Callbacks

setTimeout(function() {
  // ...
}, 500);

// vs

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

Funkcje wariacyjne

function sum() {
  let args = [].slice(arguments);
  // ...
}

// vs
const sum = () => {
  let args = [].slice(arguments);
  // ...
};
Author: Felix Kling, 2015-12-18

2 answers

Tl; dr: Nie! funkcje strzałek i deklaracje / wyrażenia funkcji nie są równoważne i nie można ich zastąpić na ślepo.
Jeśli funkcja, którą chcesz zastąpić, Nie , użyj this, arguments i nie jest wywoływana przez new, to tak.


Jak często: To zależy . Funkcje strzałek mają inne zachowanie niż deklaracje / wyrażenia funkcji, więc spójrzmy najpierw na różnice:

1. Leksykalne this i arguments

Funkcje strzałek nie mają własnych wiązań this lub arguments. Zamiast tego identyfikatory te są rozwiązywane w zakresie leksykalnym, jak każda inna zmienna. Oznacza to, że wewnątrz funkcji strzałki, this i arguments odnoszą się do wartości this i arguments w środowisku funkcja strzałki jest zdefiniowana W (tzn. "na zewnątrz" funkcji strzałki):

// 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

W przypadku wyrażenia funkcji, this odnosi się do obiekt, który został utworzony wewnątrz createObject. W przypadku funkcji strzałki, this odnosi się do this z createObject.

To sprawia, że funkcje strzałek są przydatne, jeśli potrzebujesz dostępu do this bieżącego środowiska:

// currently common pattern
var that = this;
getData(function(data) {
  that.data = data;
});

// better alternative with arrow functions
getData(data => {
  this.data = data;
});

Zauważ, że oznacza to również, że nie można ustawić funkcji strzałki this za pomocą .bind lub .call.

Jeśli nie jesteś zaznajomiony z this, rozważ przeczytanie

2. Funkcji strzałek nie można wywoływać za pomocą new

ES2015 rozróżnia funkcje, które są call able i funkcje, które są construct able. Jeśli funkcja jest konstruktywna, można ją wywołać za pomocą new, tzn. new User(). Jeśli funkcja jest wywoływalna, może być wywołana bez new (tj. normalnego wywołania funkcji).

Funkcje utworzone za pomocą funkcji deklaracje / wyrażenia są zarówno konstruktywne, jak i wywołalne.
Funkcje strzałek (i metody) można wywoływać tylko. class konstruktory są tylko konstruktywne.

Jeśli próbujesz wywołać funkcję, której nie można wywołać lub skonstruować funkcję, której nie można zbudować, pojawi się błąd runtime.


Wiedząc o tym, możemy stwierdzić, co następuje.

  • funkcje, które nie używają this lub arguments.
  • funkcje, które są używane z .bind(this)

Nie : {]}

  • funkcje konstruktora
  • funkcja / metody dodane do prototypu (ponieważ zwykle używają this)
  • Funkcje Zmienne (jeśli używają arguments (patrz niżej))

Przyjrzyjmy się temu bliżej, używając Twoich przykładów:

Funkcja konstruktora

To nie zadziała, ponieważ funkcje strzałek nie mogą być wywoływane przez new. Używanie deklaracji funkcji / wyrażenie lub użycie class.

Metody prototypowe

Najprawdopodobniej nie, ponieważ metody prototypowe zwykle używają this, aby uzyskać dostęp do instancji. Jeśli nie użyją this, możesz go zastąpić. Jeśli jednak zależy Ci przede wszystkim na zwięzłej składni, użyj class ze składnią zwięzłej metody:

class User {
  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}

Metody obiektowe

Podobnie dla metod w dosłownym obiekcie. Jeśli metoda chce odwoływać się do samego obiektu poprzez this, należy używać funkcji wyrażenia, lub użyć składni nowej metody:

const obj = {
  getName() {
    // ...
  },
};

Callbacks

To zależy. Zdecydowanie powinieneś go zastąpić, jeśli aliasujesz zewnętrzną this lub używasz .bind(this):
// old
setTimeout(function() {
  // ...
}.bind(this), 500);

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

Ale: jeśli kod wywołujący wywołanie zwrotne jawnie ustawia this na określoną wartość, jak to często ma miejsce w programach obsługi zdarzeń, zwłaszcza w jQuery, a wywołanie zwrotne używa this (lub arguments), nie można użyć strzałki funkcja!

Funkcje Zmienne

Ponieważ funkcje strzałek nie mają własnych arguments, nie można ich po prostu zastąpić funkcją strzałki. Jednak ES2015 wprowadza alternatywę dla użycia arguments: parametr rest .

// old
function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// new
const sum = (...args) => {
  // ...
};

Podobne pytanie:

Dalsze zasoby:

 410
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53

Zobacz przykład Plnkr

Zmienna this jest bardzo różna timesCalled zwiększa się tylko o 1 za każdym razem, gdy przycisk jest wywołany. Który odpowiada na moje osobiste pytanie:

.click( () => { } )

I

.click(function() { })

oba tworzą tę samą liczbę funkcji, gdy są używane w pętli, jak widać z GUID count w Plnkr.

 2
Author: jmb.mage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-12 14:01:19