supprimer ax vs ax = indéfini


138

Y a-t-il une différence substantielle entre ces deux méthodes?

delete a.x;

contre

a.x = undefined;

a = {
    x: 'boo'
};

pourrait-on dire qu'ils sont équivalents?

(Je ne prends pas en compte des trucs comme "V8 aime ne pas utiliser deletemieux" )


2
L'opérateur de suppression supprime entièrement une propriété. La définition d'une propriété sur undefined supprime la valeur. La définition d'une propriété sur null change la valeur en valeur null. Voici un test de perf si vous aimez: jsperf.com/delete-vs-undefined-vs-null/3
j08691

1
@ j08691 Nit: Cela ne supprime pas la valeur. Il assigne undefinedcomme valeur, qui est toujours un ..

Vous devriez expliquer pourquoi vous vous souciez de cela, alors la réponse peut répondre à votre problème réel.
Juan Mendes

Réponses:


181

Ils ne sont pas équivalents. La principale différence est que le réglage

a.x = undefined

signifie que a.hasOwnProperty("x")cela retournera toujours vrai, et par conséquent, il apparaîtra toujours dans une for inboucle, et dansObject.keys()

delete a.x

signifie que a.hasOwnProperty("x")cela retournera faux

La façon dont ils sont identiques est que vous ne pouvez pas dire si une propriété existe en testant

if (a.x === undefined)

Ce que vous ne devriez pas faire si vous essayez de déterminer si une propriété existe, vous devez toujours utiliser

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

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

Suivre la chaîne de prototypes (mentionnée par zzzzBov ) L'appel lui deletepermettra de remonter la chaîne de prototypes, alors que définir la valeur sur undefined ne cherchera pas la propriété dans les prototypes enchaînés 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

Suppression des propriétés héritées Si la propriété que vous essayez de supprimer est héritée, deletene l'affectera pas. Autrement dit, deletesupprime uniquement les propriétés de l'objet lui-même, pas les propriétés héritées.

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

Par conséquent, si vous devez vous assurer que la valeur d'un objet ne sera pas définie, deletene fonctionnera pas lorsque la propriété sera héritée, vous devrez la définir (la remplacer) undefineddans ce cas. À moins que l'endroit qui le vérifie ne l'utilisera hasOwnProperty, mais il ne serait probablement pas prudent de supposer que partout où il vérifierahasOwnProperty


1
"x" in areviendra aussi trueavec le premier et falseavec le second. La sortie de Object.keyssera également différente.
lonesomeday

pourquoi dites-vous que je ne devrais pas vérifier si non défini? me semble assez raisonnable.
bevacqua

@Nico Parce que cela ne vous dira pas si une propriété existe. Je ne dis pas de ne jamais l'utiliser. Mais si vous vérifiez undefined, vous pouvez aussi simplement vérifier if (a.x), à moins que ce ne soit pour des nombres et que 0 soit valide
Juan Mendes

33

Pour paraphraser la question:

Sont delete a.xet a.x = undefinedéquivalents?

Non.

Le premier supprime la clé de la variable, le second définit la clé avec une valeur de undefined. Cela fait une différence lors de l'itération sur les propriétés des objets et quand hasOwnPropertyest utilisé.

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

De plus, cela fera une différence significative lorsque la chaîne de prototypes est impliquée.

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 Excellent point à propos de lui deletepermettre de remonter la chaîne de prototypes
Juan Mendes

4

Si a.xest une fonction de réglage, a.x = undefinedappellera la fonction tandis que delete a.xn'appellera pas la fonction.


3

Oui, il y a une différence. Si vous utilisez delete a.xle x n'est plus une propriété de a, mais si vous l'utilisez, a.x=undefinedc'est une propriété mais sa valeur n'est pas définie.


2

Les noms sont un peu déroutants. a.x = undefineddéfinit simplement la propriété sur undefined, mais la propriété est toujours là:

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

delete le supprime en fait:

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

1

Cette REPL du nœud devrait illustrer la différence.

> 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

Je suis sûr que vous pouvez voir la différence entre var o1 = {p:undefined};etvar o2 = {}; .

Dans les deux cas, o.psera undefinedmais dans le premier cas, c'est parce que c'est la valeur et dans le second cas parce qu'il n'y a pas de valeur .

deleteest l'opérateur qui vous permet d'aller de o1(ou d'un autre objet auquel une valeur est attribuée à sa ppropriété) vers o2cette manière:delete o1.p; .

L'opération inverse est effectuée en affectant simplement une valeur ( undefineddans cet exemple mais cela pourrait être autre chose) à la propriétéo1.p = undefined; .

Donc non , ils ne sont pas équivalents.


delete o.p; volonté

  • supprimer la propriété pde l'objet s'il en a une

  • ne rien faire autrement

o.p = undefined; volonté

  • ajouter une propriété pà l'objet s'il n'en a pas encore et définir sa valeur surundefined

  • changez simplement la valeur de la propriété si l'objet l'a déjà


Du point de vue des performances, deleteest mauvais car cela modifie la structure de l'objet (tout comme l'ajout d'une nouvelle propriété si vous ne l'avez pas initialisée dans le constructeur).

Alors que définir la valeur sur undefinedlibère également le contenu mais sans forcer à modifier la structure.


1

L'objet est simplement une représentation arborescente, ce qui signifie qu'en mémoire la racine pointe vers divers emplacements de mémoire où les clés de cet objet sont stockées. et cet emplacement pointe vers un autre emplacement où la valeur réelle de cette clé est stockée, ou des emplacements où les clés enfants sont stockées ou des emplacements où les valeurs de tableau sont stockées.

Lorsque vous supprimez une clé d'un objet à l'aide de delete, en fait, il supprime le lien entre cette clé et son objet parent et les emplacements mémoire de la clé et de sa valeur sont libérés pour stocker d'autres informations.

Lorsque vous essayez de supprimer une clé en définissant une valeur indéfinie, vous définissez simplement sa valeur, et non la suppression de cette clé. Cela signifie que l'emplacement de la mémoire des clés est toujours lié à son objet parent et à la valeur si la clé n'est pas définie.

Utiliser undefined au lieu d'utiliser le mot-clé de suppression est une mauvaise pratique, car cela ne libère pas l'emplacement mémoire de cette clé.

Même si la clé n'est pas présente et que vous la définissez comme non définie, cette clé sera créée avec une valeur undefined.

par exemple

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

delete ne peut pas être utilisé avec des propriétés héritées car cette propriété ne fait pas partie de cet objet enfant.


1
Notez que les moteurs plus récents préfèrent que vous ne supprimiez pas les clés, car lorsque vous le faites, le moteur doit créer une nouvelle classe pour elle et la mettre à jour là où la "classe" a été référencée.
Juan Mendes

@JuanMendes, pouvez-vous donner une référence s'il vous plaît.
Laxmikant Dange

3
Voir L'utilisation du mot-clé delete affecte-t - elle les optimisations v8 d'un objet? TL; DR as a general rule of thumb, using 'delete' makes thing slower.et développeurs.google.com 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. / v8
Juan Mendes

1

En utilisant un tableau, au lieu d'un objet, je peux montrer que la suppression utilise moins de mémoire de tas que non définie.

Par exemple, ce code ne se terminera pas:

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

Il produit cette erreur:

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

Donc, comme vous pouvez le voir, undefinedoccupe réellement de la mémoire.

Cependant, si vous avez également deletel'élément ary (au lieu de simplement le définir sur undefined), le code se terminera lentement:

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}.`);

Ce sont des exemples extrêmes, mais ils font remarquer deleteque je n'ai vu personne mentionner nulle part.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.