Suppression d'objets en JavaScript

359

Je suis un peu confus avec l' deleteopérateur de JavaScript . Prenez le morceau de code suivant:

var obj = {
    helloText: "Hello World!"
};

var foo = obj;

delete obj;

Une fois que ce morceau de code a été exécuté, objis null, mais foofait toujours référence à un objet exactement comme obj. Je suppose que cet objet est le même objet que celui fooindiqué.

Cela m'embrouille, car je m'attendais à ce que l'écriture delete objsupprime l'objet qui objpointait en mémoire - pas seulement la variable obj.

Est-ce parce que le garbage collector de JavaScript fonctionne sur une base de conservation / libération, de sorte que si je n'avais pas d'autres variables pointant vers l'objet, il serait supprimé de la mémoire?

(Au fait, mes tests ont été effectués dans Safari 4.)

Steve Harrison
la source
7
Pour votre référence. developer.mozilla.org/en/Core_JavaScript_1.5_Reference/…
Daniel A. White
Article complet sur le mot clé à supprimer webcache.googleusercontent.com/…
Vitim.us
2
Le lien ci-dessus devrait être: perfectionkills.com/understanding-delete
johnmdonahue
1
@Steve Harrison delete n'est pas pour supprimer un objet en javascript delete utiliser pour supprimer une clé d'objet dans votre cas l' var obj = { helloText: "Hello World!" }; var foo = obj; delete obj;objet n'est pas supprimé vérifier objsupprimer l'utilisation: delete obj.helloTextpuis vérifierfoo now foo is an empty object
Umair Ahmed
2
@UmairAhmed, traduction gratuite: "" " deleten'est pas pour supprimer des objets en javascript. deleteEst utilisé pour supprimer une clé d'objet. Dans votre cas var obj = { helloText: "Hello World!" }; var foo = obj; delete obj;, l'objet n'est pas supprimé. Vérifiez obj. Ensuite, exécutez delete obj.helloTextet vous pouvez voir que foomaintenant pointe vers un vide objet. "" "
Pacerier

Réponses:

448

L'opérateur de suppression supprime uniquement une référence, jamais un objet lui-même. S'il supprimait l'objet lui-même, les autres références restantes seraient suspendues, comme une suppression C ++. (Et accéder à l'un d'eux provoquerait un plantage. Pour les rendre tous nuls, cela signifierait avoir du travail supplémentaire lors de la suppression ou de la mémoire supplémentaire pour chaque objet.)

Étant donné que Javascript est récupéré, vous n'avez pas besoin de supprimer les objets eux-mêmes - ils seront supprimés lorsqu'il n'y aura plus aucun moyen de s'y référer.

Il peut être utile de supprimer les références à un objet si vous en avez terminé avec elles, car cela donne au garbage collector plus d'informations sur ce qui peut être récupéré. Si des références restent à un objet volumineux, cela peut entraîner sa non-récupération - même si le reste de votre programme n'utilise pas réellement cet objet.

Jesse Rusak
la source
23
Le deletemot-clé ne fonctionne que pour les propriétés d'un objet, pas pour les variables. perfectionkills.com/understanding-delete
Alex Mund
1
@AlexJM Oui, la prochaine réponse de Guffa (et ses commentaires) en discute en détail.
Jesse Rusak
1
Une propriété d'un objet peut être un autre objet. Par exemple; var obj = {a: {}}; delete obj.a;
Alex Mund
2
Mais ... les variables ne sont-elles pas réellement des propriétés de window?
RedClover
3
@Soaku pas des variables locales. (par exemple ceux déclarés avec var)
Jesse Rusak
162

La deletecommande n'a aucun effet sur les variables régulières, seulement sur les propriétés. Après la deletecommande, la propriété n'a pas de valeur null, elle n'existe plus du tout.

Si la propriété est une référence d'objet, la deletecommande supprime la propriété mais pas l'objet. Le garbage collector prendra soin de l'objet s'il n'y a pas d'autre référence.

Exemple:

var x = new Object();
x.y = 42;

alert(x.y); // shows '42'

delete x; // no effect
alert(x.y); // still shows '42'

delete x.y; // deletes the property
alert(x.y); // shows 'undefined'

(Testé dans Firefox.)

Guffa
la source
39
Si cela est exécuté dans la portée globale, votre xvariable devient juste une propriété sur l' windowobjet global et delete x;supprime vraiment la xvariable.
Crescent Fresh
18
@crescentfresh: Ce n'est une propriété que si elle est implicitement déclarée. Si elle est explicitement déclarée comme dans l'exemple, c'est une variable globale et ne peut pas être supprimée.
Guffa
4
@Tarynn: Je vois, c'est là que se situe le problème. Si vous le faites dans la console, pour une raison quelconque, xce ne sera pas une variable appropriée dans certains navigateurs, mais une propriété dans l' windowobjet. C'est bien sûr un problème avec la console, et ne reflète pas la façon dont le code est normalement exécuté.
Guffa
2
@Guffa Après un tas de recherches, je dois admettre que c'était probablement une bonne chose de ne pas avoir assez de représentants pour voter contre. Mes excuses les plus sincères et merci d'avoir pris le temps de me montrer ce qui s'est passé ... Voici une explication approfondie: perfectionkills.com/understanding-delete/#firebug_confusion
Tarynn
2
@chao: Je vois. Vous rencontrez le même problème que Tarynn (voir les commentaires précédents). Lorsque vous faites cela dans la console, cela ne fonctionne pas de la même manière que dans le code réel.
Guffa
56

"les variables déclarées implicitement" sont des propriétés de l'objet global, donc supprimez-les fonctionne comme elles fonctionnent sur n'importe quelle propriété. Les variables déclarées avec var sont indestructibles.

Alex
la source
53
Je n'ai jamais réalisé que var était si dur à cuire.
Gavin
1
C'est un excellent point, et un JS gotcha. Les gens s'habituent à supprimer les variables de fenêtre et se demandent ensuite pourquoi ils ne peuvent pas faire de même avec les variables locales.
welbornio
2
Il en va de même let.
Pacerier
4

delete n'est pas utilisé pour supprimer un objet dans le script Java.

deleteutilisé pour retirer un object keydans votre cas

var obj = { helloText: "Hello World!" }; 
var foo = obj;
delete obj;

l'objet n'est pas supprimé vérifier obj prendre toujours les mêmes valeurs supprimer l'utilisation:

delete obj.helloText

puis vérifiez obj, foo, les deux sont des objets vides.

Umair Ahmed
la source
2

Je viens de trouver un jsperf que vous pourriez considérer intéressant à la lumière de cette affaire. (il pourrait être utile de le garder pour compléter l'image)

Il compare la suppression , la définition de null et la définition d' undefined .

Mais gardez à l'esprit qu'il teste le cas lorsque vous supprimez / définissez la propriété plusieurs fois.

garek
la source
1

IE 5 à 8 a un bug où l'utilisation de la suppression sur les propriétés d'un objet hôte (Window, Global, DOM, etc.) lève TypeError "l'objet ne prend pas en charge cette action".

var el=document.getElementById("anElementId");
el.foo = {bar:"baz"};
try{
    delete el.foo;
}catch(){
    //alert("Curses, drats and double double damn!");
    el.foo=undefined; // a work around
}

Plus tard, si vous devez vérifier où la propriété a une signification pleine valeur, el.foo !== undefinedcar "foo" in el elle retournera toujours true dans IE.

Si vous avez vraiment besoin que la propriété disparaisse vraiment ...

function hostProxy(host){
    if(host===null || host===undefined) return host;
    if(!"_hostProxy" in host){
       host._hostproxy={_host:host,prototype:host};
    }
    return host._hostproxy;
}
var el=hostProxy(document.getElementById("anElementId"));
el.foo = {bar:"baz"};

delete el.foo; // removing property if a non-host object

si vous avez besoin d'utiliser l'objet hôte avec l'api hôte ...

el.parent.removeChild(el._host);
johndhutcheson
la source
1

Je suis tombé sur cet article dans ma recherche de cette même réponse. Ce que j'ai fini par faire, c'est simplement d'extraire obj.pop()toutes les valeurs / objets stockés dans mon objet afin que je puisse réutiliser l'objet. Je ne sais pas si c'est une mauvaise pratique ou non. Cette technique m'a été utile pour tester mon code dans les outils Chrome Dev ou la console Web FireFox.

Craig London
la source
1

Ce travail pour moi, bien que ce ne soit pas une bonne pratique. Il supprime simplement tous les éléments associés auxquels l'objet appartient.

 for (element in homeService) {
          delete homeService[element];
  }
sagar de vigne
la source
quelle est la meilleure pratique? Je me souviens avoir lu que l'opérateur de suppression n'était pas le meilleur moyen de supprimer des propriétés d'objet. Je crois que je l'ai lu dans le livre JavaScript de Crockford, mais je ne peux pas le creuser pour le moment.
zero_cool
0

Définir une variable pour nullvous assurer de rompre toutes les références aux objets dans tous les navigateurs, y compris les références circulaires établies entre les éléments DOM et les étendues Javascript. En utilisant la deletecommande, nous marquons les objets à effacer lors de la prochaine exécution de la récupération de place, mais s'il existe plusieurs variables référençant le même objet, la suppression d'une seule variable NE libérera PAS l'objet, cela supprimera simplement le lien entre cette variable et L'object. Et lors de la prochaine exécution de la récupération de place, seule la variable sera nettoyée.

Pedro Justo
la source