delete ax vs ax = indefinido

138

Existe alguma diferença substancial em fazer um desses?

delete a.x;

vs

a.x = undefined;

Onde

a = {
    x: 'boo'
};

poderia-se dizer que eles são equivalentes?

(Não estou levando em consideração coisas como "V8 gosta de não usar deletemelhor" )

bevacqua
fonte
2
O operador de exclusão remove uma propriedade completamente. Definir uma propriedade como indefinida remove o valor. Definir uma propriedade como nula altera o valor para o valor nulo. Aqui está um teste de desempenho, se você gosta: jsperf.com/delete-vs-undefined-vs-null/3 #
j08691
1
@ j08691 Nit: Não remove o valor. Ele atribui undefinedcomo o valor, que ainda é ..
Você deve falar sobre por que se importa com isso, então a resposta pode atender ao seu problema real.
Juan Mendes

Respostas:

181

Eles não são equivalentes. A principal diferença é que a configuração

a.x = undefined

significa que a.hasOwnProperty("x")ainda retornará verdadeiro e, portanto, ainda aparecerá em um for inloop e emObject.keys()

delete a.x

significa que a.hasOwnProperty("x")retornará falso

A maneira como eles são iguais é que você não pode dizer se existe uma propriedade testando

if (a.x === undefined)

O que você não deve fazer se estiver tentando determinar se existe uma propriedade, sempre use

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

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

Após a cadeia de protótipos (mencionada por zzzzBov ) A chamada deletepermitirá que ela suba a cadeia de protótipos, enquanto definir o valor como indefinido não procurará a propriedade nos protótipos encadeados 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

Exclusão de propriedades herdadas Se a propriedade que você está tentando excluir for herdada, deletenão a afetará. Ou seja, deletesomente exclui propriedades do próprio objeto, não propriedades herdadas.

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

Portanto, se você precisar garantir que o valor de um objeto seja indefinido, deletenão funcionará quando a propriedade for herdada, será necessário configurá-la (substituí-la) undefinednesse caso. A menos que o local que está verificando ele use hasOwnProperty, mas provavelmente não seria seguro supor que em todos os lugares que o verifiquemhasOwnProperty

Juan Mendes
fonte
1
"x" in atambém retornará truecom o primeiro e falsecom o segundo. A saída de Object.keystambém será diferente.
Loneomeday
por que você declara que não devo procurar indefinido? parece bastante razoável para mim.
Bevacqua
@ Nico Porque isso não informa se existe uma propriedade. Não estou dizendo que nunca o use. Mas se você está verificando undefined, assim como você pode apenas verificar if (a.x), a menos que seja para números e 0 é válido
Juan Mendes
33

Parafraseando a pergunta:

São delete a.xe a.x = undefinedequivalentes?

Não.

O primeiro remove a chave da variável, o posterior define a chave com um valor de undefined. Isso faz a diferença ao iterar sobre as propriedades dos objetos e quando hasOwnPropertyé usado.

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

Além disso, isso fará uma diferença significativa quando a cadeia de protótipos estiver envolvida.

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'
zzzzBov
fonte
2
+1 Grande ponto sobre deletepermitindo-lhe subir a cadeia de protótipos
Juan Mendes
4

Se a.xfor uma função setter, a.x = undefinedchamará a função enquanto delete a.xnão chamará a função.

martin770
fonte
3

Sim, há uma diferença. Se você usar delete a.xx não é mais uma propriedade de a, mas se você usar a.x=undefined, é uma propriedade, mas seu valor é indefinido.


fonte
2

Os nomes são um pouco confusos. a.x = undefinedapenas define a propriedade como undefined, mas a propriedade ainda está lá:

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

delete realmente o exclui:

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

Este REPL do nó deve ilustrar a diferença.

> 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
kojiro
fonte
1

Tenho certeza que você pode ver a diferença entre var o1 = {p:undefined};evar o2 = {}; .

Nos dois casos, o.pserá , undefinedmas no primeiro caso, é porque esse é o valor e, no segundo caso, porque não há valor .

deleteé o operador que permite obter o1(ou outro objeto que tenha um valor atribuído à sua ppropriedade) o2dessa maneira:delete o1.p; .

A operação reversa é feita simplesmente atribuindo um valor ( undefinedneste exemplo, mas poderia ser outra coisa) à propriedadeo1.p = undefined; .

Então não , eles não são equivalentes.


delete o.p; vai

  • remova a propriedade pdo objeto se ele tiver um

  • não faça nada de outra maneira

o.p = undefined; vai

  • adicione uma propriedade pao objeto se ele ainda não tiver uma e defina seu valor comoundefined

  • basta alterar o valor da propriedade se o objeto já a possuir


Do ponto de vista do desempenho, deleteé ruim porque modifica a estrutura do objeto (como adicionar uma nova propriedade se você não a inicializou no construtor).

Considerando que definir o valor para undefinedliberar o conteúdo também, mas sem forçar a modificar a estrutura.

xavierm02
fonte
1

Objeto é simplesmente uma representação em árvore, ou seja, na memória a raiz aponta para vários locais de memória onde as chaves desse objeto são armazenadas. e esse local aponta para outro local onde o valor real dessa chave está armazenado, ou locais onde as chaves filho são armazenadas ou locais onde os valores da matriz são armazenados.

Quando você exclui qualquer chave de um objeto usando delete, na verdade, ele exclui o link entre essa chave e seu objeto pai e os locais de memória da chave e seu valor são liberados para armazenar outras informações.

Quando você tenta excluir qualquer chave definindo indefinido como seu valor, está apenas definindo seu valor, não excluindo essa chave. Isso significa que o local da memória das chaves ainda está vinculado ao seu objeto pai e ao valor se a chave estiver indefinida.

Usar indefinido em vez de excluir a palavra-chave delete é uma prática ruim, pois não libera o local da memória dessa chave.

Mesmo que a chave não esteja presente e você a defina como indefinida, ela será criada com valor undefined.

por exemplo

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

A exclusão não pode ser trabalhada com propriedades herdadas porque essa propriedade não faz parte do objeto filho.

Laxmikant Dange
fonte
1
Observe que os mecanismos mais recentes preferem que você não exclua as chaves, porque, quando o faz, precisa criar uma nova classe para ele e atualizá-lo onde quer que a "classe" tenha sido referenciada.
Juan Mendes
@ JuanMendes, você pode dar qualquer referência, por favor.
Laxmikant Dange
3
Consulte O uso da palavra-chave delete afeta as otimizações da v8 de um objeto? TL; DR as a general rule of thumb, using 'delete' makes thing slower.e developers.google.com/v8/design e 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., finalmente, smashingmagazine.com/2012/11/…
Juan Mendes
1

Usando uma matriz, em vez de um objeto, posso mostrar que a exclusão usa menos memória heap do que o indefinido.

Por exemplo, este código não será concluído:

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

Produz este erro:

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

Então, como você pode ver, undefinedna verdade, ocupa memória de pilha.

No entanto, se você também deleteo item ário (em vez de apenas configurá-lo como undefined), o código será concluído 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}.`);

Estes são exemplos extremos, mas eles enfatizam deleteque nunca vi ninguém mencionar em lugar algum.

Lonnie Best
fonte