2013-03-20 14 views

risposta

121

Penso che non siano equivalenti. Se non sbaglio, {}.constructor.prototype == Object.prototype mentre Object.create(null) non eredita da nessuna parte e quindi non ha proprietà.

In altre parole: un oggetto javascript eredita da Object di default, a meno che non lo si crei esplicitamente specificando null come prototipo, come in Object.create(null).

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


In Chrome DevTool si può vedere che non hanno Object.create(null)__proto che {} hanno.

enter image description here

81

sono sicuramente non equivalenti. Sto scrivendo questa risposta per spiegare in modo più completo perché fa la differenza.

  1. var p = {};

    crea un oggetto che eredita le proprietà ei metodi da Object.

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

    Crea un oggetto che non eredita nulla.

Se si utilizza un oggetto come una mappa, e si crea un oggetto utilizzando il metodo 1 di cui sopra, allora dovete essere molto attenti quando si fa le ricerche nella mappa. Poiché le proprietà e i metodi da Object sono ereditati, il codice può essere eseguito in un caso in cui ci sono chiavi nella mappa che non hai mai inserito. Ad esempio, se hai effettuato una ricerca su toString, avresti trovato una funzione, anche se non hai mai inserito quel valore lì. È possibile risolvere che 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, sarà semplicemente ignorare la funzione ereditata toString su p.

Si noti che non si può solo fare p.hasOwnProperty('toString') perché si può avere inserito un tasto "hasOwnProperty" in p, così abbiamo costringerlo a utilizzare l'implementazione in Object.

D'altra parte, se si utilizza il metodo 2 sopra, non sarà necessario preoccuparsi di cose da Object visualizzate nella mappa.

Non è possibile verificare l'esistenza di una proprietà con un semplice if come questo:

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

Il valore potrebbe essere una stringa vuota, potrebbe essere false, o null o undefined o 0, oppure NaN, ecc. Per verificare se esiste una proprietà, è comunque necessario utilizzare Object.prototype.hasOwnProperty.call(p, someKey).

+2

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

+2

@mrcrowl Solo se hanno usato 'Object.create (null)'. Preferisco non fare supposizioni del genere, anche se avessi assolutamente ragione che usasse 'Object.create (null)', il codice potrebbe cambiare, l'oggetto potrebbe essere sostituito con uno che eredita 'Object' ad un certo punto. 'hasOwnProperty' funziona sempre. – doug65536

+0

Ritengo che fare attenzione a qualcosa del genere non sia necessario.Apprezzo la tua risposta, ma la documentazione dovrebbe darti l'API necessaria per lavorare con qualunque codice tu stia lavorando. Se stai catturando del codice casuale da github, allora puoi forkarlo ed essere al sicuro da aggiornamenti meno documentati. Per non parlare di '{}' è molto più diffuso di 'Object.create (null)', che se a questo punto il tuo codice cattura accidentalmente una proprietà ereditata, è probabile che ci siano molti più bug di cui preoccuparsi. Posso vedere solo le persone che usano Object.create (null) come ottimizzazione minore. – aaaaaa

1

Se qualcuno sta cercando di implementare Object.create (null), solo per sapere come funziona. È stato scritto usando proto che 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: ho scritto questo, per curiosità, ed è scritto solo in termini semplici, per esempio, non sto trasferendo i descrittori di proprietà dal secondo oggetto all'oggetto di ritorno.

+1

Nota che dal rilascio di ECMAScript in estate, '__proto__' ora [ufficialmente] (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-__proto__-property-names-in-object- inizializzatori) essere parte della lingua. – Chiru

+1

Perché '-1' in' arguments.length> 0? Argomenti [0]: - 1; '? –

+0

@happy_marmoset risposta tardiva, ma sembra che sia solo un segnaposto non nullo in modo che il prototipo 'Object' venga mantenuto se non viene fornito il primo argomento. I nomi variabili potrebbero essere molto meglio qui. –

0

Mi piacerebbe fare riferimento al documento Mozilla su Objects and maps compared qui per dare a Map un'opportunità come una pratica migliore al giorno d'oggi.

Objects sono simili a Maps in quanto entrambi consentono di impostare chiavi di valori, recuperare quei valori, eliminare le chiavi, e di rilevare se qualcosa è memorizzato in una chiave. Per questo motivo (e poiché non esistevano alternative integrate), Objects sono stati utilizzati come Maps storicamente; tuttavia, ci sono differenze importanti che fanno utilizzando un Map preferibile in alcuni casi:

  • Le chiavi di Object sono stringhe e simboli, mentre possono essere qualsiasi valore per una Map, comprese funzioni, oggetti, e qualsiasi primitivo.
  • È possibile ottenere facilmente le dimensioni di un Map con la proprietà size, mentre il numero di proprietà in un Object deve essere determinato manualmente.
  • A Map A è un iterabile e può quindi essere ripetuto direttamente, mentre l'iterazione su un Object richiede di ottenere le sue chiavi in ​​qualche modo e iterando su di esse.
  • Un Object ha un prototipo, quindi ci sono chiavi di default nella mappa che potrebbero entrare in collisione con le vostre chiavi se non state attenti. A partire da ES5 questo può essere bypassato usando map = Object.create(null), ma raramente viene eseguito.
  • A Map A può offrire prestazioni migliori in caso di aggiunta frequente e rimozione di coppie di chiavi.
Problemi correlati