web-dev-qa-db-fra.com

Comment effacer rapidement un objet JavaScript?

Avec un tableau JavaScript, je peux le réinitialiser à un état vide avec une seule affectation:

array.length = 0;

Cela fait en sorte que le tableau "semble" vide et prêt à être réutilisé. Autant que je sache, il ne s'agit que d'une seule "opération", c'est-à-dire d'un temps constant.

Existe-t-il une méthode similaire pour effacer un objet JS? Je sais que je peux parcourir ses champs en les supprimant:

for (var prop in obj) { if (obj.hasOwnProperty(prop)) { delete obj[prop]; } }

mais cela a une complexité linéaire.

Je peux aussi simplement jeter l'objet et en créer un nouveau:

obj = {};

Mais la création "promiscuous" de nouveaux objets pose des problèmes avec Garbage Collection sur IE6. ( comme décrit ici )

156
levik

Je pense que la réponse courte à votre question est non (vous pouvez simplement créer un nouvel objet).

  1. Dans cet exemple, je pense que définir la longueur à 0 laisse toujours tous les éléments pour la récupération de place.

  2. Vous pouvez ajouter ceci à Object.prototype si vous l'utilisez fréquemment. Oui, sa complexité est linéaire, mais tout ce qui ne fait pas la récupération de place ultérieurement le sera.

  3. C'est la meilleure solution. Je sais que cela n’a rien à voir avec votre question - mais pour combien de temps devons-nous continuer à soutenir IE6? Il existe de nombreuses campagnes pour en cesser l'utilisation.

N'hésitez pas à me corriger s'il y a une erreur ci-dessus.

49
jthompson

Eh bien, au risque de rendre les choses trop faciles ...

for (var member in myObject) delete myObject[member];

... semblerait assez efficace pour nettoyer l'objet dans une ligne de code avec un minimum de crochets effrayants. Tous les membres seront réellement supprimés au lieu d'être laissés à la poubelle.

Évidemment, si vous souhaitez supprimer l'objet lui-même, vous devrez toujours effectuer une suppression distincte () pour cela.

106
Wytze

ES5

La solution ES5 peut être:

// for enumerable properties
Object.keys(obj).forEach(function (prop) {
  delete obj[prop];
});

// for all properties
Object.getOwnPropertyNames(obj).forEach(function (prop) {
  delete obj[prop];
});

ES6

Et la solution ES6 peut être:

// for enumerable properties
for (const prop of Object.keys(obj)) {
  delete obj[prop];
}

// for all properties
for (const prop of Object.getOwnPropertyNames(obj)) {
  delete obj[prop];
}

Performance

Quelles que soient les spécifications, les solutions les plus rapides seront généralement les suivantes:

// for enumerable properties
var props = Object.keys(obj);
for (var i = 0; i < props.length; i++) {
  delete obj[props[i]];
}

// for all properties of an object with proto chain
var props = Object.getOwnPropertyNames(obj);
for (var i = 0; i < props.length; i++) {
  delete obj[props[i]];
}

// for all properties of shallow/plain object
for (var key in obj) {
  // this check can be safely omitted in modern JS engines
  // if (obj.hasOwnProperty(key))
    delete obj[key];
}

La raison pour laquelle for..in ne devrait être exécuté que sur un objet superficiel ou simple est qu'il traverse les propriétés héritées du prototype, pas seulement les propriétés pouvant être supprimées. S'il n'est pas certain qu'un objet soit clair, for avec Object.getOwnPropertyNames constitue un meilleur choix.

37
Estus Flask

Vous pouvez essayer ça. La fonction ci-dessous définit toutes les valeurs des propriétés de l'objet sur non défini. Fonctionne également avec des objets imbriqués.

var clearObjectValues = (objToClear) => {
    Object.keys(objToClear).forEach((param) => {
        if ( (objToClear[param]).toString() === "[object Object]" ) {
            clearObjectValues(objToClear[param]);
        } else {
            objToClear[param] = undefined;
        }
    })
    return objToClear;
};
7
Alina Poluykova

Donc, pour récapituler votre question: vous voulez éviter, autant que possible, les problèmes avec le bogue IE6 GC. Ce bogue a deux causes:

  1. Le ramassage des ordures a lieu une fois sur deux allocations; Par conséquent, plus vous allouez d'argent, plus souvent le GC s'exécutera.
  2. Plus vous avez d’objets ‘dans l’air’, plus chaque opération de récupération de place prend du temps (puisqu’elle parcourt la liste complète des objets pour voir ceux qui sont marqués comme étant des déchets).

La solution à la cause 1 semble être la suivante: réduire le nombre d’allocations; Assignez le moins possible de nouveaux objets et de nouvelles chaînes.

La solution à la cause 2 semble être la suivante: limitez le nombre d’objets "vivants"; supprimez vos chaînes et vos objets dès que vous n'en avez plus besoin, et créez-les à nouveau si nécessaire.

Dans une certaine mesure, ces solutions sont contradictoires: maintenir le nombre d’objets en mémoire à un niveau bas impliquera davantage d’allocations et de désaffectations. Inversement, réutiliser constamment les mêmes objets peut signifier conserver plus d’objets en mémoire que ce qui est strictement nécessaire.


Maintenant pour votre question. Que vous réinitialisiez un objet en en créant un nouveau ou en supprimant toutes ses propriétés: cela dépend de ce que vous voulez en faire par la suite.

Vous voudrez probablement lui attribuer de nouvelles propriétés:

  • Si vous le faites immédiatement, je vous suggère d'attribuer immédiatement les nouvelles propriétés et de commencer par supprimer ou effacer. (Assurez-vous cependant que toutes les propriétés sont écrasées ou supprimées!)
  • Si l'objet ne sera pas utilisé immédiatement, mais qu'il sera repeuplé ultérieurement, je suggère de le supprimer ou de l'attribuer à une valeur nulle et d'en créer un nouveau ultérieurement.

Il n'y a pas de moyen rapide et facile à utiliser pour effacer un objet JScript pour le réutiliser comme s'il s'agissait d'un nouvel objet, sans en créer un nouveau. Ce qui signifie que la réponse courte à votre question est "non", comme dit jthompson.

7
Martijn

Quelque chose de nouveau à penser en ce qui concerne Object.observe dans ES7 et à la liaison de données en général. Considérer:

var foo={
   name: "hello"
};

Object.observe(foo, function(){alert('modified');}); // bind to foo

foo={}; // You are no longer bound to foo but to an orphaned version of it
foo.name="there"; // This change will be missed by Object.observe()

Donc, dans ce cas, le n ° 2 peut être le meilleur choix.

4
Terry Thorsen

Vous pouvez supprimer les accessoires, mais ne supprimez pas les variables. delete abc; n'est pas valide dans ES5 (et lance avec use strict).

Vous pouvez l'attribuer à null pour le définir pour qu'il soit supprimé du GC (cela ne sera pas le cas si vous avez d'autres références à des propriétés).

La définition de la propriété length sur un objet ne change rien. (il ne définit que la propriété)

1
Ven