Czy „Funkcje strzałek” i „Funkcje” są równoważne / wymienne?
Funkcje strzałek w ES2015 zapewniają bardziej zwięzłą składnię.
- Czy mogę teraz zastąpić wszystkie deklaracje / wyrażenia funkcji funkcjami strzałkowymi?
- Na co mam uważać?
Przykłady:
Funkcja konstruktora
function User(name) {
this.name = name;
}
// vs
const User = name => {
this.name = name;
};
Metody prototypowe
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: () => {
// ...
}
};
Callback
setTimeout(function() {
// ...
}, 500);
// vs
setTimeout(() => {
// ...
}, 500);
Funkcje wariadyczne
function sum() {
let args = [].slice.call(arguments);
// ...
}
// vs
const sum = (...args) => {
// ...
};
Odpowiedzi
tl; dr: Nie! Funkcje strzałkowe i deklaracje / wyrażenia funkcji nie są równoważne i nie można ich zastąpić ślepo.
Jeśli funkcja chcesz zastąpić ma nie używać this
, arguments
a nie jest wywołana new
, to tak.
Jak to często bywa: to zależy . Funkcje strzałkowe zachowują się inaczej niż deklaracje / wyrażenia funkcji, więc najpierw spójrzmy na różnice:
1. Leksykalne this
iarguments
Funkcje strzałkowe nie mają własnego this
ani arguments
powiązania. Zamiast tego te identyfikatory są rozwiązywane w zakresie leksykalnym, jak każda inna zmienna. Oznacza to, że wewnątrz funkcji strzałkowej this
i arguments
odnoszą się do wartości this
oraz arguments
w środowisku funkcja strzałkowa jest zdefiniowana w (tj. „Na zewnątrz” funkcji strzałkowej):
// 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 obiektu, który został utworzony wewnątrz createObject
. W przypadku funkcji strzałki, this
odnosi się this
od createObject
siebie.
Dzięki temu funkcje strzałek są przydatne, jeśli chcesz uzyskać dostęp this
do 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łek za this
pomocą .bind
lub .call
.
Jeśli nie jesteś zbyt zaznajomiony this
, rozważ przeczytanie
2. Funkcje strzałkowe nie mogą być wywoływane za pomocą new
ES2015 rozróżnia funkcje, które można wywoływać i funkcje, które można konstruować . Jeśli funkcję można konstruować, można ją wywołać za pomocą new
, np new User()
. Jeśli funkcja jest wywoływalna, można ją wywołać bez new
(tj. Normalne wywołanie funkcji).
Funkcje utworzone za pomocą deklaracji / wyrażeń funkcji są zarówno konstruowalne, jak i wywoływalne.
Funkcje (i metody) strzałek można wywołać tylko.
class
konstruktorów można tylko konstruować.
Jeśli próbujesz wywołać funkcję, której nie można wywołać lub skonstruować funkcję, której nie można skonstruować, pojawi się błąd w czasie wykonywania.
Wiedząc o tym, możemy stwierdzić, co następuje.
Wymienny:
- Funkcje, które nie używają
this
lubarguments
. - Funkcje używane z platformami
.bind(this)
Nie wymienny:
- Funkcje konstruktora
- Funkcja / metody dodane do prototypu (ponieważ zwykle używają
this
) - Funkcje wariadyczne (jeśli używają
arguments
(patrz poniżej))
Przyjrzyjmy się temu bliżej na przykładach:
Funkcja konstruktora
To nie zadziała, ponieważ nie można wywołać funkcji strzałkowych new
. Nadal używaj deklaracji / wyrażenia funkcji lub użyj class
.
Metody prototypowe
Najprawdopodobniej nie, ponieważ metody prototypowe zwykle używają this
do uzyskania dostępu do instancji. Jeśli nie używają this
, możesz go wymienić. Jeśli jednak zależy Ci przede wszystkim na zwięzłej składni, użyj class
jej zwięzłej składni metody:
class User {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
Metody obiektowe
Podobnie dla metod w literale obiektu. Jeśli metoda chce odwołać się do samego obiektu za pośrednictwem this
, nadal używaj wyrażeń funkcyjnych lub użyj nowej składni metody:
const obj = {
getName() {
// ...
},
};
Callback
To zależy. Zdecydowanie powinieneś go wymienić, jeśli używasz aliasingu zewnętrznego this
lub używasz .bind(this)
:
// old
setTimeout(function() {
// ...
}.bind(this), 500);
// new
setTimeout(() => {
// ...
}, 500);
Ale: Jeśli kod, który wywołuje wywołanie zwrotne, jawnie ustawia this
określoną wartość, jak to często ma miejsce w przypadku programów obsługi zdarzeń, szczególnie w przypadku jQuery, a wywołanie zwrotne używa this
(lub arguments
), nie można użyć funkcji strzałki!
Funkcje wariadyczne
Ponieważ funkcje strzałkowe nie mają własnych arguments
, nie można ich po prostu zastąpić funkcją strzałkową. Jednak ES2015 wprowadza alternatywę użycia arguments
: parametr rest .
// old
function sum() {
let args = [].slice.call(arguments);
// ...
}
// new
const sum = (...args) => {
// ...
};
Powiązane pytanie:
- Kiedy należy używać funkcji strzałek w ECMAScript 6?
- Czy funkcje strzałkowe ES6 mają własne argumenty, czy nie?
- Jakie są różnice (jeśli w ogóle) między funkcjami strzałkowymi ES6 a funkcjami powiązanymi z Function.prototype.bind?
- Jak używać funkcji strzałkowych (publicznych pól klas) jako metod klasowych?
Dalsze zasoby:
Funkcje strzałek => najlepsza jak dotąd funkcja ES6. Są niesamowicie potężnym dodatkiem do ES6, z którego stale korzystam.
Czekaj, nie możesz używać funkcji strzałkowej wszędzie w kodzie, nie będzie ona działać we wszystkich przypadkach, takich jak this
tam, gdzie funkcje strzałkowe nie będą użyteczne. Bez wątpienia funkcja strzałki jest świetnym dodatkiem, który upraszcza kod.
Ale nie możesz użyć funkcji strzałki, gdy wymagany jest dynamiczny kontekst: definiowanie metod, tworzenie obiektów za pomocą konstruktorów, pobieranie celu podczas obsługi zdarzeń.
Funkcje strzałkowe NIE powinny być używane, ponieważ:
Oni nie mają
this
Używa „leksykalnego zakresu”, aby dowiedzieć się, jaka
this
powinna być wartość „ ”. W prostym słowie zakres leksykalny wykorzystuje „this
” z wnętrza ciała funkcji.Oni nie mają
arguments
Funkcje strzałkowe nie mają
arguments
obiektu. Ale tę samą funkcjonalność można osiągnąć za pomocą parametrów odpoczynku.let sum = (...args) => args.reduce((x, y) => x + y, 0)
sum(3, 3, 1) // output - 7
`Nie można ich używać z
new
Funkcje strzałkowe nie mogą być konstruktorami, ponieważ nie mają właściwości prototypu.
Kiedy używać funkcji strzałek, a kiedy nie:
- Nie używaj funkcji dodawania funkcji jako właściwości w literale obiektu, ponieważ nie mamy do niej dostępu.
- Wyrażenia funkcyjne są najlepsze dla metod obiektowych. Strzałka funkcje są najlepsze dla wywołania zwrotne lub metod, takich jak
map
,reduce
lubforEach
. - Użyj deklaracji funkcji dla funkcji, które chcesz wywołać według nazwy (ponieważ są one podniesione).
- Użyj funkcji strzałek do wywołań zwrotnych (ponieważ są one zwykle bardziej zwięzłe).
Aby używać funkcji strzałkowych function.prototype.call
, utworzyłem funkcję pomocniczą na prototypie obiektu:
// Using
// @func = function() {use this here} or This => {use This here}
using(func) {
return func.call(this, this);
}
stosowanie
var obj = {f:3, a:2}
.using(This => This.f + This.a) // 5
Edytować
NIE POTRZEBUJESZ pomocnika. Mógłbyś:
var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5