Sind 'Pfeilfunktionen' und 'Funktionen' gleichwertig / austauschbar?
Pfeilfunktionen in ES2015 bieten eine präzisere Syntax.
- Kann ich jetzt alle meine Funktionsdeklarationen / -ausdrücke durch Pfeilfunktionen ersetzen?
- Worauf muss ich achten?
Beispiele:
Konstruktorfunktion
function User(name) {
this.name = name;
}
// vs
const User = name => {
this.name = name;
};
Prototypmethoden
User.prototype.getName = function() {
return this.name;
};
// vs
User.prototype.getName = () => this.name;
Objektmethoden (Literalmethoden)
const obj = {
getName: function() {
// ...
}
};
// vs
const obj = {
getName: () => {
// ...
}
};
Rückrufe
setTimeout(function() {
// ...
}, 500);
// vs
setTimeout(() => {
// ...
}, 500);
Variadische Funktionen
function sum() {
let args = [].slice.call(arguments);
// ...
}
// vs
const sum = (...args) => {
// ...
};
Antworten
tl; dr: Nein! Pfeilfunktionen und Funktionsdeklarationen / -ausdrücke sind nicht äquivalent und können nicht blind ersetzt werden.
Wenn die Funktion, die Sie ersetzen möchten, nicht verwendet this
wird arguments
und nicht mit aufgerufen wird new
, dann ja.
Wie so oft: es kommt darauf an . Pfeilfunktionen haben ein anderes Verhalten als Funktionsdeklarationen / -ausdrücke. Schauen wir uns also zuerst die Unterschiede an:
1. Lexikalisch this
undarguments
Pfeilfunktionen haben keine eigene this
oder arguments
Bindung. Stattdessen werden diese Bezeichner wie jede andere Variable im lexikalischen Bereich aufgelöst. Das bedeutet, dass innerhalb einer Pfeilfunktion this
und unter arguments
Bezugnahme auf die Werte von this
und arguments
in der Umgebung die Pfeilfunktion definiert ist (dh "außerhalb" der Pfeilfunktion):
// 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
this
Bezieht sich im Fall des Funktionsausdrucks auf das Objekt, das innerhalb des Objekts erstellt wurde createObject
. In Pfeil Funktion Fall this
bezieht sich auf this
von createObject
selbst.
Dies macht Pfeilfunktionen nützlich, wenn Sie auf this
die aktuelle Umgebung zugreifen müssen :
// currently common pattern
var that = this;
getData(function(data) {
that.data = data;
});
// better alternative with arrow functions
getData(data => {
this.data = data;
});
Beachten Sie, dass dies auch bedeutet, dass es nicht möglich ist, eine Pfeilfunktion this
mit .bind
oder festzulegen .call
.
Wenn Sie nicht sehr vertraut sind this
, lesen Sie
2. Pfeilfunktionen können nicht mit aufgerufen werden new
ES2015 unterscheidet zwischen Funktionen, die aufrufbar sind , und Funktionen, die konstruierbar sind . Wenn eine Funktion konstruierbar ist, kann sie mit aufgerufen werden new
, d new User()
. H. Wenn eine Funktion aufrufbar ist, kann sie ohne aufgerufen werden new
(dh normaler Funktionsaufruf).
Durch Funktionsdeklarationen / -ausdrücke erstellte Funktionen sind sowohl konstruierbar als auch aufrufbar.
Pfeilfunktionen (und Methoden) können nur aufgerufen werden.
class
Konstruktoren sind nur konstruierbar.
Wenn Sie versuchen, eine nicht aufrufbare Funktion aufzurufen oder eine nicht aufbaubare Funktion zu erstellen, wird ein Laufzeitfehler angezeigt.
In diesem Wissen können wir Folgendes feststellen.
Austauschbar:
- Funktionen, die
this
oder nicht verwendenarguments
. - Funktionen, die mit verwendet werden
.bind(this)
Nicht austauschbar:
- Konstruktorfunktionen
- Funktion / Methoden, die einem Prototyp hinzugefügt wurden (weil sie normalerweise verwendet werden
this
) - Variadische Funktionen (falls verwendet
arguments
(siehe unten))
Schauen wir uns das anhand Ihrer Beispiele genauer an:
Konstruktorfunktion
Dies funktioniert nicht, da Pfeilfunktionen nicht mit aufgerufen werden können new
. Verwenden Sie weiterhin eine Funktionsdeklaration / einen Funktionsausdruck oder verwenden Sie class
.
Prototypmethoden
Höchstwahrscheinlich nicht, da Prototypmethoden normalerweise this
für den Zugriff auf die Instanz verwendet werden. Wenn sie nicht verwenden this
, können Sie es ersetzen. Wenn Sie sich jedoch hauptsächlich für eine prägnante Syntax interessieren, verwenden Sie diese class
mit ihrer prägnanten Methodensyntax:
class User {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
Objektmethoden
Ähnliches gilt für Methoden in einem Objektliteral. Wenn die Methode auf das Objekt selbst verweisen möchte this
, verwenden Sie weiterhin Funktionsausdrücke oder verwenden Sie die neue Methodensyntax:
const obj = {
getName() {
// ...
},
};
Rückrufe
Es hängt davon ab, ob. Sie sollten es auf jeden Fall ersetzen, wenn Sie das äußere Aliasing verwenden this
oder Folgendes verwenden .bind(this)
:
// old
setTimeout(function() {
// ...
}.bind(this), 500);
// new
setTimeout(() => {
// ...
}, 500);
Aber: Wenn der Code, der den Rückruf aufruft, explizit this
auf einen bestimmten Wert festgelegt wird, wie dies häufig bei Ereignishandlern, insbesondere bei jQuery, der Fall ist und der Rückruf this
(oder arguments
) verwendet, können Sie keine Pfeilfunktion verwenden !
Variadische Funktionen
Da Pfeilfunktionen keine eigenen haben arguments
, können Sie sie nicht einfach durch eine Pfeilfunktion ersetzen. ES2015 bietet jedoch eine Alternative zur Verwendung arguments
: den Parameter rest .
// old
function sum() {
let args = [].slice.call(arguments);
// ...
}
// new
const sum = (...args) => {
// ...
};
Verwandte Frage:
- Wann sollte ich Pfeilfunktionen in ECMAScript 6 verwenden?
- Haben ES6-Pfeilfunktionen ihre eigenen Argumente oder nicht?
- Was sind die Unterschiede (falls vorhanden) zwischen ES6-Pfeilfunktionen und Funktionen, die an Function.prototype.bind gebunden sind?
- Wie verwende ich Pfeilfunktionen (öffentliche Klassenfelder) als Klassenmethoden?
Weitere Ressourcen:
Pfeilfunktionen => bisher beste ES6-Funktion. Sie sind eine enorm leistungsstarke Ergänzung zu ES6, die ich ständig benutze.
Warten Sie, Sie können die Pfeilfunktion nicht überall in Ihrem Code verwenden. Sie funktioniert nicht in allen Fällen, in this
denen Pfeilfunktionen nicht verwendet werden können. Ohne Zweifel ist die Pfeilfunktion eine großartige Ergänzung, die Code-Einfachheit bringt.
Sie können jedoch keine Pfeilfunktion verwenden, wenn ein dynamischer Kontext erforderlich ist: Definieren von Methoden, Erstellen von Objekten mit Konstruktoren, Abrufen des Ziels beim Behandeln von Ereignissen.
Pfeilfunktionen sollten NICHT verwendet werden, weil:
Sie haben nicht
this
Es verwendet "lexikalisches Scoping", um herauszufinden, wie hoch der Wert von "
this
" sein sollte. In lexikalischem Scoping mit einfachen Worten wird "this
" aus dem Inneren des Funktionskörpers verwendet.Sie haben nicht
arguments
Pfeilfunktionen haben kein
arguments
Objekt. Die gleiche Funktionalität kann jedoch mit Ruheparametern erreicht werden.let sum = (...args) => args.reduce((x, y) => x + y, 0)
sum(3, 3, 1) // output - 7
`Sie können nicht mit verwendet werden
new
Pfeilfunktionen können keine Construtoren sein, da sie keine Prototyp-Eigenschaft haben.
Wann und wann nicht?
- Verwenden Sie diese Option nicht, um eine Funktion als Eigenschaft im Objektliteral hinzuzufügen, da wir nicht darauf zugreifen können.
- Funktionsausdrücke eignen sich am besten für Objektmethoden. Pfeil Funktionen sind am besten für Rückrufe oder Methoden wie
map
,reduce
oderforEach
. - Verwenden Sie Funktionsdeklarationen für Funktionen, die Sie beim Namen aufrufen möchten (weil sie hochgezogen sind).
- Verwenden Sie Pfeilfunktionen für Rückrufe (da diese tendenziell kürzer sind).
Um Pfeilfunktionen mit zu verwenden function.prototype.call
, habe ich eine Hilfsfunktion für den Objektprototyp erstellt:
// Using
// @func = function() {use this here} or This => {use This here}
using(func) {
return func.call(this, this);
}
Verwendung
var obj = {f:3, a:2}
.using(This => This.f + This.a) // 5
Bearbeiten
Du brauchst keinen Helfer. Du könntest es tun:
var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5