eliminar ax vs ax = indefinido

138

¿Hay alguna diferencia sustancial en hacer cualquiera de estos?

delete a.x;

vs

a.x = undefined;

dónde

a = {
    x: 'boo'
};

¿se podría decir que son equivalentes?

(No estoy teniendo en cuenta cosas como "delete Me gusta V8 no usar mejor" )

bevacqua
fuente
2
El operador de eliminación elimina una propiedad por completo. Establecer una propiedad como indefinida elimina el valor. Establecer una propiedad en nulo cambia el valor al valor nulo. Aquí hay una prueba de rendimiento
j08691
1
@ j08691 Nit: no elimina el valor. Se asigna undefinedcomo el valor, que sigue siendo un ..
Debe hablar sobre por qué le importa esto, entonces la respuesta puede satisfacer su problema real.
Juan Mendes

Respuestas:

181

No son equivalentes. La principal diferencia es esa configuración

a.x = undefined

significa que a.hasOwnProperty("x")aún devolverá verdadero, y por lo tanto, todavía se mostrará en un for inbucle, y enObject.keys()

delete a.x

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

La forma en que son iguales es que no se puede saber si existe una propiedad mediante pruebas

if (a.x === undefined)

Lo que no debe hacer si está tratando de determinar si existe una propiedad, siempre debe usar

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

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

Seguir la cadena de prototipos (mencionada por zzzzBov ) Llamar deletele permitirá subir la cadena de prototipos, mientras que establecer el valor en indefinido no buscará la propiedad en los prototipos encadenados 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

Eliminar propiedades heredadas Si la propiedad que está intentando eliminar es heredada, deleteno la afectará. Es decir, deletesolo elimina propiedades del objeto en sí, no propiedades heredadas.

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

Por lo tanto, si necesita asegurarse de que el valor de un objeto no esté definido, deleteno funcionará cuando se herede la propiedad, tendrá que establecerlo (anularlo) undefineden ese caso. A menos que se use el lugar que lo está comprobando hasOwnProperty, pero probablemente no sería seguro suponer que en todas partes que lo verifique se usaráhasOwnProperty

Juan mendes
fuente
1
"x" in aTambién volverá truecon el primero y falsecon el segundo. La salida de Object.keystambién será diferente.
solitario
¿Por qué declaras que no debería verificar si no está definido? me parece bastante razonable
bevacqua
@Nico Porque eso no te dirá si existe una propiedad. No digo que nunca lo uses. Pero si está buscando undefined, también puede verificar if (a.x), a menos que sea para números y 0 sea válido
Juan Mendes
33

Parafraseando la pregunta:

¿Son delete a.xy a.x = undefinedequivalentes?

No.

El primero elimina la clave de la variable, el segundo establece la clave con un valor de undefined. Esto marca la diferencia cuando se itera sobre las propiedades de los objetos y cuando hasOwnPropertyse usa.

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

Además, esto hará una diferencia significativa cuando la cadena de prototipos esté involucrada.

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
fuente
2
+1 Gran punto sobre deletepermitirle subir a la cadena de prototipos
Juan Mendes
4

Si a.xes una función de establecimiento, a.x = undefinedllamará a la función mientras delete a.xque no la llamará.

martin770
fuente
3

Sí, hay una diferencia. Si usa delete a.xla x ya no es una propiedad de a, pero si la usa a.x=undefinedes una propiedad pero su valor no está definido.


fuente
2

Los nombres son un poco confusos. a.x = undefinedsolo establece la propiedad en undefined, pero la propiedad sigue ahí:

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

delete en realidad lo elimina:

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

Este REPL del nodo debería ilustrar la diferencia.

> 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
fuente
1

Estoy seguro de que puedes ver la diferencia entre var o1 = {p:undefined};y var o2 = {};.

En ambos casos, o.pserá , undefinedpero en el primer caso, es porque ese es el valor y en el segundo caso porque no hay valor .

deletees el operador que le permite obtener a partir de o1(u otro objeto que tiene un valor asignado a su ppropiedad) para o2de esa manera: delete o1.p;.

La operación inversa se realiza simplemente asignando un valor ( undefineden este ejemplo, pero podría ser otra cosa) a la propiedad o1.p = undefined;.

Entonces no , no son equivalentes.


delete o.p; será

  • eliminar la propiedad pdel objeto si tiene uno

  • no hacer nada de otra manera

o.p = undefined; será

  • agregue una propiedad pal objeto si aún no tiene una y establezca su valor enundefined

  • simplemente cambie el valor de la propiedad si el objeto ya lo tiene


Desde una perspectiva de rendimiento, deletees malo porque modifica la estructura del objeto (al igual que agregar una nueva propiedad si no lo ha inicializado en el constructor).

Mientras que establecer el valor para undefinedliberar el contenido también, pero sin obligar a modificar la estructura.

xavierm02
fuente
1

El objeto es simplemente una representación en árbol, es decir, en la memoria, la raíz apunta a varias ubicaciones de memoria donde se almacenan las claves de ese objeto. y esa ubicación apunta a otra ubicación donde se almacena el valor real de esa clave, o ubicaciones donde se almacenan las claves secundarias o ubicaciones donde se almacenan los valores de la matriz.

Cuando elimina cualquier clave de un objeto usando delete, en realidad elimina el enlace entre esa clave y su objeto principal y las ubicaciones de memoria de la clave y su valor se liberan para almacenar otra información.

Cuando intenta eliminar cualquier clave configurando undefined como su valor, simplemente está configurando su valor, no eliminando esa clave. Eso significa que la ubicación de la memoria de claves todavía está vinculada con su objeto principal y el valor si la clave no está definida.

Usar una palabra clave indefinida en lugar de eliminar es una mala práctica, ya que no libera la ubicación de memoria de esa clave.

Incluso si la clave no está presente, y la configura como indefinida, esa clave se creará con valor undefined.

p.ej

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

eliminar no se puede trabajar con propiedades heredadas porque esa propiedad no es parte de ese objeto secundario.

Laxmikant Dange
fuente
1
Tenga en cuenta que los motores más nuevos prefieren que no elimine las claves, porque cuando lo hace, el motor necesita crear una nueva clase para él y actualizarlo siempre que se haga referencia a la "clase".
Juan Mendes
@JuanMendes, ¿Puedes dar alguna referencia por favor?
Laxmikant Dange
3
Consulte ¿El uso de la palabra clave delete afecta las optimizaciones v8 de un objeto? TL; DR as a general rule of thumb, using 'delete' makes thing slower.y 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. , y finalmente smashingmagazine.com/2012/11/…
Juan Mendes
1

Usando una matriz, en lugar de un objeto, puedo mostrar que eliminar usa menos memoria de almacenamiento dinámico que indefinido.

Por ejemplo, este código no terminará:

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 este error:

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

Entonces, como puede ver, en undefinedrealidad ocupa memoria de montón.

Sin embargo, si también deleteutiliza el elemento ary (en lugar de simplemente configurarlo undefined), el código terminará 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}.`);

Estos son ejemplos extremos, pero señalan deleteque no he visto a nadie mencionar en ningún lado.

Lonnie Best
fuente