JS-Objekt mit Object.create (null) erstellen?

150

Ich kenne viele Möglichkeiten, um JS-Objekte zu erstellen, aber ich kannte das nicht Object.create(null).

Frage:

ist es genau das gleiche wie:

var p = {}

vs.

var p2 = Object.create(null);

?

Royi Namir
quelle

Antworten:

199

Sie sind nicht gleichwertig. {}.constructor.prototype == Object.prototypewährend Object.create(null)erbt von nichts und hat daher überhaupt keine Eigenschaften.

Mit anderen Worten: Ein Javascript-Objekt erbt standardmäßig von Object, es sei denn, Sie erstellen es explizit mit null als Prototyp, z Object.create(null).

{}wäre stattdessen gleichbedeutend mit Object.create(Object.prototype).


In Chrome Devtool können Sie sehen, dass dies Object.create(null)keine __proto__Eigenschaft hat, während dies der {}Fall ist.

Geben Sie hier die Bildbeschreibung ein

Peter Herdenborg
quelle
99

Sie sind definitiv nicht gleichwertig. Ich schreibe diese Antwort, um genauer zu erklären, warum es einen Unterschied macht.

  1. var p = {};

    Erstellt ein Objekt, von dem die Eigenschaften und Methoden geerbt werden Object.

  2. var p2 = Object.create(null);

    Erstellt ein Objekt, das nichts erbt.

Wenn Sie ein Objekt als Karte verwenden und ein Objekt mit der obigen Methode 1 erstellen, müssen Sie beim Nachschlagen in der Karte besonders vorsichtig sein. Da die Eigenschaften und Methoden von Objectgeerbt werden, kann Ihr Code in einen Fall geraten, in dem die Karte Schlüssel enthält, die Sie nie eingefügt haben. Wenn Sie beispielsweise nachschlagen toString, finden Sie eine Funktion, obwohl Sie diesen Wert dort nie angegeben haben. Sie können das folgendermaßen umgehen:

if (Object.prototype.hasOwnProperty.call(p, 'toString')) {
    // we actually inserted a 'toString' key into p
}

Beachten Sie, dass es in Ordnung ist, etwas zuzuweisen p.toString, da es einfach die geerbte toStringFunktion überschreibt p.

Beachten Sie, dass Sie dies nicht einfach tun können, p.hasOwnProperty('toString')weil Sie möglicherweise einen Schlüssel "hasOwnProperty" eingefügt haben. Daher perzwingen wir, dass die Implementierung in verwendet wird Object.

Wenn Sie dagegen Methode 2 oben verwenden, müssen Sie sich keine Sorgen machen, dass Dinge Objectin der Karte angezeigt werden.

Mit einem einfachen ifBeispiel können Sie nicht prüfen, ob eine Eigenschaft vorhanden ist :

// Unreliable:
if (p[someKey]) {
    // ...
}

Der Wert kann eine leere Zeichenfolge sein false, oder nulloder oder oder undefinedoder 0oder NaNusw. Um zu überprüfen, ob überhaupt eine Eigenschaft vorhanden ist, müssen Sie diese noch verwenden Object.prototype.hasOwnProperty.call(p, someKey).

doug65536
quelle
6
Eine einfachere Alternative zur Überprüfung der Existenz einer Eigenschaft ist:if (someKey in p) {
Mrcrowl
2
@mrcrowl Nur wenn sie verwendet Object.create(null). Ich ziehe es vor Object.create(null), solche Annahmen nicht zu treffen, selbst wenn Sie absolut Recht hätten, dass sie verwendet werden , könnte sich der Code ändern, das Objekt könnte durch eines ersetzt werden, das Objectirgendwann erbt . hasOwnPropertyfunktioniert immer.
Doug65536
1
Ich bin der Meinung, dass es unnötig sein sollte, bei so etwas vorsichtig zu sein. Ich freue mich über Ihre Antwort, aber die Dokumentation sollte Ihnen die API geben, die Sie benötigen, um mit dem Code zu arbeiten, mit dem Sie arbeiten. Wenn Sie zufälligen Code von Github abrufen, können Sie ihn abspalten und vor weniger dokumentierten Updates sicher sein. Ganz zu schweigen davon, dass {}es so viel häufiger vorkommt Object.create(null), dass Sie wahrscheinlich größere Fehler befürchten müssen, wenn Ihr Code an dieser Stelle versehentlich eine geerbte Eigenschaft erfasst. Ich kann nur Leute sehen, die Object.create (null) als geringfügige Optimierung verwenden.
aaaaaa
Doppelte Verneinung !!p[key]funktioniert gut mit Object.create(null). hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)
Ist
> Beachten Sie, dass Sie p.hasOwnProperty ('toString') nicht einfach ausführen können, da Sie möglicherweise einen Schlüssel "hasOwnProperty" in p eingefügt haben. Daher erzwingen wir die Verwendung der Implementierung in Object. Das ist unnötig. In diesem Fall können Sie keine Methoden verwenden, pda jede Methode eingefügt werden kann und daher nicht sicher ist.
Xianshenglu
1

Durch das Erstellen von Objekten mithilfe von {}wird ein Objekt erstellt, dessen Prototyp Object.prototypedie Grundfunktionen des ObjectPrototyps erbt. Beim Erstellen von Objekten mithilfe von Object.create(null)wird ein leeres Objekt erstellt, dessen Prototyp null ist.

Praveen Kishor
quelle
0

Wenn jemand nach einer Implementierung sucht Object.create(null), nur um zu wissen, wie es funktioniert. Es ist so geschrieben, __proto__dass es nicht dem Standard entspricht, und daher empfehle ich es nicht .

function objectCreateMimic()
{
  /*optional parameters: prototype_object, own_properties*/
  var P = arguments.length>0?arguments[0]:-1;
  var Q = arguments.length>1?arguments[1]:null;
  var o = {};
  if(P!==null && typeof P === "object")
  {
    o.__proto__ = P;
  }
  else if(P===null)
  {
    o.__proto__ = null;
  }
  if(Q!==null && typeof Q === "object")
  {
   for(var key in Q)
   {
     o[key] = Q[key];
   }
  }
  return o;
}

Hinweis : Ich habe dies aus Neugier geschrieben und es ist nur in einfachen Worten geschrieben. Beispielsweise übertrage ich die Eigenschaftsbeschreibungen nicht vom zweiten Objekt auf das Rückgabeobjekt.

Aravind
quelle
1
Beachten Sie, dass ab der Veröffentlichung von ECMAScript im Sommer __proto__nun offiziell Teil der Sprache sein wird.
Chiru
1
Warum -1in arguments.length>0?arguments[0]:-1;?
happy_marmoset
@happy_marmoset späte Antwort, aber es sieht so aus, als wäre es nur ein Platzhalter ungleich Null, sodass der ObjectPrototyp beibehalten wird, wenn das erste Argument nicht angegeben wird. Variablennamen könnten hier viel besser sein.
Mike Hill
Auch sollte der zweite Parameter die Eigenschaft beschreibt Deskriptoren , anstatt die tatsächlichen Eigenschaften selbst. Siehe Referenz hier: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Mike Hill
0

Wenn Sie ein Objekt mit Object.create (null) erstellen, bedeutet dies, dass Sie ein Objekt ohne Prototyp erstellen. null bedeutet hier das Ende der Prototypkette. Wenn Sie jedoch ein Objekt wie {} erstellen, wird ein Objektprototyp hinzugefügt. Daher sind dies zwei verschiedene Objekte, eines mit Prototyp und eines ohne Prototyp. Hoffentlich hilft dies

user13624607
quelle