Comment supprimer une propriété d'un objet javascript?

Disons que je crée un objet comme celui-ci:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; 

Quel est le meilleur moyen de supprimer la propriété regex pour se retrouver avec un nouveau myObject comme celui-ci:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI" }; 
5276
16 окт. set johnstok 16 oct. 2008-10-16 13:57 '08 à 13:57 2008-10-16 13:57
@ 37 réponses
  • 1
  • 2

La voici:

 delete myObject.regex; // or, delete myObject['regex']; // or, var prop = "regex"; delete myObject[prop]; 

Démo

Kangax a écrit un article de blog incroyablement détaillé sur la déclaration de delete de son blog, Understanding Deletion .  Fortement recommandé. 

7292
16 окт. réponse donnée nickf 16 oct. 2008-10-16 13:58 '08 à 13h58 2008-10-16 13:58

delete opérateur ralentit de façon inattendue!

Regardez le repère .

Supprimer est le seul moyen sûr de supprimer les propriétés d'un objet sans résidu, mais il fonctionne environ 100 fois plus lentement que son object[key] = undefined paramètre "alternatif" object[key] = undefined .

Cette alternative n'est pas la bonne réponse à cette question! Mais si vous l'utilisez avec précaution, vous pouvez considérablement accélérer certains algorithmes. Si vous utilisez la delete dans les boucles et que vous rencontrez des problèmes de performances, lisez l'explication détaillée.

Quand faut-il utiliser la delete et quand la valeur spécifiée est-elle undefined ?

Un objet peut être considéré comme un ensemble de paires clé-valeur. Ce que j'appelle "valeur" est une primitive ou une référence à un autre objet associé à cette "clé".

Utilisez delete lorsque vous transmettez un objet de résultat à un code dans lequel vous n’avez aucun contrôle (ou lorsque vous n’avez pas confiance en votre équipe ou en vous-même).

Il enlève la clé de la carte de hachage .

  var obj = { field: 1 }; delete obj.field; 

Si vous n'êtes pas sûr des performances, utilisez l'option undefined . Cela peut sérieusement affecter votre code.

La clé reste à sa place dans le hashmap , seule la valeur est remplacée par undefined . Comprenez que le cycle for..in passe toujours par cette clé.

  var obj = { field: 1 }; obj.field = undefined; 

En utilisant cette méthode, toutes les méthodes pour déterminer la propriété d'existence ne fonctionneront pas comme prévu.

Cependant, ce code:

object.field === undefined

se comportera de manière équivalente pour les deux méthodes.

tests

En résumé, il y a des différences dans les manières de déterminer l’existence d’une propriété et for..in .

border=0
  console.log('* -> "Takes prototype inheritance into consideration, that means it lookups all over prototype chain too."'); console.log(obj.field === undefined, 'obj.field === undefined', 'You get "undefined" value when querying for "field" in object-hashmap. *'); console.log(obj["field"] === undefined, 'obj["field"] === undefined', 'Just another way to query (equivalent). *'); console.log(typeof obj.field === "undefined", 'typeof obj.field === "undefined"', 'Get the value attached to "field" key, and check it\ type is "undefined". *'); console.log("field" in obj, '"field" in obj', 'This statement returns true if "field" key exists in the hashmap. False otherwise. *'); console.log(obj.hasOwnProperty("field"), 'obj.hasOwnProperty("field")', 'This statement returns true if \'field\' key exists in the hashmap. The ONLY way NOT to lookup for property in the prototype chain!'); //Object.keys().indexOf() is an overkill that runs much slower :) var counter = 0, key; for (key in obj) { counter++; } console.assert(counter === 0, 'counter === 0', '"field" is not iterated using "for .. in" loop. *'); 

Attention aux fuites de mémoire!

Bien que obj[prop] = undefined plus rapide que delete obj[prop] , il est également important de obj[prop] = undefined que obj[prop] = undefined peut ne pas toujours être pertinent. delete obj[prop] supprime prop de obj et l'efface de la mémoire, tandis que obj[prop] = undefined définit simplement la valeur de prop sur undefined ce qui laisse prop en mémoire. Par conséquent, dans les situations où de nombreuses clés sont créées et supprimées, utiliser obj[prop] = undefined peut entraîner une cohérence de la mémoire coûteuse (provoquant le blocage de la page) et éventuellement une erreur de mémoire insuffisante. Examinez le code suivant.

 "use strict"; var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[]; for (i = 0; i !== numberOfNodes; i++) { nodeRecords[i] = []; current = theNodeList[i] = document.createElement("div"); current.textContent = i; document.body.appendChild( current ); } var lastTime = -1; requestAnimationFrame(function recordUpdates(){ var currentTime = Math.round( performance.now()*1000 ) for (i = 0; i !== numberOfNodes; i++) { if (lastTime !== -1) { // the previously collected data is no longer in use   nodeRecords[i][lastTime] = undefined;   } nodeRecords[i][currentTime] = theNodeList[i].outerHTML; } lastTime = currentTime; requestAnimationFrame( recordUpdates ); }); 

Dans le code ci-dessus, il suffit de nodeRecords[i][lastTime] = undefined; entraînera une fuite de mémoire massive en raison de chaque image d'animation. Chaque trame, tous les éléments de 65536 DOM occuperont 65 536 emplacements supplémentaires, mais les emplacements précédents 65 536 ne seront réglés que sur non défini, ce qui les laissera en suspens en mémoire. Continuez, essayez d’exécuter le code ci-dessus dans la console et voyez par vous-même. Après une erreur de mémoire forcée, essayez de l'exécuter à nouveau, à l'exception de la version suivante du code, qui utilise l'opérateur de delete place.

 "use strict"; var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[]; for (i = 0; i !== numberOfNodes; i++) { nodeRecords[i] = []; current = theNodeList[i] = document.createElement("div"); current.textContent = i; document.body.appendChild( current ); } var lastTime = -1; requestAnimationFrame(function recordUpdates(){ var currentTime = Math.round( performance.now()*1000 ) for (i = 0; i !== numberOfNodes; i++) { if (lastTime !== -1) { // the previously collected data is no longer in use   delete nodeRecords[i][lastTime];   } nodeRecords[i][currentTime] = theNodeList[i].outerHTML; } lastTime = currentTime; requestAnimationFrame( recordUpdates ); }); 

Comme le montre l'extrait de code ci-dessus, il existe quelques rares utilisations appropriées pour l'opérateur de delete . Cependant, ne vous inquiétez pas trop de ce problème. Cela ne deviendra un problème que pour les objets de longue durée de vie, qui leur ajoutent constamment de nouvelles clés. Dans tous les autres cas (c'est presque tous les cas dans la programmation réelle), il est préférable d'utiliser obj[prop] = undefined . L’objectif principal de cette section est simplement d’attirer votre attention sur le fait que, dans de rares cas, cela devient un problème dans votre code, vous pouvez alors plus facilement comprendre le problème et, par conséquent, ne perdez pas de temps à analyser votre code pour trouver et comprendre ce problème.

Pas toujours défini sur undefined

Le polymorphisme est un aspect important à prendre en compte. Le polymorphisme est l'attribution de variables / emplacements identiques à des objets de types différents, comme indiqué ci-dessous.

 var foo = "str"; foo = 100; // variable foo is now labeled polymorphic by the browser var bar = ["Some", "example"]; bar[2] = "text"; // bar is a monomorphic array here because all its entries have the // same type: string primitive bar[1] = undefined; // bar is now a polymorphic array 

Cependant, deux problèmes principaux ne peuvent pas être éliminés lors de l’utilisation de tableaux polymorphes:

  1. Ils sont lents et inefficaces. Lors de l'accès à un index spécifique, au lieu de simplement obtenir un type global pour un tableau, le navigateur devrait plutôt recevoir un type basé sur un index, dans lequel chaque index stocke des métadonnées supplémentaires de son type.
  2. Après polymorphe, toujours polymorphe. Lorsqu'un tableau est rendu polymorphe, le polymorphisme ne peut pas être annulé dans les navigateurs Webkit. Ainsi, même si vous restaurez un tableau polymorphe en tant que non-polymorphe, le navigateur le conservera en tant que tableau polymorphe.

Vous pouvez comparer le polymorphisme de la toxicomanie. À première vue, cela semble incroyablement rentable: un code magnifique, plutôt moelleux. Le codeur entre alors dans sa matrice dans un médicament polymorphique. Instantanément, une matrice polymorphe devient moins efficace et ne peut jamais devenir aussi efficace qu'avant, car elle est anesthésiée. Afin de corréler cette situation avec la réalité, un cocaïnomane peut même ne pas être capable de manipuler une simple poignée de porte et encore moins de pouvoir calculer les indices de performance. De même, une matrice sur une préparation de polymorphisme ne peut pas être aussi efficace qu'une matrice monomorphe.

Mais comment l'analogie avec la drogue se réfère-t-elle à l'opération de delete ? La réponse contient la dernière ligne de code de l'extrait ci-dessus. Alors laissez-le être révisé, cette fois avec une torsion.

 var bar = ["Some", "example"]; bar[2] = "text"; // bar is not a polymorphic array here because all its entries have the // same type: string primitive bar[1] = ""; // bar is still a monomorphic array bar[1] = undefined; // bar is now a polymorphic array 

Fais attention. bar[1] = "" ne provoque pas de polymorphisme, alors que bar[1] = undefined . Par conséquent, il est toujours nécessaire, lorsque cela est possible, d’utiliser le type approprié pour vos objets afin de ne pas provoquer accidentellement un polymorphisme. Une de ces personnes peut utiliser la liste suivante comme lien général pour les obtenir. Cependant, veuillez ne pas utiliser les idées ci-dessous. Au lieu de cela, utilisez ce qui fonctionne bien pour votre code.

  • Lorsque vous utilisez un tableau / une variable entrée dans une primitive booléenne, utilisez la valeur false ou undefined comme valeur vide. Bien que l’évitement d’un polymorphisme inutile soit une bonne chose, réécrire tout votre code pour le désactiver explicitement risque de nuire aux performances. Utilisez un bon jugement!
  • Lorsque vous utilisez un tableau / une variable entrée dans une primitive numérique, utilisez 0 comme valeur vide. Notez qu'il existe deux types de nombres à l'intérieur: les entiers rapides (de 2147483647 à -2147483648 inclus) et les points lents à virgule flottante double (autre que NaN et Infinity ). Lorsqu'un entier tombe à un double, il ne peut pas être classé comme un entier.
  • Lorsque vous utilisez un tableau / une variable entrée dans une primitive de chaîne, utilisez "" comme valeur vide.
  • Lorsque vous utilisez le symbole, attendez, pourquoi utilisez-vous le symbole?!?! Mauvais personnages de juju pour la performance. Tous les caractères programmés pour être utilisés peuvent être reprogrammés pour ne pas utiliser de caractères, ce qui donne un code plus rapide et sans code. Les symboles ne sont en réalité qu'un méta-sucre inefficace.
  • Si vous utilisez autre chose, utilisez null .

Cependant, soyez prudent! Ne commencez pas à faire cela avec tout le code existant, car cela risquerait de le casser et / ou de présenter des erreurs étranges. Une telle pratique efficace devrait plutôt être mise en œuvre dès le début et lors de la conversion du code existant, il est recommandé de doubler, tripler, quadrupler les contrôles de toutes les lignes associées, car la tentative de mise à jour de l'ancien code avec cette nouvelle pratique peut être aussi risquée qu'utile. .

770
12 февр. Répondre Dan 12 fév 2014-02-12 20:48 14 à 20:48 2014-02-12 20:48

215
16 окт. la réponse est donnée par redsquare le 16 oct. 2008-10-16 14:03 2008 à 14h03 2008-10-16 14:03

Mise à jour 2018-07-21: Pendant longtemps, j'ai été gêné par cette réponse, alors je pense l'avoir un peu touchée. Juste un petit commentaire, une clarification et un formatage pour accélérer la lecture des parties inutiles, longues et déroutantes de cette réponse.


VERSION COURTE

La réponse réelle à la question

Comme d’autres l’ont dit, vous pouvez utiliser delete .

 obj // {"foo": "bar"} delete obj["foo"] obj // {} obj["foo"] // undefined 

Équivalent massif

Ne pas delete du tableau. Array.prototype.splice cette utilisation Array.prototype.splice .

 arr // [1,2,3,4,5] arr.splice(3,1); // 4 arr // [1,2,3,5] 

VERSION LONGUE

JavaScript est un >

Dans les tableaux, contrairement aux vieux objets simples, l’utilisation de delete laisse la corbeille sous la forme null , créant ainsi un "trou" dans le tableau.

 var array = [1, 2, 3, 4]; delete array[2];  

Comme vous pouvez le constater, la delete ne fonctionne pas toujours comme prévu. La valeur est écrasée, mais la mémoire n'est pas redistribuée. En d'autres termes, le array[4] ne se déplace pas vers le array[3] . Contrairement à Array.prototype.unshift , qui insère un élément au début d'un tableau et décale tout vers le haut ( array[0] devient array[1] , etc.),

Honnêtement, en plus de définir null et non undefined - ce qui est tout à fait étrange - ce comportement ne devrait pas être surprenant, car delete est un opérateur unaire, tel que typeof , qui est tordu de manière rigide dans le >Array est une sous-classe d' Object avec des méthodes spécialement conçues pour travailler avec des tableaux. Par conséquent, il n'y a aucune raison pour que delete ait un cas spécial préparé pour déplacer un tableau, car cela ralentirait simplement le travail avec du travail inutile. Avec le recul, mes attentes étaient irréalistes.

Bien sur que ça m'a surpris. Parce que je l'ai écrit pour justifier ma croisade contre le "zéro déchet":

En ignorant les dangers et les problèmes inhérents à null espace null et au gaspillage, cela peut être problématique si le tableau doit être exact.

Ce qui est une excuse terrible pour se débarrasser de null s-- null n’est dangereux que s’il est utilisé à mauvais escient et n’a rien à voir avec la "précision". La vraie raison pour laquelle vous ne devriez pas delete d’un tableau est que laisser les structures de données vides et sales est désordonné et source d’erreurs.

Le script ci-dessous est assez long pour vous permettre de consulter la section «Solution» si vous le souhaitez. La seule raison pour laquelle je quitte cette section est que je pense que certaines personnes trouvent probablement cela drôle, et je ne veux pas être le «gars» qui envoie la réponse «drôle», puis la supprime. tout "drôle",

... C'est stupide, je sais.

Le scénario artificiel et à long terme PDP-11

Par exemple, supposons que vous créez une application Web qui utilise la sérialisation JSON pour stocker le tableau utilisé pour les onglets dans une chaîne ( localStorage dans ce cas). Laissez-les également dire que le code utilise les index numériques des éléments du tableau pour les "nommer" lors du dessin à l'écran. Pourquoi faites-vous cela et pas seulement en conservant le "titre"? Parce que ... raisons.

Eh bien, laissez-moi vous dire que vous essayez d'économiser de la mémoire à la demande de cet utilisateur qui exécute le mini-ordinateur PDP-11 depuis 1960, sous UNIX, et a écrit sa propre interface compatible JavaScript avec la prise en charge du navigateur JavaScript, car X11 n'est pas compatible. hors de question.

Un script de plus en plus stupide du script marginal qui utilise delete dans le tableau spécifié null pollution du tableau et risque de provoquer des erreurs dans l'application ultérieurement. Et si vous cochez la null , il sautera automatiquement des numéros, de sorte que les onglets affichés ressemblent à [1] [2] [4] [5]...

 if (array[index] == null) continue; else title = (index + 1).toString();  

Oui, ce n'est certainement pas ce que tu voulais.

Vous pouvez maintenant enregistrer le deuxième itérateur, par exemple j , pour l'incrémenter uniquement lorsque les valeurs réelles sont lues dans le tableau. Mais cela ne résout définitivement pas le problème de null , et vous aimez toujours cet utilisateur Troll PDP-11. Hélas, son ordinateur ne dispose tout simplement pas de suffisamment de mémoire pour stocker ce dernier nombre entier (ne demandez pas comment il parvient à gérer un tableau de largeur variable ...) .

Alors il vous envoie une lettre de colère:

 Hey, your webapp broke my browser! I checked my localStorage database after your stupid code made my browser segfault, and this is what I found: >"tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... ]" After clearing my precious data, it segfaulted again, and I did a backtrace, and what do I find? WHAT DO I FIND!? YOU USE TOO MANY VARIABLES! >var i = index; >var j = 1; Grr, I am angry now. -Troll Davidson 

Maintenant vous êtes à votre fin. Ce gars s'est constamment plaint de votre application et vous voulez lui dire de se taire et d'aller sur le meilleur ordinateur.

Array.prototype.splice

Heureusement, les tableaux ont une méthode spéciale pour supprimer les index et réaffecter la mémoire: Array.prototype.splice() . Vous pourriez écrire quelque chose comme ceci:

 Array.prototype.remove = function(index){ this.splice(index,1); } ... array = [1, 2, 3, 4]; array.remove(2); // Result -> [1, 2, 4] 

Et juste comme ça, vous êtes satisfait de M. PDP-11. Hourra! (Je lui dirais quand même ...)

Array.prototype.splice vs Array.prototype.slice

Je trouve important de noter la différence entre ces deux fonctions portant le même nom, car elles sont toutes deux très utiles.

Array.prototype.splice (début, n)

.splice() mute un tableau et renvoie des index distants. Le tableau est coupé à partir de l'index, le start et n éléments sont coupés. Si n n'est pas spécifié, l'ensemble du tableau après le start n = array.length - start ( n = array.length - start ).

 let a = [5,4,3,2,1]; let chunk = a.splice(2,2); // a [5,4,3,2,1] // start 0 1 2 - - // n - - 1 2 - chunk; // [3,2] a; // [5,4,1] 

Array.prototype.slice (début, fin)

.slice() est non destructif et renvoie un nouveau tableau contenant les index spécifiés du start à la end . Si end pas spécifiée à end , le comportement sera le même que celui de .splice() ( end = array.length ). Le comportement est un peu compliqué car, pour une raison quelconque, les indices de end commencent par 1 au lieu de 0. Je ne sais pas pourquoi cela se produit, mais c’est vrai. De plus, si end <= start , le résultat est un tableau vide.

 let a = [5,4,3,2,1]; let chunks = [ a.slice(2,0), a.slice(2,2), a.slice(2,3), a.slice(2,5) ]; // a [5,4,3,2,1] // start 0 1 2 - - // end, for... - - - - - // chunks[0] 0 - - - - - // chunks[1] 1 2 - - - // chunks[2] 1 2 3 - - // chunks[3] 1 2 3 4 5 chunks; // [ [], [], [3], [3,2,1] ] a; // [5,4,3,2,1] 

En fait, ce n'est pas ce qui se passe, mais il est plus facile d'y penser. Selon MDN, voici ce qui se passe réellement:

 // a [5,4,3,2,1] // start 0 1 2 - - - // end, for... - - - - - - // chunks[0] 0 - - - - - // chunks[1] 0 1 2 - - - // chunks[2] 0 1(2)3 - - // chunks[3] 0 1(2 3 4)5 

L'index spécifié par end est simplement exclu de la tranche. Les indices entre parenthèses indiquent ce qui est découpé. Dans tous les cas, le comportement n’est pas intuitif et est dû au fait qu’il provoque sa juste part d’erreurs "les unes après les autres", vous pouvez donc trouver utile de rendre la fonction wrapper supérieure à .splice() de .splice() comportement de .splice() :

 function ez_slice(array, start = 0, n = null){ if(!Array.isArray(array) || !is_number(start)) return null; if(is_number(n)) return array.slice(start, start + n); if(n === null) return array.slice(start); return null; } ez_slice([5,4,3,2,1], 2, 1) // [3] ez_slice([5,4,3,2,1], 2) // [3,2,1]  function is_nan(num){ return typeof num === "number"  num !== num; } function is_number(num){ return !is_nan(num)  typeof num === "number"  isFinite(num); } 

Notez que la fonction wrapper concerne les types très forts et renvoie null si quelque chose est désactivé. Cela inclut une chaîne de type "3" . Il reste au programmeur à faire preuve de diligence dans ses types. Cela devrait contribuer à de bonnes pratiques de programmation.

Mise à jour concernant is_array()

Cela s'applique à ce fragment (maintenant supprimé):

 function is_array(array){ return array !== null  typeof array === "object"  typeof array.length !== "undefined"  array.__proto__ === Array.prototype; } 

Il s’est donc avéré qu’il existe un moyen intégré de déterminer si un tableau est vraiment un tableau, il s’agit de Array.isArray() , introduit dans ECMAScript 5 (décembre 2009). Я нашел это, глядя на вопрос, есть ли вопрос о том, чтобы сообщать массивы с объектов, чтобы увидеть, было ли лучшее решение, чем мое, или добавить мое, если их не было. Итак, если вы используете версию JavaScript, которая раньше ECMA 5, там ваш полипол. Тем не менее, я настоятельно рекомендую не использовать is_array() , так как продолжение поддержки старых версий JavaScript означает продолжение поддержки старых браузеров, которые их реализуют, что означает поощрение использования небезопасного программного обеспечения и помещение пользователей под угрозу для вредоносного ПО. Поэтому, пожалуйста, используйте Array.isArray() . Используйте let и const . Используйте новые функции, которые добавляются в язык. Не используйте префиксы поставщиков. Удалите это полисплощадку IE с вашего сайта. Удалите этот XHTML <!CDATA[[... crap, тоже - мы переместились в HTML5 еще в 2014 году.). Чем раньше все откажутся от поддержки этих старых/эзотерических браузеров, тем скорее поставщики браузеров будут действительно следовать веб-стандарту и охватывают новые технологии, и чем скорее мы сможем перейти к более безопасной сети.

164
ответ дан Braden Best 18 сент. '12 в 3:56 2012-09-18 03:56

Старый вопрос, современный ответ. Используя деструктурирование объектов, ECMAScript 6 , это так же просто, как:

 const { a, ...rest } = { a: 1, b: 2, c: 3 };