Die Frage richtet sich an Personen, die im Rahmen des kommenden ECMAScript 6 (Harmony) über den Codestil nachgedacht haben und bereits mit der Sprache gearbeitet haben.
Mit () => {}
und erhalten function () {}
wir zwei sehr ähnliche Möglichkeiten, um Funktionen in ES6 zu schreiben. In anderen Sprachen zeichnen sich Lambda-Funktionen häufig durch Anonymität aus, in ECMAScript kann jedoch jede Funktion anonym sein. Jeder der beiden Typen hat eindeutige Verwendungsdomänen (nämlich wenn this
entweder explizit gebunden werden muss oder explizit nicht gebunden werden muss). Zwischen diesen Domänen gibt es eine große Anzahl von Fällen, in denen eine der beiden Notationen ausreicht.
Pfeilfunktionen in ES6 haben mindestens zwei Einschränkungen:
- Arbeiten Sie nicht mit
new
und können beim Erstellen nicht verwendet werdenprototype
- Feste
this
gebunden Umfang bei der Initialisierung
Abgesehen von diesen beiden Einschränkungen könnten Pfeilfunktionen reguläre Funktionen theoretisch fast überall ersetzen. Was ist der richtige Ansatz, um sie in der Praxis anzuwenden? Sollten Pfeilfunktionen verwendet werden, z.
- "Überall, wo sie funktionieren", dh überall, wo eine Funktion nicht agnostisch gegenüber der
this
Variablen sein muss und wir kein Objekt erstellen. - nur "überall dort, wo sie gebraucht werden", dh Ereignis-Listener, Timeouts, die an einen bestimmten Bereich gebunden sein müssen
- mit 'kurzen' Funktionen, aber nicht mit 'langen' Funktionen
- Nur mit Funktionen, die keine weitere Pfeilfunktion enthalten
Was ich suche, ist eine Richtlinie zur Auswahl der geeigneten Funktionsnotation in der zukünftigen Version von ECMAScript. Die Richtlinie muss klar sein, damit sie Entwicklern in einem Team beigebracht werden kann, und konsistent sein, damit kein ständiges Umgestalten von einer Funktionsnotation zur anderen erforderlich ist.
quelle
Fixed this bound to scope at initialisation
als Einschränkung?this
etwas ist, was Sie mit regulären Funktionen tun können, aber nicht mit Pfeilfunktionen.Fixed this bound to scope at initialisation
eine Einschränkung ist. :) Schauen Sie sich diesen Artikel an: exploringjs.com/es6/ch_arrow-functions.htmlAntworten:
Vor einiger Zeit hat unser Team den gesamten Code (eine mittelgroße AngularJS-App) auf JavaScript migriert, das mit
TraceurBabel kompiliert wurde . Ich verwende jetzt die folgende Faustregel für Funktionen in ES6 und darüber hinaus:function
im globalen Bereich und fürObject.prototype
Eigenschaften.class
für Objektkonstruktoren.=>
überall sonst.Warum fast überall Pfeilfunktionen verwenden?
thisObject
wie die Wurzel verwendet. Wenn auch nur ein einzelner Standardfunktionsrückruf mit einer Reihe von Pfeilfunktionen gemischt wird, besteht die Möglichkeit, dass der Bereich durcheinander gerät.function
sticht jeder Reguläre sofort hervor, um den Umfang zu definieren. Ein Entwickler kann immer die nächsthöherefunction
Anweisung nachschlagen, um zu sehen, was diethisObject
ist.Warum immer reguläre Funktionen im globalen Bereich oder im Modulbereich verwenden?
thisObject
.window
Objekt (globaler Bereich) wird am besten explizit angesprochen.Object.prototype
Definitionen leben im globalen Bereich (denkenString.prototype.truncate
usw.) und diese müssen im Allgemeinenfunction
sowieso vom Typ sein. Die konsequente Verwendungfunction
des globalen Bereichs hilft, Fehler zu vermeiden.function foo(){}
alsconst foo = () => {}
- insbesondere außerhalb anderer Funktionsaufrufe. (2) Der Funktionsname wird in Stapelspuren angezeigt. Während es mühsam wäre, jeden internen Rückruf zu benennen, ist es wahrscheinlich eine gute Idee, alle öffentlichen Funktionen zu benennen.Objektkonstruktoren
Der Versuch, eine Pfeilfunktion zu instanziieren, löst eine Ausnahme aus:
Ein wesentlicher Vorteil von Funktionen gegenüber Pfeilfunktionen besteht daher darin, dass Funktionen als Objektkonstruktoren fungieren:
Die funktionsidentische 2 ES Harmony- Entwurfsklassendefinition ist jedoch fast genauso kompakt:
Ich gehe davon aus, dass von der Verwendung der früheren Notation irgendwann abgeraten wird. Die Objektkonstruktornotation kann von einigen weiterhin für einfache anonyme Objektfabriken verwendet werden, in denen Objekte programmgesteuert generiert werden, aber nicht für viele andere.
Wenn ein Objektkonstruktor benötigt wird, sollte in Betracht gezogen werden, die Funktion
class
wie oben gezeigt in eine zu konvertieren . Die Syntax funktioniert auch mit anonymen Funktionen / Klassen.Lesbarkeit der Pfeilfunktionen
Das wahrscheinlich beste Argument für das Festhalten an regulären Funktionen - verdammt noch mal die Sicherheit des Oszilloskops - wäre, dass Pfeilfunktionen weniger lesbar sind als reguläre Funktionen. Wenn Ihr Code überhaupt nicht funktioniert, scheinen Pfeilfunktionen möglicherweise nicht erforderlich zu sein, und wenn Pfeilfunktionen nicht konsistent verwendet werden, sehen sie hässlich aus.
ECMAScript hat sich seit ECMAScript 5.1 erheblich verändert
Array.forEach
,Array.map
und all diese funktionalen Programmierfunktionen verwenden Funktionen, bei denen zuvor for-Schleifen verwendet worden wären. Asynchrones JavaScript hat sich ziemlich stark verbessert. ES6 wird auch einPromise
Objekt versenden , was noch mehr anonyme Funktionen bedeutet. Für die funktionale Programmierung gibt es kein Zurück. In funktionalem JavaScript sind Pfeilfunktionen regulären Funktionen vorzuziehen.Nehmen Sie zum Beispiel diesen (besonders verwirrenden) Teil von Code 3 :
Der gleiche Code mit regulären Funktionen:
Während jede der Pfeilfunktionen durch eine Standardfunktion ersetzt werden kann, wäre davon nur sehr wenig zu profitieren. Welche Version ist besser lesbar? Ich würde den ersten sagen.
Ich denke, die Frage, ob Pfeilfunktionen oder reguläre Funktionen verwendet werden sollen, wird mit der Zeit weniger relevant. Die meisten Funktionen werden entweder zu Klassenmethoden, die das
function
Schlüsselwort entfernen , oder sie werden zu Klassen. Funktionen werden weiterhin zum Patchen von Klassen über das verwendetObject.prototype
. In der Zwischenzeit schlage ich vor, dasfunction
Schlüsselwort für alles zu reservieren, was eigentlich eine Klassenmethode oder eine Klasse sein sollte.Anmerkungen
extend
Schlüsselwort nicht verwendet . Ein kleiner Unterschied besteht darin, dass Klassendeklarationen Konstanten sind, Funktionsdeklarationen jedoch nicht.quelle
function
ist, wenn Sie nichtthis
gebunden werden möchten , oder? Mein häufigstes Szenario hierfür sind Ereignisse, bei denen Sie möglicherweisethis
auf das Objekt (normalerweise den DOM-Knoten) verweisen möchten , das das Ereignis ausgelöst hat.=>
sieht es mit der Zeit besser aus. Ich bezweifle, dass Nicht-Programmierer die beiden Beispiele sehr unterschiedlich sehen würden. Wenn Sie ES2016-Code schreiben, werden Sie normalerweise auch nicht so viele Pfeilfunktionen verwenden. In diesem Beispiel würden Sie bei Verwendung von async / await und einem Array-Verständnis nur eine Pfeilfunktion imreduce()
Aufruf erhalten.Dem Vorschlag zufolge zielten Pfeile darauf ab, "mehrere häufig auftretende Probleme zu lösen und zu lösen
Function Expression
". Sie wollten die Sache verbessern, indem siethis
lexikalisch binden und eine knappe Syntax bieten.Jedoch,
this
lexikalisch bindenDaher können Pfeilfunktionen zu Verwirrung und Fehlern führen und sollten aus dem Vokabular eines JavaScript-Programmierers ausgeschlossen und durch
function
ausschließlich ersetzt werden.In Bezug auf lexikalische
this
this
ist problematisch:Mit den Pfeilfunktionen soll das Problem behoben werden, bei dem auf eine Eigenschaft
this
innerhalb eines Rückrufs zugegriffen werden muss. Dazu gibt es bereits mehrere Möglichkeiten: Sie könnenthis
einer Variablen zuweisen ,bind
das dritte Argument verwenden oder verwenden, das für dieArray
Aggregatmethoden verfügbar ist . Pfeile scheinen jedoch die einfachste Problemumgehung zu sein, sodass die Methode folgendermaßen überarbeitet werden könnte:Überlegen Sie jedoch, ob der Code eine Bibliothek wie jQuery verwendet, deren Methoden
this
speziell gebunden sind . Nun gibt es zweithis
Werte, mit denen man sich befassen muss:Wir müssen verwenden ,
function
umeach
zu bindenthis
dynamisch. Wir können hier keine Pfeilfunktion verwenden.Der Umgang mit mehreren
this
Werten kann auch verwirrend sein, da es schwierig ist zu wissen, über wasthis
ein Autor gesprochen hat:Wollte der Autor tatsächlich anrufen
Book.prototype.reformat
? Oder hat er vergessen zu bindenthis
und beabsichtigt anzurufenReader.prototype.reformat
? Wenn wir den Handler in eine Pfeilfunktion ändern, werden wir uns ebenfalls fragen, ob der Autor die Dynamik wolltethis
, aber einen Pfeil gewählt hat, weil er in eine Zeile passt:Man könnte sagen: "Ist es außergewöhnlich, dass Pfeile manchmal die falsche Funktion sind? Wenn wir nur selten dynamische
this
Werte benötigen , ist es immer noch in Ordnung, die meiste Zeit Pfeile zu verwenden."Aber fragen Sie sich Folgendes: "Wäre es 'wert', Code zu debuggen und festzustellen, dass das Ergebnis eines Fehlers durch einen 'Randfall' verursacht wurde?" Ich würde es vorziehen, Probleme nicht nur die meiste Zeit zu vermeiden, sondern 100% der Zeit.
Es gibt einen besseren Weg: Immer verwenden
function
(this
kann also immer dynamisch gebunden werden) und immerthis
über eine Variable referenzieren . Variablen sind lexikalisch und nehmen viele Namen an. Das Zuweisenthis
zu einer Variablen macht Ihre Absichten klar:Darüber hinaus wird durch die ständige Zuweisung
this
zu einer Variablen (auch wenn eine einzelnethis
oder keine andere Funktion vorhanden ist) sichergestellt, dass die eigenen Absichten auch nach einer Änderung des Codes klar bleiben.Auch Dynamik
this
ist kaum außergewöhnlich. jQuery wird auf über 50 Millionen Websites verwendet (Stand: Februar 2016). Hier sind andere APIs, diethis
dynamisch binden :this
.this
.this
.EventTarget
withthis
.this
.(Statistiken über http://trends.builtwith.com/javascript/jQuery und https://www.npmjs.com .)
Sie benötigen wahrscheinlich
this
bereits dynamische Bindungen.Ein Lexikon
this
wird manchmal erwartet, aber manchmal nicht; so wie eine Dynamikthis
manchmal erwartet wird, aber manchmal nicht. Zum Glück gibt es einen besseren Weg, der immer die erwartete Bindung erzeugt und kommuniziert.In Bezug auf die knappe Syntax
Pfeilfunktionen haben es geschafft, eine "kürzere syntaktische Form" für Funktionen bereitzustellen. Aber werden diese kürzeren Funktionen Sie erfolgreicher machen?
Ist
x => x * x
"leichter zu lesen" alsfunction (x) { return x * x; }
? Vielleicht liegt es daran, dass es wahrscheinlicher ist, dass eine einzelne, kurze Codezeile erzeugt wird. Nach Dysons Einfluss von Lesegeschwindigkeit und Zeilenlänge auf die Effektivität des Lesens vom Bildschirm ,Ähnliche Begründungen werden für den bedingten (ternären) Operator und für einzeilige
if
Anweisungen gemacht.Schreiben Sie jedoch wirklich die einfachen mathematischen Funktionen, die im Vorschlag angegeben sind ? Meine Domänen sind nicht mathematisch, daher sind meine Unterprogramme selten so elegant. Vielmehr sehe ich häufig, dass Pfeilfunktionen eine Spaltenbegrenzung überschreiten und aufgrund des Editors oder Styleguides in eine andere Zeile umbrechen, wodurch die "Lesbarkeit" nach Dysons Definition ungültig wird.
Man könnte sich fragen: "Wie wäre es, wenn Sie nur die Kurzversion für kurze Funktionen verwenden, wenn möglich?" Aber jetzt widerspricht eine Stilregel einer Sprachbeschränkung: "Versuchen Sie, die kürzestmögliche Funktionsnotation zu verwenden, wobei zu beachten ist, dass manchmal nur die längste Notation
this
wie erwartet gebunden wird ." Eine solche Verschmelzung macht Pfeile besonders anfällig für Missbrauch.Es gibt zahlreiche Probleme mit der Pfeilfunktionssyntax:
Beide Funktionen sind syntaktisch gültig. Aber es
doSomethingElse(x);
ist nicht im Körper vonb
, es ist nur eine schlecht eingerückte Aussage auf höchster Ebene.Beim Erweitern auf die Blockform gibt es kein Implizit mehr
return
, dessen Wiederherstellung man vergessen könnte. Aber der Ausdruck sollte möglicherweise nur eine Nebenwirkung hervorrufen. Wer weiß also, ob inreturn
Zukunft ein expliziter Ausdruck erforderlich sein wird?Was als Ruheparameter gedacht sein kann, kann als Spread-Operator analysiert werden:
Die Zuweisung kann mit Standardargumenten verwechselt werden:
Blöcke sehen aus wie Objekte:
Was bedeutet das?
Wollte der Autor ein No-Op oder eine Funktion erstellen, die ein leeres Objekt zurückgibt? ( Sollten wir in diesem Sinne jemals
{
danach platzieren=>
? Sollten wir uns nur auf die Ausdruckssyntax beschränken? Dies würde die Häufigkeit der Pfeile weiter verringern.)=>
sieht aus wie<=
und>=
:Um einen Pfeilfunktionsausdruck sofort aufzurufen, muss er
()
außen platziert()
werden. Die Platzierung innen ist jedoch gültig und kann beabsichtigt sein.Wenn man jedoch
(() => doSomething()());
mit der Absicht schreibt, einen sofort aufgerufenen Funktionsausdruck zu schreiben, passiert einfach nichts.Es ist schwer zu argumentieren, dass Pfeilfunktionen in Anbetracht aller oben genannten Fälle "verständlicher" sind. Man könnte alle speziellen Regeln lernen, die erforderlich sind, um diese Syntax zu verwenden. Lohnt es sich wirklich?
Die Syntax von
function
ist ausnahmsweise verallgemeinert. Zur Nutzungfunction
bedeutet , ausschließlich die Sprache selbst eine vom Schreiben verwirrend Code verhindert. Um Prozeduren zu schreiben, die in allen Fällen syntaktisch verstanden werden sollten, wähle ichfunction
.In Bezug auf eine Richtlinie
Sie fordern eine Richtlinie an, die "klar" und "konsistent" sein muss. Die Verwendung von Pfeilfunktionen führt schließlich zu syntaktisch gültigem, logisch ungültigem Code, wobei beide Funktionsformen sinnvoll und willkürlich miteinander verflochten sind. Deshalb biete ich folgendes an:
Richtlinie für die Funktionsnotation in ES6:
function
.this
einer Variablen zuweisen . Nicht verwenden() => {}
.quelle
self
statt eines dies sehen. Ihre angegebenen Fallstricke für Pfeilfunktionen sind ebenfalls alle gültig, und die gleichen Standards wie bei anderen Aussagen, die ohne geschweifte Klammern auskommen können, gelten auch hier. Ansonsten könnte man mit Ihrem Argument genauso gut überall für Pfeilfunktionen eintreten.this
ist das Problem von Javascript. Anstatt implizit gebunden zu sein,this
sollte als explizites Argument übergeben werden.Pfeilfunktionen wurden erstellt, um die Funktion zu vereinfachen
scope
und dasthis
Schlüsselwort zu lösen, indem es einfacher gestaltet wird. Sie verwenden die=>
Syntax, die wie ein Pfeil aussieht.Hinweis: Die vorhandenen Funktionen werden nicht ersetzt. Wenn Sie jede Funktionssyntax durch Pfeilfunktionen ersetzen, funktioniert dies nicht in allen Fällen.
Werfen wir einen Blick auf die vorhandene ES5-Syntax. Wenn sich das
this
Schlüsselwort in der Methode eines Objekts befindet (eine Funktion, die zu einem Objekt gehört), auf was würde es sich beziehen?Das obige Snippet würde sich auf einen beziehen
object
und den Namen ausdrucken"RajiniKanth"
. Lassen Sie uns den folgenden Ausschnitt untersuchen und sehen, worauf dies hier hinweisen würde.Was ist nun, wenn sich das
this
Schlüsselwort in befindetmethod’s function
?Hier würde sich dies
window object
als dasinner function
als herausgefallen bezeichnenscope
. Weilthis
, immer den Besitzer der Funktion verweist ist es in, für diesen Fall - da er nun den Gültigkeitsbereich ist - das Fenster / global - Objekt.Wenn es sich innerhalb einer
object
Methodefunction
befindet, ist der Eigentümer des Objekts das Objekt. Somit ist das Schlüsselwort this an das Objekt gebunden. Wenn es sich jedoch innerhalb einer Funktion befindet, entweder allein oder innerhalb einer anderen Methode, bezieht es sich immer auf daswindow/global
Objekt.Es gibt Möglichkeiten, dieses Problem
ES5
selbst zu lösen. Lassen Sie uns dies untersuchen, bevor wir uns mit den ES6-Pfeilfunktionen befassen, wie es gelöst werden kann.Normalerweise erstellen Sie eine Variable außerhalb der inneren Funktion der Methode. Jetzt
‘forEach’
erhält die Methode Zugriff aufthis
und damit auf dieobject’s
Eigenschaften und deren Werte.Verwenden Sie
bind
, um dasthis
Schlüsselwort, das sich auf die Methode bezieht, an das anzuhängenmethod’s inner function
.Mit der
ES6
Pfeilfunktion können wir daslexical scoping
Problem jetzt einfacher lösen.Arrow functions
sind eher Funktionsanweisungen, nur dass siebind
dies tunparent scope
. Wenn dasarrow function is in top scope
,this
bezieht Argumentwindow/global scope
, während ein Pfeil Funktion innerhalb einer regulären Funktion wird sein , dieses Argument hat das gleiche wie seine äußeree Funktion.With-
arrow
Funktionenthis
sind zumscope
Zeitpunkt der Erstellung an das Gehäuse gebunden und können nicht geändert werden. Der neue Operator, Binden, Aufrufen und Anwenden hat keine Auswirkung darauf.Im obigen Beispiel haben wir die Kontrolle darüber verloren. Wir können das obige Beispiel lösen, indem wir eine variable Referenz von
this
oder verwendenbind
. Mit ES6 wird es einfacher, das zu verwalten, an das esthis
gebunden istlexical scoping
.Wenn nicht zu Pfeilfunktionen
In einem Objektliteral.
Actor.getName
ist mit einem Pfeil Funktion definiert, aber beim Aufruf es undefined - Benachrichtigungen , dathis.name
istundefined
als der Kontext bleibtwindow
.Dies geschieht, weil die Pfeilfunktion den Kontext lexikalisch mit dem
window object
... dh dem äußeren Bereich verbindet. Die Ausführungthis.name
entspricht äquivalent zuwindow.name
, was nicht definiert ist.Objektprototyp
Die gleiche Regel gilt für die Definition von Methoden auf a
prototype object
. Anstatt eine Pfeilfunktion zum Definieren der sayCatName-Methode zu verwenden, wird Folgendes falsch angegebencontext window
:Konstruktoren aufrufen
this
In einem Konstruktionsaufruf ist das neu erstellte Objekt. Bei der Ausführung von new Fn () ist der Kontext vonconstructor Fn
ein neues Objekt :this instanceof Fn === true
.this
wird aus dem umschließenden Kontext eingerichtet, dh aus dem äußeren Bereich, der es dem neu erstellten Objekt nicht zuweist.Rückruf mit dynamischem Kontext
Die Pfeilfunktion bindet die
context
statisch bei Deklaration und kann nicht dynamisch gemacht werden. Das Anhängen von Ereignis-Listenern an DOM-Elemente ist eine häufige Aufgabe bei der clientseitigen Programmierung. Ein Ereignis löst die Handlerfunktion mit diesem als Zielelement aus.this
ist ein Fenster in einer Pfeilfunktion, die im globalen Kontext definiert ist. Wenn ein Klickereignis auftritt, versucht der Browser, die Handlerfunktion mit Schaltflächenkontext aufzurufen, die Pfeilfunktion ändert jedoch nicht den vordefinierten Kontext.this.innerHTML
ist gleichbedeutend mitwindow.innerHTML
und hat keinen Sinn.Sie müssen einen Funktionsausdruck anwenden, mit dem Sie dies je nach Zielelement ändern können:
Wenn der Benutzer auf die Schaltfläche klickt, ist dies in der Handlerfunktion die Schaltfläche. Somit
this.innerHTML = 'Clicked button'
ändert korrekt auf den Button Text geklickt Status zu reflektieren.Referenzen: https://dmitripavlutin.com/when-not-to-use-arrow-functions-in-javascript/
quelle
using bind to attach the this keyword that refers to the method to the method’s inner function.
hat Syntaxfehler.var Actor = { name: 'RajiniKanth', movies: ['Kabali', 'Sivaji', 'Baba'], showMovies: function() { this.movies.forEach(function(movie){ alert(this.name + ' has acted in ' + movie); }.bind(this)) } }; Actor.showMovies();
Verwendung: Alle ES5-Funktionen sollten durch ES6-Pfeilfunktionen ersetzt werden, außer in folgenden Szenarien:
Pfeilfunktionen sollten NICHT verwendet werden:
this
/arguments
in einer Funktion verwenden möchtenthis
/arguments
ihre eigenen, hängen sie auf ihrem äußeren Rahmen.constructor
this
.this
(was Objekt selbst sein sollte).Lassen Sie uns einige Varianten der Pfeilfunktionen verstehen, um sie besser zu verstehen:
Variante 1 : Wenn wir mehr als ein Argument an eine Funktion übergeben und einen Wert davon zurückgeben möchten.
ES5-Version :
ES6-Version :
Hinweis: Das
function
Schlüsselwort ist NICHT erforderlich.=>
ist erforderlich.{}
sind optional, wenn wir nicht bereitstellen,{}
return
wird implizit von JavaScript hinzugefügt, und wenn wir bereitstellen{}
, müssen wir hinzufügen,return
wenn wir es benötigen.Variante 2 : Wenn wir NUR ein Argument an eine Funktion übergeben und einen Wert davon zurückgeben möchten.
ES5-Version :
ES6-Version :
Hinweis: Wenn Sie nur ein Argument übergeben, können Sie Klammern weglassen
()
.Variante 3 : Wenn wir KEIN Argument an eine Funktion übergeben und keinen Wert zurückgeben möchten.
ES5-Version :
ES6-Version :
Variante 4 : Wenn wir explizit von Pfeilfunktionen zurückkehren möchten.
ES6-Version :
Variante 5 : Wenn wir ein Objekt von Pfeilfunktionen zurückgeben möchten.
ES6-Version :
Hinweis: Wir müssen das Objekt in Klammern setzen,
()
sonst kann JavaScript nicht zwischen einem Block und einem Objekt unterscheiden.Variante 6 : Pfeilfunktionen haben KEIN
arguments
eigenes (Array-ähnliches Objekt), für das sie vom äußeren Kontext abhängenarguments
.ES6-Version :
Hinweis:
foo
eine ES5 Funktion, mit einemarguments
Array wie Objekt und ein Argument übergeben , um es ist2
soarguments[0]
zufoo
2 ist .abc
ist eine ES6 Funktion Pfeil , da es selbst nicht hat , es istarguments
es daher drucktarguments[0]
derfoo
anstelle äußeren Kontext es ist.Variante 7 : Pfeilfunktionen haben KEINE
this
eigenen Funktionen, für die sie vom äußeren Kontext abhängenthis
ES5-Version :
Hinweis: Der an setTimeout übergebene Rückruf ist eine ES5-Funktion und hat eine eigene,
this
die in deruse-strict
Umgebung undefiniert ist. Daher erhalten wir folgende Ausgabe:ES6-Version :
Hinweis: Die Callback übergeben
setTimeout
ist eine ES6 Funktion Pfeil und es verfügt nicht über eine eigene ist ,this
so dass es dauert es von ihm äußere Rahmen ist, der ist ,greetUser
was hatthis
das heißtobj6
also bekommen wir Ausgabe:Verschiedenes: Wir können nicht
new
mit Pfeilfunktionen verwenden. Pfeilfunktionen haben keineprototype
Eigenschaft. Wir haben KEINE Bindung,this
wann die Pfeilfunktion durchapply
oder aufgerufen wirdcall
.quelle
Zusätzlich zu den bisher großartigen Antworten möchte ich einen ganz anderen Grund vorstellen, warum Pfeilfunktionen in gewissem Sinne grundsätzlich besser sind als "normale" JavaScript-Funktionen. Nehmen wir zur Diskussion vorübergehend an, wir verwenden eine Typprüfung wie TypeScript oder Facebooks "Flow". Betrachten Sie das folgende Spielzeugmodul, bei dem es sich um einen gültigen ECMAScript 6-Code plus Anmerkungen zum Flusstyp handelt: (Ich werde den untypisierten Code, der realistisch aus Babel resultieren würde, am Ende dieser Antwort einfügen, damit er tatsächlich ausgeführt werden kann.)
Nun sehen Sie, was passiert, wenn wir die Klasse C aus einem anderen Modul wie folgt verwenden:
Wie Sie sehen können, ist die Typprüfung hier fehlgeschlagen : f2 sollte eine Zahl zurückgeben, aber eine Zeichenfolge!
Schlimmer noch, es scheint, dass kein denkbarer Typprüfer normale JavaScript-Funktionen (ohne Pfeil) verarbeiten kann, da das "this" von f2 in der Argumentliste von f2 nicht vorkommt, sodass der erforderliche Typ für "this" möglicherweise nicht hinzugefügt werden konnte als Anmerkung zu f2.
Betrifft dieses Problem auch Personen, die keine Typprüfer verwenden? Ich denke schon, denn selbst wenn wir keine statischen Typen haben, denken wir, als ob sie da wären. ("Die ersten Parameter müssen eine Zahl sein, der zweite eine Zeichenfolge" usw.) Ein verstecktes "this" -Argument, das im Körper der Funktion verwendet werden kann oder nicht, erschwert unsere mentale Buchhaltung.
Hier ist die ausführbare, untypisierte Version, die von Babel produziert wird:
quelle
Ich bevorzuge die Verwendung von Pfeilfunktionen zu allen Zeiten, in denen
this
kein Zugriff auf local erforderlich ist, da die Pfeilfunktion ihre eigenen Argumente, Super- oder New.target-Werte nicht bindet .quelle
Ich stehe immer noch zu allem, was ich in meiner ersten Antwort in diesem Thread geschrieben habe. Meine Meinung zum Codestil hat sich jedoch seitdem weiterentwickelt, sodass ich eine neue Antwort auf diese Frage habe, die auf meiner letzten aufbaut.
In Bezug auf lexikalische
this
In meiner letzten Antwort habe ich absichtlich einen Grundgedanken vermieden, den ich über diese Sprache habe, da er nicht direkt mit dem Argument zusammenhängt, das ich vorbrachte. Ohne dies ausdrücklich zu erwähnen, kann ich jedoch verstehen, warum viele Menschen meiner Empfehlung, keine Pfeile zu verwenden, einfach widersprechen, wenn sie Pfeile so nützlich finden.
Mein Glaube ist folgender: Wir sollten ihn überhaupt nicht verwenden
this
. Wenn eine Person die Verwendungthis
in ihrem Code absichtlich vermeidet , ist die „lexikalischethis
“ Funktion von Pfeilen daher von geringem bis gar keinem Wert. Unter der Voraussetzung, dass diesthis
eine schlechte Sache ist, ist die Behandlung von Pfeilenthis
weniger eine „gute Sache“. Stattdessen ist es eher eine Form der Schadensbegrenzung für eine andere schlechte Sprachfunktion.Ich denke, dass dies entweder einigen Menschen nicht einfällt, aber selbst denen, denen es passiert, müssen sie sich immer in Codebasen befinden, in denen
this
hundert Mal pro Datei vorkommt, und ein wenig (oder viel) Schadensbegrenzung ist alles eine vernünftige Person könnte hoffen. Pfeile können also in gewisser Weise gut sein, wenn sie eine schlechte Situation verbessern.Auch wenn es einfacher ist, Code mit
this
und ohne Pfeile zu schreiben , bleiben die Regeln für die Verwendung von Pfeilen sehr komplex (siehe: aktueller Thread). Daher sind Richtlinien weder "klar" noch "konsistent", wie Sie es gewünscht haben. Selbst wenn Programmierer die Mehrdeutigkeiten von Pfeilen kennen, zucken sie mit den Schultern und akzeptieren sie trotzdem, weil der Wert von lexikalisch siethis
überschattet.All dies ist ein Vorwort zu folgender Erkenntnis: Wenn man es nicht benutzt
this
, wird die Mehrdeutigkeit überthis
diese Pfeile normalerweise irrelevant. Pfeile werden in diesem Zusammenhang neutraler.In Bezug auf die knappe Syntax
Als ich meine erste Antwort schrieb, war ich der Meinung, dass selbst die sklavische Einhaltung von Best Practices einen lohnenden Preis darstellt, wenn dies bedeutet, dass ich perfekteren Code produzieren kann. Aber irgendwann wurde mir klar, dass Knappheit als eine Form der Abstraktion dienen kann, die auch die Codequalität verbessern kann - genug, um manchmal zu rechtfertigen, von Best Practices abzuweichen.
Mit anderen Worten: Verdammt, ich möchte auch Einzeilerfunktionen!
In Bezug auf eine Richtlinie
Mit der Möglichkeit von
this
neutralen Pfeilfunktionen und der Verfolgung der Knappheit biete ich die folgende mildere Richtlinie an:Richtlinie für die Funktionsnotation in ES6:
this
.quelle
Auf einfache Weise
Eine andere Instanz:
Antwort: Die Konsole würde 20 drucken.
Der Grund dafür ist, dass bei jeder Ausführung einer Funktion ein eigener Stapel erstellt wird. In diesem Beispiel wird die
ex
Funktion mit demnew
Operator ausgeführt, sodass ein Kontext erstellt wird. Wenn sieinner
ausgeführt wird, erstellt JS einen neuen Stapel und führt dieinner
Funktion a ausglobal context
obwohl es eine gibt lokaler Kontext.Wenn wir also möchten, dass die
inner
Funktion einen lokalen Kontextex
hat, müssen wir den Kontext an die innere Funktion binden.Pfeile lösen dieses Problem, anstatt die zu
Global context
nehmen,local context
wenn sie welche haben . In dergiven example,
wird esnew ex()
als dauernthis
.In allen Fällen, in denen die Bindung explizit ist, lösen Pfeile das Problem standardmäßig.
quelle
Pfeilfunktionen oder Lambdas wurden in ES 6 eingeführt. Abgesehen von seiner Eleganz in minimaler Syntax besteht der bemerkenswerteste funktionale Unterschied darin, dass innerhalb einer Pfeilfunktion
this
ein Bereich festgelegt wirdEinschränkungen Pfeilfunktionen als Methoden für ein Objekt
Im Fall von ,
objA.print()
wennprint()
Methode regelmäßig definiert mitfunction
, es funktionierte durch die Lösungthis
richtigobjA
für Methodenaufruf aber nicht , wenn sie als Pfeil definiert=>
Funktion. Dies liegt daran, dassthis
in einer regulären Funktion beim Aufrufen als Methode für ein Objekt (objA
) das Objekt selbst vorhanden ist. Im Falle einer Pfeilfunktionthis
wird sie jedoch lexikalisch an diethis
des umschließenden Bereichs gebunden, in dem sie definiert wurde (in unserem Fall global / Window), und bleibt während des Aufrufs als Methode unverändertobjA
.Vorteile einer Pfeilfunktion gegenüber regulären Funktionen in Methode (n) eines Objekts, ABER nur dann, wenn
this
erwartet wird, dass sie bei der Zeitdefinition festgelegt und gebunden wird.Im Fall des in
objB.print()
demprint()
Verfahren als Funktion definiert , dass Invokesconsole.log(
[$ {this.id} -> {this.name}])
asynchron als Rückruf aufsetTimeout
,this
aufgelöst richtig ,objB
wenn ein Pfeil Funktion als Rückruf verwendet wurde , aber nicht wenn Rückruf als reguläre Funktion definiert wurde. Dies liegt daran=>
, dasssetTimeout(()=>..)
diethis
Pfeilfunktion von ihrem übergeordneten Element lexikalisch an geschlossen übergeben wurde, d. H. AufrufobjB.print()
davon definiert es. Mit anderen Worten-der Pfeil=>
bestand Funktion um bissetTimeout(()==>...
zu gebundenobjB
als ,this
weil die in AufrufobjB.print()
this
warobjB
selbst.Wir könnten leicht verwenden
Function.prototype.bind()
, um den Rückruf als reguläre Funktion zu definieren, indem wir ihn an die richtige bindenthis
.Pfeilfunktionen sind jedoch praktisch und weniger fehleranfällig für den Fall von asynchronen Rückrufen, bei denen wir das kennen
this
zum Zeitpunkt der Funktionsdefinition abgerufen werden und gebunden werden sollten.Einschränkung von Pfeilfunktionen, bei denen sich dies über Aufrufe hinweg ändern muss
Immer
this
wenn wir eine Funktion benötigen , die zum Zeitpunkt des Aufrufs geändert werden kann, können wir keine Pfeilfunktionen verwenden.Keine der oben genannten Funktionen funktioniert
const print = () => { console.log(
mit der Pfeilfunktion [$ {this.id} -> {this.name}],);}
dathis
sie nicht geändert werden kann und anthis
den umschließenden Bereich gebunden bleibt, in dem sie definiert wurde (global / Window). In all diesen Beispielen haben wir dieselbe Funktion mit verschiedenen Objekten (obj1
undobj2
) nacheinander aufgerufen , die beide nach dem erstellt wurdenprint()
Deklaration Funktion erstellt wurden.Dies waren erfundene Beispiele, aber lassen Sie uns über einige weitere Beispiele aus dem wirklichen Leben nachdenken. Wenn wir unsere
reduce()
Methode ähnlich wie eine schreiben müssten , die funktioniertarrays
, können wir sie wiederum nicht als Lambda definieren, da sie abgeleitet werden mussthis
aus dem Aufrufkontext abgeleitet werden muss, d. H. das Array, auf dem es aufgerufen wurdeAus diesem Grund können
constructor
Funktionen niemals als Pfeilfunktionen definiert werden, dathis
für eine Konstruktorfunktion zum Zeitpunkt ihrer Deklaration keine Funktionen festgelegt werden können. Jedes Mal, wenn eine Konstruktorfunktion mit aufgerufen wirdnew
Schlüsselwort , wird ein neues Objekt erstellt, das dann an diesen bestimmten Aufruf gebunden wird.Auch wenn Frameworks oder Systeme eine Rückruffunktion (en) akzeptieren, die später mit dynamischem Kontext aufgerufen werden sollen
this
, können wir keine Pfeilfunktionen verwenden, da diesethis
möglicherweise bei jedem Aufruf erneut geändert werden müssen. Diese Situation tritt häufig bei DOM-Ereignishandlern aufDies ist auch der Grund, warum in Frameworks wie Angular 2+ und Vue.js erwartet wird, dass die Bindungsmethoden für Vorlagenkomponenten reguläre Funktionen / Methoden sind, da
this
ihr Aufruf von den Frameworks für die Bindungsfunktionen verwaltet wird. (Angular verwendet Zone.js, um den asynchronen Kontext für Aufrufe von Bindungsfunktionen für Ansichtsvorlagen zu verwalten.)Auf der anderen Seite, in Reaktion , wenn wir einer Komponente Methode als ein Ereignis-Handler zum Beispiel passieren wollen
<input onChange={this.handleOnchange} />
wir definieren solltenhandleOnchanage = (event)=> {this.props.onInputChange(event.target.value);}
als Pfeil Funktion wie bei jedem Aufruf wollen wir dieselbe Instanz der Komponente sein, der die JSX produziert für erbrachte DOM-Element.Dieser Artikel ist auch in meiner Medium- Veröffentlichung verfügbar . Wenn Ihnen der Artikel gefällt oder Sie Kommentare und Vorschläge haben, klatschen Sie bitte oder hinterlassen Sie Kommentare zu Medium .
quelle