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);
// ...
};
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
lubarguments
. - 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:
- kiedy należy używać funkcji strzałek w ECMAScript 6?
- czy funkcje strzałek ES6 mają swoje własne argumenty, czy nie?
- co? są różnicami (jeśli istnieją) między funkcjami strzałek ES6 a funkcjami związanymi z funkcją.prototyp.bind?
- jak używać strzałek ES6 w metodach klasowych?
Dalsze zasoby:
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
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.
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