elimina ax vs ax = non definito


138

C'è qualche differenza sostanziale nel fare uno di questi?

delete a.x;

vs

a.x = undefined;

dove

a = {
    x: 'boo'
};

si potrebbe dire che sono equivalenti?

(Non sto prendendo in considerazione cose come "V8 like non usano deletemeglio" )


2
L'operatore delete rimuove completamente una proprietà. L'impostazione di una proprietà su indefinito rimuove il valore. L'impostazione di una proprietà su null modifica il valore sul valore null. Ecco un test perf se ti piace: jsperf.com/delete-vs-undefined-vs-null/3
j08691

1
@ j08691 Nit: non rimuove il valore. Assegna undefinedcome valore, che è ancora un ..

Dovresti parlare del perché ti preoccupi di questo, quindi la risposta può soddisfare il tuo vero problema.
Juan Mendes,

Risposte:


181

Non sono equivalenti. La differenza principale è quella impostazione

a.x = undefined

significa che a.hasOwnProperty("x")tornerà comunque vero, e quindi, apparirà comunque in un for inciclo, e dentroObject.keys()

delete a.x

significa che a.hasOwnProperty("x")restituirà false

Il modo in cui sono uguali è che non è possibile stabilire se esiste una proprietà testando

if (a.x === undefined)

Cosa che non dovresti fare se stai cercando di determinare se esiste una proprietà, dovresti sempre usarla

// If you want inherited properties
if ('x' in a)

// If you don't want inherited properties
if (a.hasOwnProperty('x'))

Seguendo la catena di prototipi (menzionata da zzzzBov ) Calling deleteconsentirà di risalire la catena di prototipi, mentre l'impostazione del valore su indefinito non cercherà la proprietà nei prototipi concatenati http://jsfiddle.net/NEEw4/1/

var obj = {x: "fromPrototype"};
var extended = Object.create(obj);
extended.x = "overriding";
console.log(extended.x); // overriding
extended.x  = undefined;
console.log(extended.x); // undefined
delete extended.x;
console.log(extended.x); // fromPrototype

Eliminazione delle proprietà ereditate Se la proprietà che si sta tentando di eliminare viene ereditata, deletenon influirà su di essa. Cioè, deleteelimina solo le proprietà dall'oggetto stesso, non le proprietà ereditate.

var obj = {x: "fromPrototype"};
var extended = Object.create(obj);
delete extended.x;
console.log(extended.x); // Still fromPrototype

Pertanto, se è necessario assicurarsi che il valore di un oggetto sia indefinito, deletenon funzionerà quando la proprietà viene ereditata, è necessario impostarlo (sovrascriverlo) undefinedin quel caso. A meno che non venga utilizzato il luogo che lo sta controllando hasOwnProperty, ma probabilmente non sarebbe sicuro presumere che verrà utilizzato dappertuttohasOwnProperty


1
"x" in atornerà anche truecon il primo e falsecon il secondo. Anche l'output di Object.keyssarà diverso.
lunedì

perché affermi che non dovrei controllare se non definito? mi sembra abbastanza ragionevole.
Bevacqua,

@Nico Perché questo non ti dirà se esiste una proprietà. Non sto dicendo di non usarlo mai. Ma se stai controllando undefined, puoi anche controllare if (a.x), a meno che non sia per numeri e 0 è valido
Juan Mendes,

33

Per parafrasare la domanda:

Sono delete a.xed a.x = undefinedequivalenti?

No.

Il primo rimuove la chiave dalla variabile, il successivo imposta la chiave con un valore di undefined. Questo fa la differenza quando si ripetono le proprietà degli oggetti e quando hasOwnPropertyviene utilizzato.

a = {
    x: true
};
a.x = undefined;
a.hasOwnProperty('x'); //true
delete a.x;
a.hasOwnProperty('x'); //false

Inoltre, ciò farà una differenza significativa quando è coinvolta la catena di prototipi.

function Foo() {
    this.x = 'instance';
}
Foo.prototype = {
    x: 'prototype'
};
a = new Foo();
console.log(a.x); //'instance'

a.x = undefined;
console.log(a.x); //undefined

delete a.x;
console.log(a.x); //'prototype'

2
+1 Ottimo punto su come deletepermettergli di salire sulla catena del prototipo
Juan Mendes,

4

Se a.xè una funzione setter, a.x = undefinedchiamerà la funzione mentre delete a.xnon chiamerà la funzione.


3

Sì, c'è differenza. Se usi delete a.xx non è più una proprietà di a, ma se la usi a.x=undefinedè una proprietà ma il suo valore non è definito.


2

I nomi sono un po 'confusi. a.x = undefinedimposta semplicemente la proprietà su undefined, ma la proprietà è ancora lì:

> var a = {x: 3};
> a.x = undefined;
> a.constructor.keys(a)
["x"]

delete lo elimina effettivamente:

> var a = {x: 3};
> delete a.x;
> a.constructor.keys(a)
[]

1

Questo REPL dal nodo dovrebbe illustrare la differenza.

> a={ x: 'foo' };
{ x: 'foo' }
> for (var i in a) { console.log(i); };
x
undefined
> a.x=undefined;
undefined
> for (var i in a) { console.log(i); };
x
undefined
> delete a.x;
true
> for (var i in a) { console.log(i); };
undefined

1

Sono sicuro che puoi vedere la differenza tra var o1 = {p:undefined};e var o2 = {};.

In entrambi i casi, o.psarà , undefinedma nel primo caso, è perché quello è il valore e nel secondo caso perché non c'è valore .

deleteè l'operatore che consente di ottenere da o1(o un altro oggetto che ha un valore assegnato alla sua pproprietà) a o2quel modo: delete o1.p;.

L'operazione inversa viene eseguita semplicemente assegnando un valore ( undefinedin questo esempio ma potrebbe essere qualcos'altro) alla proprietà o1.p = undefined;.

Quindi no , non sono equivalenti.


delete o.p; volere

  • rimuovere la proprietà pdall'oggetto se ne ha uno

  • non fare diversamente

o.p = undefined; volere

  • aggiungi una proprietà pall'oggetto se non ne ha ancora una e imposta il suo valore suundefined

  • cambia semplicemente il valore della proprietà se l'oggetto lo possiede già


Dal punto di vista delle prestazioni, deleteè un problema perché modifica la struttura dell'oggetto (proprio come aggiungere una nuova proprietà se non è stata inizializzata nel costruttore).

Mentre si imposta il valore per undefinedrilasciare anche il contenuto, ma senza forzare la modifica della struttura.


1

L'oggetto è semplicemente una rappresentazione ad albero, ciò significa che in memoria la radice punta a varie posizioni di memoria in cui sono memorizzate le chiavi di quell'oggetto. e tale posizione punta a un'altra posizione in cui è archiviato il valore effettivo di quella chiave o posizioni in cui sono memorizzate le chiavi figlio o posizioni in cui sono memorizzati i valori dell'array.

Quando si elimina una chiave da un oggetto utilizzando Elimina, in realtà elimina il collegamento tra quella chiave e l'oggetto principale e le posizioni di memoria della chiave e il suo valore vengono liberati per memorizzare un'altra informazione.

Quando si tenta di eliminare qualsiasi chiave impostando undefined come valore, quindi si sta semplicemente impostando il suo valore, non eliminando quella chiave. Ciò significa che la posizione della memoria delle chiavi è ancora collegata al suo oggetto padre e al valore se la chiave non è definita.

L'utilizzo di undefined anziché dell'eliminazione della parola chiave è una pratica errata, in quanto non rilascia la posizione di memoria di quella chiave.

Anche se la chiave non è presente e la si imposta come non definita, tale chiave verrà creata con valore undefined.

per esempio

var a = {};
a.d = undefined;
console.log(a); // this will print { d: undefined }

l'eliminazione non può essere eseguita con le proprietà ereditate perché quella proprietà non fa parte dell'oggetto figlio.


1
Nota che i motori più recenti preferiscono non eliminare le chiavi, perché quando lo fai il motore deve creare una nuova classe per esso e aggiornarla ovunque sia stata fatta riferimento alla "classe".
Juan Mendes,

@JuanMendes, puoi fare qualche riferimento per favore.
Laxmikant Dange

3
Vedere L'uso della parola chiave delete influisce sulle ottimizzazioni v8 di un oggetto? TL; DR as a general rule of thumb, using 'delete' makes thing slower.e developers.google.com/v8/design To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes. In V8, an object changes its hidden class when a new property is added. e infine smashingmagazine.com/2012/11/…
Juan Mendes

1

Usando un array, invece di un oggetto, posso mostrare che delete usa meno memoria heap di non definita.

Ad esempio, questo codice non finirà:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

Produce questo errore:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

Quindi, come puoi vedere, undefinedoccupa effettivamente memoria heap.

Tuttavia, se hai anche deletel'oggetto ary (invece di impostarlo su undefined), il codice finirà lentamente:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

Questi sono esempi estremi, ma sottolineano deleteche non ho visto nessuno menzionare da nessuna parte.

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.