In einer anderen Frage wies ein Benutzer darauf hin, dass die new
Verwendung des Schlüsselworts gefährlich sei, und schlug eine Lösung für die Objekterstellung vor, die nicht verwendet wurde new
. Ich habe nicht geglaubt, dass das stimmt, hauptsächlich, weil ich Prototype, Scriptaculous und andere hervorragende JavaScript-Bibliotheken verwendet habe und jeder von ihnen das new
Schlüsselwort verwendet hat.
Trotzdem habe ich gestern Douglas Crockfords Vortrag im YUI-Theater gesehen und er sagte genau das Gleiche, dass er das new
Schlüsselwort nicht mehr in seinem Code verwendet hat ( Crockford in JavaScript - Akt III: Function the Ultimate - 50:23 Minuten ).
Ist es "schlecht", das new
Schlüsselwort zu verwenden? Was sind die Vor- und Nachteile der Verwendung?
quelle
new
. Aber wenn Sie sich die YUI-Bibliothek ansehen. Sie müssennew
überall verwenden. Wie zum Beispielvar myDataSource = new Y.DataSource.IO({source:"./myScript.php"});
.init
Methode hacken müssen, wenn Sie denObject.create
Ansatz verwenden, und diese anschließend aufrufen. Viel einfacher zu verwenden,new
was beides bewirkt, die Prototypenkette festlegt und einen Initialisierungscode aufruft.new
ist nicht gefährlich. Auslassennew
ist gefährlich und daher schlecht . In ES5 können Sie jedoch den Strict Mode verwenden , der Sie vor dieser und vielen anderen Gefahren schützt.Antworten:
Crockford hat viel getan, um gute JavaScript-Techniken bekannt zu machen. Seine Stellungnahme zu Schlüsselelementen der Sprache hat viele nützliche Diskussionen ausgelöst. Trotzdem gibt es viel zu viele Menschen, die jede Verkündigung von "schlecht" oder "schädlich" als Evangelium betrachten und sich weigern, über die Meinung eines Mannes hinauszuschauen. Es kann manchmal etwas frustrierend sein.
Die Verwendung der durch das
new
Schlüsselwort bereitgestellten Funktionalität hat mehrere Vorteile gegenüber der Erstellung jedes Objekts von Grund auf neu:prototype
undnew
zum Ausstempeln neuer Objekte. Dies ist nicht nur schneller (es wird kein Code für jede Methode des Prototyps benötigt), sondern es wird auch vermieden, dass jedes Objekt mit separaten Eigenschaften für jede Methode überlagert wird. Auf langsameren Computern (oder insbesondere langsameren JS-Interpreten) kann dies beim Erstellen vieler Objekte zu einer erheblichen Zeit- und Speicherersparnis führen.Und ja,
new
hat einen entscheidenden Nachteil, der durch andere Antworten geschickt beschrieben wird: Wenn Sie vergessen, ihn zu verwenden, wird Ihr Code ohne Vorwarnung beschädigt. Glücklicherweise lässt sich dieser Nachteil leicht abmildern - fügen Sie der Funktion selbst einfach ein bisschen Code hinzu:Jetzt können Sie die Vorteile nutzen,
new
ohne sich um Probleme sorgen zu müssen, die durch versehentlichen Missbrauch verursacht wurden. Sie können der Prüfung sogar eine Behauptung hinzufügen, wenn Sie der Gedanke an fehlerhaften Code stört. Oder verwenden Sie, wie einige kommentiert haben, die Prüfung, um eine Laufzeitausnahme einzuführen:(Beachten Sie, dass mit diesem Snippet vermieden werden kann, dass der Name der Konstruktorfunktion fest codiert wird, da das Objekt im Gegensatz zum vorherigen Beispiel nicht tatsächlich instanziiert werden muss. Daher kann es ohne Änderung in jede Zielfunktion kopiert werden.)
John Resig geht in seinem einfachen "Klassen" -Instanzierungsbeitrag ausführlich auf diese Technik ein und fügt standardmäßig ein Mittel hinzu, um dieses Verhalten in Ihre "Klassen" zu integrieren. Auf jeden Fall eine Lektüre wert ... ebenso wie sein bevorstehendes Buch Secrets of the JavaScript Ninja , das in diesem und vielen anderen "schädlichen" Merkmalen der JavaScript-Sprache verborgenes Gold findet (das Kapitel darüber
with
ist besonders aufschlussreich für diejenigen von uns, die es ursprünglich entlassen haben diese vielfach bösartige Funktion als Spielerei).quelle
new
, oder verwenden Sie eine Wrapper-Funktion, um es für Sie zu speichern. Ich vermute , wenn Sie an dem Punkt angelangt sind, an dem es darauf ankommt, haben Sie bereits andere Optimierungen wie das Auswendiglernen ausgeschöpft, sodass Ihre Erstellungsaufrufe ohnehin lokalisiert werden ...arguments.callee
, um zu überprüfen, ob Sie angerufen wurden, istnew
möglicherweise nicht so gut, daarguments.callee
sie im strengen Modus nicht verfügbar ist. Verwenden Sie besser den Funktionsnamen.new
weil Sie vergessen können, es in Ihren Code zu schreiben, ist genauso lächerlich wie mein Beispiel.Ich habe gerade einige Teile seines Crockfords-Buches "Javascript: The Good Parts" gelesen. Ich habe das Gefühl, dass er alles, was ihn jemals gebissen hat, als schädlich ansieht:
Über Schalter fallen durch:
Über ++ und -
Über neu:
Es gibt noch mehr, aber ich hoffe, Sie bekommen das Bild.
Meine Antwort auf Ihre Frage: Nein, es ist nicht schädlich. Aber wenn Sie vergessen, es zu verwenden, wenn Sie sollten, könnten Sie einige Probleme haben. Wenn Sie sich in einer guten Umgebung entwickeln, bemerken Sie das.
Aktualisieren
Ungefähr ein Jahr nach dem Schreiben dieser Antwort wurde die 5. Ausgabe von ECMAScript veröffentlicht, die den strengen Modus unterstützt . Ist im strengen Modus
this
nicht mehr an das globale Objekt gebunden, sondern anundefined
.quelle
Javascript ist eine dynamische Sprache. Es gibt unzählige Möglichkeiten, Fehler zu machen, wo eine andere Sprache Sie aufhalten würde.
Das Vermeiden einer grundlegenden Sprachfunktion, beispielsweise
new
auf der Grundlage von Unordnung, ist ein bisschen so, als würden Sie Ihre glänzenden neuen Schuhe ausziehen, bevor Sie durch ein Minenfeld gehen, nur für den Fall, dass Ihre Schuhe schlammig werden.Ich verwende eine Konvention, bei der Funktionsnamen mit einem Kleinbuchstaben beginnen und 'Funktionen', die eigentlich Klassendefinitionen sind, mit einem Großbuchstaben beginnen. Das Ergebnis ist ein wirklich überzeugender visueller Hinweis darauf, dass die 'Syntax' falsch ist:
Darüber hinaus helfen gute Namensgewohnheiten. Nachdem alle Funktionen Dinge getan haben, sollte der Name ein Verb enthalten, während Klassen Objekte darstellen und Substantive und Adjektive ohne Verb sind.
Es ist interessant, wie die Syntaxfärbung von SO den obigen Code interpretiert hat.
quelle
if (! this instanceof MyClass) return new MyClass()
) bevorzuge ich eigentlich dienew
-less-Syntax. Warum? Weil Funktionen allgemeiner sind als Konstruktorfunktionen . Das Weglassennew
macht es einfach, eine Konstruktorfunktion in eine reguläre Funktion umzuwandeln ... oder umgekehrt. Durchnew
das Hinzufügen wird der Code spezifischer als nötig. Und damit weniger flexibel. Vergleichen Sie mit Java, wo empfohlen wird,List
stattdessen zu akzeptieren,ArrayList
damit der Aufrufer die Implementierung auswählen kann.Ich bin ein Neuling in Javascript, also bin ich vielleicht nicht so erfahren darin, einen guten Standpunkt dazu zu bieten. Dennoch möchte ich meine Meinung zu dieser "neuen" Sache teilen.
Ich komme aus der C # -Welt, in der die Verwendung des Schlüsselworts "neu" so natürlich ist, dass es das Fabrikdesignmuster ist, das mir komisch vorkommt.
Wenn ich zum ersten Mal in Javascript codiere, merke ich nicht, dass es das "neue" Schlüsselwort und den neuen Code wie im YUI-Muster gibt, und es dauert nicht lange, bis ich in eine Katastrophe gerate. Ich verliere den Überblick darüber, was eine bestimmte Zeile tun soll, wenn ich auf den Code zurückblicke, den ich geschrieben habe. Chaotischer ist, dass mein Verstand nicht wirklich zwischen Objektinstanzgrenzen wechseln kann, wenn ich den Code "trocken laufen lasse".
Dann fand ich das "neue" Schlüsselwort, das für mich "Dinge trennt". Mit dem neuen Schlüsselwort werden Dinge erstellt. Ohne das neue Schlüsselwort weiß ich, dass ich es nicht mit dem Erstellen von Dingen verwechseln werde, es sei denn, die von mir aufgerufene Funktion gibt mir starke Hinweise darauf.
Zum Beispiel habe
var bar=foo();
ich keine Ahnung, welcher Balken möglicherweise sein könnte ... Ist es ein Rückgabewert oder ist es ein neu erstelltes Objekt? Abervar bar = new foo();
ich weiß mit Sicherheit, dass Bar ein Objekt ist.quelle
typeof new foo() == "object"
. Esnew
gibt eine Instanz von zurückfoo
, und Sie wissen, dass Siefoo.bar()
und aufrufen könnenfoo.bang()
. Dies kann jedoch leicht durch die Verwendung von JsDocs @return gemildert werden. Nicht, dass ich mich für Verfahrenscode einsetze (das Wort meidenew
)Ein weiterer Fall für Neues ist das, was ich Pooh Coding nenne . Winnie the Pooh folgt seinem Bauch. Ich sage, geh mit der Sprache, die du benutzt, nicht dagegen .
Es besteht die Möglichkeit, dass die Betreuer der Sprache die Sprache für die Redewendungen optimieren, die sie zu fördern versuchen. Wenn sie ein neues Schlüsselwort in die Sprache einfügen, halten sie es wahrscheinlich für sinnvoll, beim Erstellen einer neuen Instanz klar zu sein.
Code, der gemäß den Absichten der Sprache geschrieben wurde, wird mit jeder Version effizienter. Und Code, der die Schlüsselkonstrukte der Sprache vermeidet, wird mit der Zeit leiden.
EDIT: Und das geht weit über die Leistung hinaus. Ich kann die Zeiten zählt , die ich gehört habe (oder die) „Warum zum Teufel hat sie das ?“ wenn Sie seltsam aussehenden Code finden. Es stellt sich oft heraus, dass es zu der Zeit, als der Code geschrieben wurde, einen "guten" Grund dafür gab. Das Befolgen des Tao der Sprache ist Ihre beste Versicherung dafür, dass Ihr Code in einigen Jahren nicht verspottet wird.
quelle
Ich habe einen Beitrag darüber geschrieben, wie das Problem des Aufrufs eines Konstruktors ohne das neue Schlüsselwort gemindert werden kann.
Es ist größtenteils didaktisch, zeigt jedoch, wie Sie Konstruktoren erstellen können, die mit oder ohne
new
funktionieren, und erfordert nicht, dass Sie in jedem Konstruktor Boilerplate-Code zum Testen hinzufügenthis
.http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html
Hier ist der Kern der Technik:
So verwenden Sie es:
quelle
arguments.callee
ist großartig!surrogateConstructor
sollte seinsurrogateCtor
(oder umgekehrt).Die Gründe für die Nichtverwendung des neuen Schlüsselworts sind einfach:
Wenn Sie es überhaupt nicht verwenden, vermeiden Sie die Gefahr, dass Sie es versehentlich weglassen. Das von YUI verwendete Konstruktionsmuster ist ein Beispiel dafür, wie Sie das neue Schlüsselwort insgesamt vermeiden können. "
Alternativ könnten Sie so:
Auf diese Weise laufen Sie jedoch Gefahr, dass jemand vergisst, das neue Schlüsselwort zu verwenden, und dass dieser Operator nur ein Fubar ist. AFAIK es gibt keinen Vorteil, dies zu tun (außer Sie sind daran gewöhnt).
Am Ende des Tages: Es geht darum, defensiv zu sein. Können Sie die neue Anweisung verwenden? Ja. Macht es Ihren Code gefährlicher? Ja.
Wenn Sie jemals C ++ geschrieben haben, entspricht dies dem Setzen von Zeigern auf NULL, nachdem Sie sie gelöscht haben.
quelle
Ich denke, "neu" fügt dem Code Klarheit hinzu. Und Klarheit ist alles wert. Gut zu wissen, dass es Fallstricke gibt, aber sie durch Vermeidung von Klarheit zu vermeiden, scheint mir nicht der richtige Weg zu sein.
quelle
Fall 1:
new
ist nicht erforderlich und sollte vermieden werdenFall 2:
new
ist erforderlich, andernfalls wird eine Fehlermeldung angezeigtquelle
toString()
. Verwenden Sie in allen anderen Fällen Literale. NichtString('asd')
, aber einfach'asd'
und nichtNumber(12)
, sondern einfach12
.Array
:Array(5).fill(0)
ist offensichtlich besser lesbar als[undefined, undefined, undefined, undefined, undefined].fill(0)
und(var arr = []).length = 5; arr.fill(0);
new
mit Konstruktoren für Objekttypen bezieht, die primitiven Typen entsprechen. Das von Ihnen vorgeschlagene Literal entspricht nicht demArray
Aufruf (try0 in …
), und der Rest ist ein Syntaxfehler :) Ansonsten sind Sie korrekt, obwohl auch angemerkt werden sollte, dassArray(5)
dies mehrdeutig sein kann, wenn Sie nicht konforme Implementierungen in Betracht ziehen (und daher eine emulierteArray.prototype.fill(…)
).Hier ist die kürzeste Zusammenfassung der beiden stärksten Argumente für und gegen die Verwendung des
new
Operators:Gegenargument
new
new
Operators als Objekte instanziiert werden sollen , können katastrophale Auswirkungen haben, wenn sie fälschlicherweise als normale Funktionen aufgerufen werden. In einem solchen Fall wird der Code einer Funktion in dem Bereich ausgeführt, in dem die Funktion aufgerufen wird, anstatt wie beabsichtigt im Bereich eines lokalen Objekts. Dies kann dazu führen, dass globale Variablen und Eigenschaften mit katastrophalen Folgen überschrieben werden.function Func()
, dann aufzurufenFunc.prototype
und Dinge hinzuzufügen, damit Sie aufrufen könnennew Func()
, um Ihr Objekt zu konstruieren, die aus architektonischen und stilistischen Gründen lieber einen anderen Stil der Objektvererbung verwenden würden.Weitere Informationen zu diesem Argument finden Sie in Douglas Crockfords großartigem und prägnantem Buch Javascript: The Good Parts. In der Tat überprüfen Sie es trotzdem.
Argument für
new
new
Operators zusammen mit der prototypischen Zuweisung ist schnell.In John Resigs Beitrag finden Sie eine einfache Erklärung dieser Technik und eine allgemein tiefere Erklärung des von ihm befürworteten Vererbungsmodells.
quelle
'use strict';
Modus (oder der Methode in Ihrem Link) gemildert werden. # 2 Hat in ES6 synatischen Zucker , das Verhalten ist jedoch das gleiche wie zuvor.Ich stimme Pez und einigen hier zu.
Mir scheint klar, dass "neu" eine selbstbeschreibende Objekterstellung ist, bei der das von Greg Dean beschriebene YUI-Muster vollständig verdeckt ist .
Die Möglichkeit, dass jemand schreiben könnte
var bar = foo;
odervar bar = baz();
wo baz keine Methode zum Erstellen von Objekten ist, scheint weitaus gefährlicher zu sein.quelle
Ich denke, neu ist böse, nicht weil es Probleme verursachen kann, wenn Sie vergessen, es versehentlich zu verwenden, sondern weil es die Vererbungskette durcheinander bringt und das Verständnis der Sprache erschwert.
JavaScript ist prototypbasiert objektorientiert. Daher MUSS jedes Objekt so aus einem anderen Objekt erstellt werden
var newObj=Object.create(oldObj)
. Hier wird oldObj als Prototyp von newObj bezeichnet (daher "prototypbasiert"). Dies bedeutet, dass eine Eigenschaft, die in newObj nicht gefunden wird, in oldObj durchsucht wird . newObj ist daher standardmäßig ein leeres Objekt, scheint jedoch aufgrund seiner Prototypkette alle Werte von oldObj zu haben .Auf der anderen Seite , wenn Sie tun ,
var newObj=new oldObj()
der Prototyp, NEWOBJ ist oldObj.prototype , die unnötig schwer zu verstehen ist.Der Trick ist zu verwenden
Es ist innerhalb dieser Funktion und nur hier sollte neu verwendet werden. Verwenden Sie danach einfach die Object.create () -Methode. Die Methode löst das Prototypproblem.
quelle
var c = new Car()
ist das gleiche wie zu tunvar c = Object.create(Car.prototype); Car.call(c)