Crockford hat viel dazu beigetragen, gute JavaScript-Techniken bekannt zu machen. Seine Stellungnahmen zu Schlüsselelementen der Sprache haben viele nützliche Diskussionen ausgelöst. Allerdings gibt es viel zu viele Leute, die jede Verkündung von "schlecht" oder "schädlich" als Evangelium nehmen und sich weigern, über die Meinung eines Mannes hinauszusehen. Das kann manchmal ein wenig frustrierend sein.
Die Nutzung der Funktionen des new
hat mehrere Vorteile gegenüber der Erstellung jedes Objekts von Grund auf:
- Vererbung von Prototypen . Obwohl sie von denjenigen, die an klassenbasierte OO-Sprachen gewöhnt sind, oft mit einer Mischung aus Misstrauen und Spott betrachtet wird, ist die native Vererbungstechnik von JavaScript ein einfaches und überraschend effektives Mittel zur Wiederverwendung von Code. Und die
new
ist das kanonische (und einzig verfügbare plattformübergreifende) Mittel zur Verwendung des Schlüsselworts.
- Leistung. Dies ist ein Nebeneffekt von Nr. 1: Wenn ich jedem von mir erstellten Objekt 10 Methoden hinzufügen möchte, muss ich podría einfach eine Erstellungsfunktion schreiben, die jede Methode manuell jedem neuen Objekt zuweist... Oder ich könnte sie der Erstellungsfunktion zuweisen
prototype
und verwenden new
um neue Objekte auszustempeln. Dies ist nicht nur schneller (kein Code für jede einzelne Methode des Prototyps erforderlich), sondern vermeidet auch, dass jedes Objekt mit separaten Eigenschaften für jede Methode aufgebläht wird. Auf langsameren Rechnern (oder insbesondere langsameren JS-Interpretern) kann dies bei der Erstellung vieler Objekte eine erhebliche Zeit- und Speichereinsparung bedeuten.
Und ja, new
hat einen entscheidenden Nachteil, der bereits in anderen Antworten beschrieben wurde: Wenn Sie vergessen, es zu benutzen, wird Ihr Code ohne Vorwarnung beschädigt. Glücklicherweise lässt sich dieser Nachteil leicht abmildern - fügen Sie einfach ein wenig Code zur Funktion selbst hinzu:
function foo()
{
// if user accidentally omits the new keyword, this will
// silently correct the problem...
if ( !(this instanceof foo) )
return new foo();
// constructor logic follows...
}
Jetzt können Sie die Vorteile nutzen von new
ohne sich um Probleme durch versehentliche Fehlbedienung sorgen zu müssen.
John Resig geht auf diese Technik in seinem Buch Einfache "Klassen"-Instantiierung Post sowie eine Möglichkeit, dieses Verhalten standardmäßig in Ihre "Klassen" einzubauen. Definitiv eine Lektüre wert... wie auch sein kommendes Buch, Die Geheimnisse des JavaScript-Ninjas das in dieser und vielen anderen "schädlichen" Eigenschaften der JavaScript-Sprache verstecktes Gold findet (die Kapitel en with
ist besonders für diejenigen von uns aufschlussreich, die diese vielgeschmähte Funktion zunächst als Spielerei abgetan haben).
Eine allgemeine Plausibilitätsprüfung
Sie können sogar eine Behauptung in die Prüfung einbauen, wenn Sie der Gedanke stört, dass fehlerhafter Code stillschweigend funktioniert. Oder, wie einige kommentiert, verwenden Sie die Prüfung, um eine Laufzeitausnahme einzuführen:
if ( !(this instanceof arguments.callee) )
throw new Error("Constructor called as a function");
Beachten Sie, dass dieses Snippet die harte Kodierung des Konstruktorfunktionsnamens vermeiden kann, da es im Gegensatz zum vorherigen Beispiel das Objekt nicht tatsächlich instanziieren muss - daher kann es ohne Änderung in jede Zielfunktion kopiert werden.
ES5 nimmt weg
Comme Sean McMillan , stephenbez y jrh festgestellt, dass die Verwendung von arguments.callee
ist in der ES5-Version ungültig strenger Modus . Das obige Muster führt also zu einem Fehler, wenn Sie es in diesem Zusammenhang verwenden.
ES6 und eine völlig harmlose new
ES6 führt ein Klassen zu JavaScript - nein, nicht in der seltsamen Java-aping Weise, dass die alte Schule Crockford tat, sondern im Geiste viel mehr wie die leichtgewichtige Art, die er (und andere) später angenommen, wobei die besten Teile der prototypischen Vererbung und Backen gemeinsame Muster in die Sprache selbst.
...und dazu gehört auch ein Safe new
:
class foo
{
constructor()
{
// constructor logic that will ONLY be hit
// if properly constructed via new
}
}
// bad invocation
foo(); // throws,
// Uncaught TypeError: class constructors must be invoked with 'new'
Aber was ist, wenn Sie das nicht tun? wollen den neuen Zucker zu verwenden? Was ist, wenn Sie einfach Ihren einwandfreien Prototyp-Code im alten Stil mit den oben gezeigten Sicherheitsprüfungen aktualisieren wollen, so dass er weiterhin im Strict-Modus funktioniert?
Nun, als Nick Parsons stellt fest bietet ES6 auch dafür eine praktische Prüfung in Form von new.target
:
function foo()
{
if ( !(new.target) )
throw new Error("Constructor called as a function");
// constructor logic follows...
}
Für welchen Ansatz Sie sich auch entscheiden, Sie können - mit ein wenig Überlegung und guter Hygiene - die new
ohne Schaden.
97 Stimmen
Es ist NICHT "schlecht", das Schlüsselwort new zu verwenden. Aber wenn Sie es vergessen, rufen Sie den Objektkonstruktor wie eine normale Funktion auf. Wenn Ihr Konstruktor seinen Ausführungskontext nicht überprüft, wird er nicht bemerken, dass "this" auf ein anderes Objekt (normalerweise das globale Objekt) statt auf die neue Instanz zeigt. Daher wird Ihr Konstruktor Eigenschaften und Methoden zum globalen Objekt (Fenster) hinzufügen. Wenn Sie in der Objektfunktion immer prüfen, ob "this" eine Instanz Ihres Objekts ist, werden Sie dieses Problem nie haben.
5 Stimmen
Ich kann das nicht verstehen. Einerseits rät Doug von der Verwendung von
new
. Aber wenn Sie sich die YUI-Bibliothek ansehen. Sie haben zu verwendennew
überall. Wie zum Beispielvar myDataSource = new Y.DataSource.IO({source:"./myScript.php"});
.2 Stimmen
@aditya_gaur Das liegt daran, dass man, wenn man eine Initialisierung eines Objekts benötigt, eine
init
Methode, wenn Sie dieObject.create
Ansatz und rufen Sie danach an. Viel einfacher ist es, einfach zu verwendennew
der beides tut, die Prototypenkette setzt und einen Initialisierungscode aufruft.71 Stimmen
Ich glaube nicht, dass die Sache geschlossen werden sollte. Ja, es wird wahrscheinlich einige Crockford-Antifan-Gifte auslösen, aber wir reden hier über den beliebten Rat, ein wichtiges Sprachfeature grundsätzlich zu vermeiden. Der Mechanismus, der dafür sorgt, dass jedes JQuery-Objekt fast nichts wiegt (was den Speicher betrifft), beinhaltet die Verwendung des Schlüsselworts "new". Ziehen Sie Factory-Methoden dem ständigen Aufrufen von new vor, aber schränken Sie Ihre architektonischen Möglichkeiten und Ihr Leistungspotenzial nicht drastisch ein, indem Sie nur Objektliterale verwenden. Sie haben ihre Berechtigung und Konstruktoren haben ihre Berechtigung. Das ist ein veralteter und miserabler Ratschlag.
1 Stimmen
Einen Ausführungskontext abzulehnen, der nicht von Ihrer Objektfunktion erbt, ist kein sinnvoller Ansatz. Sie haben dann kritische Funktionen wie .call und .apply unterbrochen.
5 Stimmen
TLDR: Verwendung
new
ist nicht gefährlich. Auslassen vonnew
gefährlich ist, und deshalb schlecht . Aber in ES5 können Sie verwenden Strenger Modus die Sie vor dieser und vielen anderen Gefahren schützt.3 Stimmen
Dieser gesamte Thread ist veraltet. Die derzeit beste Praxis ist die Verwendung von ES6-Modulen und, für die Vererbung, ES6-Klassen. Sie sind standardmäßig im Strict-Modus, was bedeuten würde, dass
this
wird nicht seinglobalThis
in einem Funktionsaufruf, aber es geht noch darüber hinaus: Klassen können nicht verwendet werden ohnenew
überhaupt . Seit ES6 hat sich die Sprache weiterentwickelt zu fördern die Verwendung vonnew
wie sie von neueren Konstrukteuren wieMap
oSet
nicht (mehr) benutzbar sein ohnenew
. Dagegen vorzugehen, erscheint nicht sinnvoll. Beachten Sie, dass alt Konstrukteure, z.B.new String
,new Date
,new Array
haben alt Regeln.