Creazione di un oggetto JS con Object.create (null)?


150

Conosco molti modi per creare oggetti JS ma non conoscevo Object.create(null)quello.

Domanda:

è esattamente lo stesso di:

var p = {}

vs

var p2 = Object.create(null);

?

Risposte:


199

Non sono equivalenti. {}.constructor.prototype == Object.prototypementre Object.create(null)non eredita da nulla e quindi non ha alcuna proprietà.

In altre parole: un oggetto JavaScript eredita da oggetto per impostazione predefinita, a meno che non si crea esplicitamente con null come il suo prototipo, come: Object.create(null).

{}sarebbe invece equivalente a Object.create(Object.prototype).


In Chrome Devtool puoi vedere che Object.create(null)non ha __proto__proprietà, mentre lo {}fa.

inserisci qui la descrizione dell'immagine


99

Non sono assolutamente equivalenti. Sto scrivendo questa risposta per spiegare meglio perché fa la differenza.

  1. var p = {};

    Crea un oggetto che eredita le proprietà e i metodi da Object.

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

    Crea un oggetto che non eredita nulla.

Se stai usando un oggetto come mappa e crei un oggetto usando il metodo 1 sopra, devi fare molta attenzione quando esegui ricerche nella mappa. Poiché le proprietà e i metodi di Objectsono ereditati, il codice potrebbe incorrere in un caso in cui nella mappa sono presenti chiavi che non sono mai state inserite. Ad esempio, se si eseguisse una ricerca toString, si troverà una funzione, anche se non si inserisce mai quel valore lì. Puoi aggirare questo in questo modo:

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

Si noti che è bene assegnare qualcosa a p.toString, semplicemente sostituirà la toStringfunzione ereditata su p.

Nota che non puoi semplicemente farlo p.hasOwnProperty('toString')perché potresti aver inserito una chiave "hasOwnProperty" in p, quindi lo forziamo a usare l'implementazione in Object.

D'altra parte, se usi il metodo 2 sopra, non dovrai preoccuparti che le cose Objectappaiano nella mappa.

Non puoi verificare l'esistenza di una proprietà con un semplice ifcome questo:

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

Il valore potrebbe essere una stringa vuota, potrebbe essere false, oppure nulloppure oppure oppure undefinedoppure 0oppure NaN, ecc. Per verificare l'esistenza di una proprietà, è comunque necessario utilizzarla Object.prototype.hasOwnProperty.call(p, someKey).


6
Un'alternativa più semplice per verificare l'esistenza di una proprietà è:if (someKey in p) {
mrcrowl

2
@mrcrowl Solo se utilizzati Object.create(null). Preferisco non fare ipotesi del genere, anche se avessi assolutamente ragione Object.create(null), il codice potrebbe cambiare, l'oggetto potrebbe essere sostituito con uno che eredita Objectad un certo punto. hasOwnPropertyfunziona sempre.
doug65536,

1
Sento che fare attenzione a qualcosa del genere non dovrebbe essere necessario. Apprezzo la tua risposta, ma la documentazione dovrebbe darti l'api necessario per lavorare con qualunque codice tu stia lavorando. Se stai afferrando del codice casuale da github, puoi forkarlo ed essere al sicuro da aggiornamenti meno documentati. Per non parlare del fatto che {}è molto più diffuso che Object.create(null), se il tuo codice prende accidentalmente una proprietà ereditata a questo punto, probabilmente avrai bug molto più grandi di cui preoccuparti. Vedo solo le persone che usano Object.create (null) come un'ottimizzazione minore.
aaaaaa,

La doppia negazione !!p[key]funziona bene Object.create(null). Ma hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)non è neanche male
andreid

> Nota che non puoi semplicemente fare p.hasOwnProperty ('toString') perché potresti aver inserito una chiave "hasOwnProperty" in p, quindi lo forziamo a usare l'implementazione in Object. Questo non è necessario. In questo caso, non è possibile utilizzare alcun metodo pperché ogni metodo potrebbe essere inserito e quindi non essere sicuro.
Xianshenglu,

1

La creazione di oggetti mediante l'utilizzo {}creerà un oggetto il cui prototipo è Object.prototypeche eredita le funzioni di base dal Objectprototipo, mentre la creazione di oggetti mediante l'utilizzo Object.create(null)creerà un oggetto vuoto il cui prototipo è nullo.


0

Se qualcuno sta cercando l'implementazione Object.create(null), solo per sapere come funziona. È scritto usando un __proto__metodo non standard e quindi non lo consiglio .

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;
}

Nota : l'ho scritto per curiosità ed è scritto solo in termini semplici, ad esempio, non trasferisco i descrittori di proprietà dal secondo oggetto all'oggetto return.


1
Si noti che a partire dal rilascio di ECMAScript in estate, __proto__diventerà ufficialmente parte della lingua.
Chiru,

1
Perché -1dentro arguments.length>0?arguments[0]:-1;?
happy_marmoset,

Risposta ritardata di @happy_marmoset, ma sembra che sia solo un segnaposto non nullo, in modo che il Objectprototipo venga mantenuto se non viene fornito il primo argomento. I nomi delle variabili potrebbero essere molto meglio qui.
Mike Hill,

Inoltre, il secondo parametro dovrebbe descrivere la proprietà descrittori piuttosto che le proprietà effettive. Vedi riferimento qui: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Mike Hill

0

Quando si crea un oggetto con Object.create (null) significa che si sta creando un oggetto senza prototipo. null qui significa fine della catena del prototipo. Tuttavia, quando si crea un oggetto come {} verrà aggiunto il prototipo di oggetto. Quindi questi sono due oggetti diversi, uno con prototipo un altro senza prototipo. Spero che questo aiuti

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.