596 Stimmen

Gilt das Schlüsselwort "new" in JavaScript als schädlich?

In einem anderen Frage wies ein Nutzer darauf hin, dass die new Schlüsselwort gefährlich war, und schlug eine Lösung für die Objekterstellung vor, bei der keine new . Ich habe nicht geglaubt, dass das stimmt, vor allem, weil ich Prototype, Scriptaculous und andere hervorragende JavaScript-Bibliotheken verwendet habe, und jede von ihnen hat die new Stichwort.

Trotzdem habe ich gestern den Vortrag von Douglas Crockford im YUI-Theater gesehen und er sagte genau das Gleiche, dass er die new Schlüsselwort nicht mehr in seinem Code ( Crockford über JavaScript - Akt III: Die ultimative Funktion - 50:23 Minuten ).

Ist es "schlecht", die new Stichwort? Was sind die Vor- und Nachteile seiner Verwendung?

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 verwenden new überall. Wie zum Beispiel var 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 die Object.create Ansatz und rufen Sie danach an. Viel einfacher ist es, einfach zu verwenden new der beides tut, die Prototypenkette setzt und einen Initialisierungscode aufruft.

628voto

Shog9 Punkte 151504

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:

  1. 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.
  2. 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.

190voto

some Punkte 45857

Ich habe gerade einige Teile von Crockford das Buch " JavaScript: Die guten Seiten ". Ich habe das Gefühl, dass er alles, was ihn jemals gebissen hat, als schädlich betrachtet:

Über Schalter fallen durch:

Ich lasse niemals Schalterkoffer fallen zum nächsten Fall übergehen. Ich fand einmal einen Fehler in meinem Code, der durch einen unbeabsichtigtes Durchfallen unmittelbar nachdem ich eine energische Rede darüber gehalten hatte darüber gehalten hatte, warum Fall-Through manchmal nützlich ist. (Seite 97, ISBN 978-0-596-51774-8)

Über ++ und --:

Die Funktionen ++ (Inkrement) und -- (Dekrement) Operatoren sind dafür bekannt, dass sie zu schlechtem Code beitragen, indem sie zu übermäßige Trickserei. Sie sind nach nach einer fehlerhaften Architektur in Viren und andere Sicherheitslücken Bedrohungen. (Seite 122)

Über neu:

Wenn Sie vergessen, die neu Präfix beim Aufruf eines Konstruktors Funktion, dann este wird nicht an das neue Objekt gebunden. Traurig, este wird an das globale Objekt gebunden, so dass anstatt Ihr neues Objekt zu erweitern, werden Sie sich mit globalen Variablen. Das ist wirklich schlecht. Es gibt gibt es keine Kompilierwarnung, und es gibt keine Laufzeit-Warnung. (Seite 49)

Es gibt noch mehr, aber ich hoffe, Sie haben das Bild verstanden.

Meine Antwort auf Ihre Frage: Nein, es ist nicht schädlich. aber wenn man vergisst, es zu benutzen, wenn man es sollte, könnte man Probleme bekommen. Wenn man in einer guten Umgebung entwickelt, merkt man das.

In der 5. Ausgabe von ECMAScript gibt es Unterstützung für strenger Modus . Im strengen Modus, this ist nicht mehr an das globale Objekt gebunden, sondern an undefined .

93voto

AnthonyWJones Punkte 182582

Da JavaScript eine dynamische Sprache ist, gibt es unzählige Möglichkeiten, Fehler zu machen, die man in einer anderen Sprache nicht machen würde.

Der Verzicht auf ein grundlegendes Sprachmerkmal wie new Das ist in etwa so, als würde man seine neuen, glänzenden Schuhe ausziehen, bevor man durch ein Minenfeld läuft, nur weil man befürchtet, dass die Schuhe schlammig werden könnten.

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 sehr überzeugender visueller Hinweis darauf, dass die "Syntax" falsch ist:

var o = MyClass();  // This is clearly wrong.

Darüber hinaus sind gute Namensgebungsgewohnheiten hilfreich. Schließlich tun Funktionen Dinge und sollten daher ein Verb in ihrem Namen haben, während Klassen Objekte darstellen und Substantive und Adjektive ohne Verb sind.

var o = chair() // Executing chair is daft.
var o = createChair() // Makes sense.

Es ist interessant, wie die Syntaxfärbung von Stack Overflow den obigen Code interpretiert hat.

42voto

Conrad Punkte 703

Ich bin ein Neuling in JavaScript, also bin ich vielleicht nicht zu erfahren, um einen guten Standpunkt zu diesem Thema einzunehmen. Dennoch möchte ich meine Sicht auf diese "neue" Sache zu teilen.

Ich komme aus der C#-Welt, in der die Verwendung des Schlüsselworts "new" so selbstverständlich ist, dass mir das Factory-Designmuster seltsam vorkommt.

Wenn ich zum ersten Mal in JavaScript programmiere, weiß ich nicht, dass es das Schlüsselwort "new" gibt und Code wie der in YUI Muster 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 mir den Code ansehe, den ich geschrieben habe. Noch chaotischer ist, dass ich beim "Trockenlauf" des Codes nicht wirklich zwischen den Grenzen der Objektinstanzen wechseln kann.

Dann fand ich das Schlüsselwort "neu", das für mich die Dinge "trennt". Mit dem neu Schlüsselwort, es schafft Dinge. Ohne das neu Schlüsselwort, weiß ich, dass ich es nicht mit der Erstellung von Dingen verwechseln werde, es sei denn, die Funktion, die ich aufrufe, gibt mir starke Hinweise darauf.

Zum Beispiel, mit var bar=foo(); Ich habe keine Anhaltspunkte dafür, was bar könnte möglicherweise sein.... Handelt es sich um einen Rückgabewert oder um ein neu erstelltes Objekt? Aber mit var bar = new foo(); Ich bin mir sicher, dass bar ist ein Objekt.

40voto

PEZ Punkte 16398

Ein weiterer Fall für neu ist, was ich als Pooh-Codierung . Winnie-the-Pooh folgt seinem Bauch. Ich sage los mit die Sprache, die Sie verwenden, nicht contra es.

Die Chancen stehen gut, dass die Betreuer der Sprache die Sprache für die Idiome optimieren, die sie zu fördern versuchen. Wenn sie ein neues Schlüsselwort in die Sprache aufnehmen, halten sie es wahrscheinlich für sinnvoll, bei der Erstellung einer neuen Instanz klar zu sein.

Code, der den Intentionen der Sprache folgt, wird mit jeder neuen Version effizienter. Und Code, der die Schlüsselkonstrukte der Sprache vermeidet, wird mit der Zeit leiden.

Und das geht weit über die Leistung hinaus. Ich kann gar nicht mehr zählen, wie oft ich gehört (oder gesagt) habe: "Warum zum Teufel haben sie das gemacht? dass ?", wenn man seltsam aussehenden Code findet. Oft stellt sich heraus, dass es zu der Zeit, als der Code geschrieben wurde, einen "guten" Grund dafür gab. Das Tao der Sprache zu befolgen ist die beste Versicherung dafür, dass Ihr Code in einigen Jahren nicht lächerlich gemacht wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X