Comment puis-je supprimer une propriété d'un objet JavaScript?

dire que je crée un objet comme suit:

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

Quelle est la meilleure façon de supprimer la propriété regex pour finir avec le nouveau myObject comme suit?

var myObject = {
    "ircEvent": "PRIVMSG",
    "method": "newURI"
};
5066
demandé sur Peter Mortensen 2008-10-16 14:57:45

30 réponses

comme ceci:

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

Démo

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

console.log(myObject);

pour toute personne intéressée à lire plus à ce sujet, Stack Overflow user kangax a écrit un billet de blog incroyablement en profondeur sur le delete déclaration sur leur blog, comprendre supprimer . Il est fortement recommandé.

7021
répondu nickf 2017-10-09 16:55:56

Opérateur delete est lent de façon inattendue!

Regardez de la de référence", 1519490920" .

Delete est le seul vrai moyen de supprimer les propriétés de l'objet sans aucun reliquat, mais il fonctionne ~ 100 fois plus lent , par rapport à son "alternative", le réglage object[key] = undefined .

cette alternative n'est pas la réponse correcte à cette question! Mais, si vous utiliser avec précaution, vous pouvez accélérer considérablement certains algorithmes. Si vous utilisez delete dans les boucles et que vous avez des problèmes de performance, lisez l'explication verbeuse.

quand doit-on utiliser delete et undefined ?

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

utiliser delete , lorsque vous passez l'objet résultat au code sur lequel vous n'avez pas de contrôle (ou lorsque vous n'êtes pas sûr de votre équipe ou vous-même).

It supprime la clé de la carte .

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

utilisez le paramètre undefined , lorsque vous vous souciez de performance. Il peut donner un sérieux coup de pouce à votre code.

la clé reste sur sa place dans le hashmap , seule la valeur est remplacée par undefined . Comprenez, cette boucle for..in sera encore itérée sur cette clé.

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

en utilisant cette méthode, toutes les façons de déterminer l'existence d'un bien ne fonctionneront pas comme prévu.

cependant, ce code:

object.field === undefined

se comportera de façon équivalente pour les deux méthodes.

Essais

pour résumer, les différences sont toutes sur les façons de déterminer l'existence de la propriété, et environ for..in boucle.

 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\'s 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!

alors que obj[prop] = undefined est plus rapide que delete obj[prop] , une autre considération importante est que obj[prop] = undefined peut ne pas toujours être approprié. delete obj[prop] supprime prop de obj et l'efface de mémoire alors que obj[prop] = undefined fixe simplement la valeur de prop à undefined qui laisse prop encore en mémoire. Par conséquent, dans les circonstances où de nombreuses clés sont créées et supprimées, l'utilisation de obj[prop] = undefined peut forcer une réconciliation de mémoire coûteuse (provoquant le gel de la page) et potentiellement une erreur de mémoire. 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, simplement faire nodeRecords[i][lastTime] = undefined; causera un massif fuite de mémoire parce que chaque image d'animation. Chaque image, les 65536 éléments DOM prendront un autre 65536 emplacements individuels, mais les 65536 emplacements précédents seront seulement mis à non défini ce qui les laisse suspendus dans la mémoire. Allez-y, essayez d'exécuter le code ci-dessus dans la console et voir par vous-même. Après avoir forcé une erreur de mémoire, essayer de l'exécuter à nouveau sauf avec la version suivante du code qui utilise l'opérateur delete à la 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 );
});

As vu dans l'extrait de code ci-dessus, il y a quelques rares cas d'utilisation appropriée pour l'opérateur delete . Cependant, ne vous inquiétez pas trop de ce problème. Cela ne deviendra un problème qu'avec les objets de longue durée de vie qui reçoivent de nouvelles clés constamment ajoutées. Dans tous les autres cas (ce qui est presque toujours le cas dans la programmation en situation réelle), il est plus approprié d'utiliser obj[prop] = undefined . Le but principal de cette section est juste de porter ceci à votre attention afin que dans la rare chance que cela ne devenir un problème dans votre code, alors vous pouvez plus facilement comprendre le problème et donc ne pas avoir à perdre des heures à disséquer votre code pour localiser et comprendre ce problème.

Ne Correspond Pas Toujours À undefined

un aspect de Javascript qui est important à considérer est le polymorphisme. Le polymorphisme est lors de l'attribution de la même variable/fente-dans-un-objet de différents types comme vu 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, il y a deux grands irrécupérable problèmes avec polymorphes tableaux:

  1. ils sont lents et la mémoire inefficace. Lorsque vous accédez à un index spécifique, au lieu de simplement obtenir le type global pour le tableau, le navigateur doit plutôt obtenir le type sur une base per-index par lequel chaque index stocke les métadonnées supplémentaires de son type.
  2. une fois polymorphe, toujours polymorphe. Quand un tableau est rendu polymorphique, le polymorphisme ne peut pas être défait dans Webkit navigateur. Donc, même si vous restaurez un tableau polymorphe d'être non polymorphes, il sera toujours stocké par le navigateur comme un polymorphe tableau.

on peut comparer le polymorphisme à une toxicomanie. À première vue, cela semble extrêmement lucratif: joli code plutôt moelleux. Ensuite, le codeur introduit leur réseau à la drogue du polymorphisme. Instantanément, le polymorphic array devient moins efficace, et il ne peut jamais devenir aussi efficace qu'il l'était auparavant, car il est droguée. Pour corréler de telles circonstances à la vie réelle, quelqu'un sous cocaïne pourrait même ne pas être capable d'opérer une simple poignée de porte, et encore moins être capable de calculer les chiffres de PI. De même, un tableau sur le médicament de polymorphisme ne peut jamais être aussi efficace qu'un monomorphe tableau.

mais, comment une analogie de voyage de drogue se rapporte-t-elle à l'opération delete ? La réponse hérite de la dernière ligne de code dans le snippet ci-dessus. Qu'il soit donc réexaminé, 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

observez. bar[1] = "" ne contraint pas le polymorphisme alors que bar[1] = undefined le fait. Par conséquent, il faut toujours, dans la mesure du possible, utiliser le type correspondant pour leurs objets afin de ne pas causer de polymorphisme accidentel. Une telle personne peut utiliser la liste suivante comme une référence générale pour les faire aller. Toutefois, n'utilisez pas explicitement les idées ci-dessous. Utilisez plutôt ce qui fonctionne bien pour votre code.

  • Lorsque vous utilisez un tableau/variable tapé à la primitive booléenne, utilisez soit false ou undefined comme valeur vide. Alors qu'éviter le polymorphisme inutile est bon, réécrire tout votre code pour l'interdire explicitement entraînera probablement en fait une diminution de la performance. Utilisez votre bon jugement!
  • lorsque vous utilisez un tableau/une variable dactylographiée à la primitive number, utilisez 0 comme valeur vide. Notez qu'en interne, il y a deux types de nombres: les entiers rapides (2147483647 à -2147483648 inclusivement) et les doubles à virgule flottante lente (tout autre que celui incluant NaN et Infinity ). Quand un entier est rétrogradé à un double, il ne peut pas être promu de nouveau à un entier.
  • lorsque vous utilisez un tableau/variable tapé à la primitive string, utilisez "" comme valeur vide.
  • quand vous utilisez un symbole, attendez, pourquoi utilisez-vous un symbole?!?! Les symboles sont mauvais juju pour la performance. Tout programmée pour utiliser des symboles peut être reprogrammée pour ne pas utiliser de symboles, résultant en un code plus rapide sans Symboles. Les symboles sont vraiment juste super inefficace méta-sucre.
  • pour toute autre utilisation, Utilisez null .

attention! Ne commencez pas soudainement à faire cela avec tout votre code préexistant maintenant car il serait probablement briser ce code préexistant et/ou introduire des bogues étranges. Une telle pratique efficace doit plutôt être mis en œuvre dès le début, et lors de la conversion de code préexistant, il est recommandé que vous double, triple, quadruple vérifier toutes les lignes relatives à ce que d'essayer de mettre à niveau l'ancien code à cette nouvelle pratique peut être aussi risqué que c'est gratifiant.

731
répondu Dan 2018-04-19 10:26:30

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

console.log ( myObject.regex); // logs: undefined

cela fonctionne dans Firefox et Internet Explorer, et je pense qu'il fonctionne dans tous les autres.

203
répondu redsquare 2018-06-01 16:29:50

mise à jour 2018-07-21: depuis longtemps, je me sens embarrassé par cette réponse, donc je pense qu'il est temps que je la retouche un peu. Juste un peu de commentaire, de clarification et de formatage pour aider à accélérer la lecture des parties inutilement longues et alambiquées de cette réponse.


LA VERSION COURTE

la réponse effective à la question

comme les autres vous pouvez utiliser delete .

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

equivalent Array

Ne pas delete à partir d'un tableau. Utilisez Array.prototype.splice à la place.

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

LA VERSION LONGUE

JavaScript est un langage OOP, donc tout est un objet, y compris tableaux . Donc, je pense qu'il faut une mise en garde.

dans les tableaux, contrairement aux vieux objets simples, en utilisant delete laisse des ordures dans la forme de null , créant un" trou " dans le tableau.

var array = [1, 2, 3, 4];
delete array[2];
/* Expected result --> [1, 2, 4]
 * Actual result   --> [1, 2, null, 4]
 */

Comme vous pouvez le voir, delete ne fonctionne pas toujours comme on pourrait s'y attendre. La valeur est écrasée, mais la mémoire n'est pas réaffecté. C'est-à-dire que array[4] n'est pas relocalisé dans array[3] . Qui est en contraste avec Array.prototype.unshift , qui insère un élément dans le début du tableau et change tout ( array[0] devient array[1] , etc.)

honnêtement, à part mettre à null plutôt que undefined --ce qui est légitimement bizarre--ce comportement ne devrait pas être surprenant, puisque delete est un opérateur unaire, comme typeof , qui est dur dans le langage et n'est pas censé se soucier du type de l'objet qu'il est utilisé, alors que Array est un sous-classe de Object avec les méthodes spécialement conçue pour travaillant avec des matrices. Il n'y a donc pas de bonne raison pour que delete fasse cuire un étui spécial pour changer le tableau, car cela ne ferait que ralentir les choses avec du travail inutile. Rétrospectivement, mes attentes étaient irréalistes.

bien sûr, il a fait me surprendre. Parce que j'ai écrit ceci pour justifier ma croisade contre "null garbage":

en ignorant les dangers et les problèmes inhérents à null , et l'espace perdu, cela peut être problématique si le tableau doit être précis.

qui est une terrible justification pour se débarrasser du null s-- null n'est dangereux que s'il est mal utilisé, et il n'a rien à voir avec la"précision". La vraie raison pour laquelle vous ne devriez pas delete d'un tableau est parce que laissant les données remplies de déchets et de désordre les structures autour sont négligées et sujettes aux insectes.

ce qui suit est un scénario artificiel qui devient assez long-winded, de sorte que vous pouvez passer à la section, la Solution , si vous voulez. La seule raison pour laquelle je laisse cette section est parce que je pense que certaines personnes pensent probablement que c'est drôle, et je ne veux pas être "ce gars" qui poste une réponse "drôle" et puis supprime tous les "drôle" de celui-ci plus tard.

...C'est stupide, je sais.

L'artificiel et de longue haleine PDP-11 scénario

par exemple, disons que vous créez une webapp qui utilise la sérialisation JSON pour stocker un tableau utilisé pour 'tabs' dans une chaîne (dans ce cas, localStorage ). Disons aussi que le code utilise les indices numériques de la matrice de la "titre" quand le dessin à l'écran. Pourquoi faites-vous cela plutôt que de simplement stocker le "titre"? Parce... motifs .

d'accord, disons simplement que vous essayez d'enregistrer de la mémoire à la demande de cet un utilisateur qui exécute un mini-ordinateur PDP-11 à partir de L'exécution UNIX des années 1960, et a écrit son propre elinks-basé, JavaScript-conforme, ligne-navigateur facile à imprimer parce que X11 est hors de question .

de plus en plus stupide bord-scénario cas mis à part, en utilisant delete sur ledit tableau résultera dans null polluant le tableau, et causant probablement des bugs dans l'application plus tard. Et si vous cochez null , il serait tout droit sauter les numéros résultant dans les onglets étant rendus comme [1] [2] [4] [5] ... .

if (array[index] == null)
    continue;
else
    title = (index + 1).toString();
/* 0 -> "1"
 * 1 -> "2"
 * 2 -> (nothing)
 * 3 -> "4"
 */

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

Maintenant, vous pourrait garder un deuxième itérateur, comme j , pour augmenter seulement quand les valeurs valides sont lues à partir du tableau. Mais cela ne résoudrait pas exactement le problème null , et vous devez toujours s'il vous plaît que troll PDP-11 utilisateur. Hélas, son ordinateur juste ne ont pas assez de mémoire pour tenir ce dernier entier (ne demandez pas comment il gère un tableau de largeur variable...) .

donc, il vous envoie un email en 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

vous êtes à bout de nerfs. Ce mec s'est plaint sans arrêt de votre application, et vous voulez lui dire de se taire et d'aller chercher un meilleur ordinateur.

La Solution: Array.prototype.splice

heureusement, les tableaux do ont une méthode spécialisée pour supprimer des indices et réallouer 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 comme ça, vous avez plu à M. PDP-11. Hourra! (je lui dirais quand même...)

tableau.prototype.splice vs Array.prototype.tranche

je pense qu'il est important de souligner la différence entre ces deux fonctions nommées de la même façon, car elles sont toutes deux très utiles.

tableau.prototype.splice(démarrer, n)

.splice() mute la matrice, et renvoie les indices supprimés. Le tableau est découpé à partir de la l'indice de 1519430920" , et n éléments sont découpées. Si n n'est pas spécifié, le tableau entier après start est découpé ( 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]

tableau.prototype.tranche(début, fin)

.slice() est non destructif et renvoie un nouveau tableau contenant l'indication des indices de start à end . Si end est spécifié, le comportement est le même que .splice() ( end = array.length ). Le comportement est un peu délicat puisque, pour une raison quelconque, end indexes de 1 au lieu de 0. Je ne sais pas pourquoi il fait ça, mais c'est comme ça. Aussi, 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]

ce n'est pas ce qui se passe, mais c'est plus facile de penser à ça. 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'indice spécifié par end est simplement exclu de la tranche. Le les indices entre parenthèses indiquent ce qui est tranché. De toute façon, le comportement n'est pas intuitif et il est lié à causer sa juste part d'erreurs off-by-one, donc vous pourriez trouver utile de faire une fonction wrapper pour imiter plus étroitement le 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]

/* Fun fact: isNaN is unreliable.
 * [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(isNaN)
 * [NaN, {}, undefined, "Hi"]
 *
 * What we want is...
 *
 * [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(is_nan)
 * [NaN]
 */
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 est conçue pour être très stricte sur les types, et retournera null si quelque chose est éteint. Cela inclut mettre une corde comme "3" . Il est de gauche jusqu'au programmeur d'être diligent sur ses types. C'est pour encourager les bonnes de la programmation de la pratique.

mise à jour concernant is_array()

il s'agit de cet extrait (maintenant supprimé):

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

il s'avère qu'il y a en fait une manière intégrée de dire si un tableau est vraiment un tableau, et c'est Array.isArray() , introduit dans ECMAScript 5 (décembre 2009). J'ai trouvé cela tout à la recherche pour voir si il y avait une question sur le fait de raconter des tableaux à partir d'objets, pour voir s'il y avait une meilleure solution que la mienne, ou pour ajouter la mienne s'il n'y en avait pas. Donc, si vous utilisez une version de JavaScript qui est antérieure à ECMA 5, Voici votre polyfill. Cependant, je recommande fortement de ne pas utiliser ma fonction is_array() , car continuer à prendre en charge les anciennes versions de JavaScript signifie continuer à prendre en charge les anciens navigateurs qui les mettent en œuvre, ce qui signifie encourager l'utilisation de logiciels peu sûrs et mettre en place des les utilisateurs à risque pour les logiciels malveillants. Alors s'il vous plaît, utilisez Array.isArray() . Utilisez let et const . Utiliser les nouvelles fonctionnalités sont ajoutées à la langue. Ne pas utiliser des fournisseurs de préfixes. Supprimer que IE polyfill de la merde de votre site web. Supprimer ce XHTML <!CDATA[[... merde, aussi--nous avons déménagé à HTML5 en 2014. Le plus tôt tout le monde retire la prise en charge pour ces vieux navigateurs/esoteric, le plus tôt les vendeurs de navigateur seront réellement suivre la norme web et adopter la nouvelle technologie, et le plus tôt nous pourrons passer à un web plus sûr.

149
répondu Braden Best 2018-07-26 18:57:37

question ancienne, réponse moderne. En utilisant la déstructuration d'objet, une fonctionnalité ECMAScript 6 , c'est aussi simple que:

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

ou avec l'échantillon de questions:

const myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
const { regex, ...newObject } = myObject;
console.log(newObject);

Vous pouvez le voir en action dans la Babel d'essai de l'éditeur.


modifier:

pour réattribuer à la même variable, utilisez un let :

let myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
({ regex, ...myObject } = myObject);
console.log(myObject);
104
répondu Koen. 2016-12-01 20:51:19

une autre solution consiste à utiliser le soulignement .js bibliothèque.

notez que _.pick() et _.omit() renvoient une copie de l'objet et ne modifient pas directement l'objet original. L'affectation du résultat de l'objet d'origine devrait faire l'affaire (non illustré).

la Référence: lien _.pick(objet, *clés)

retourner une copie du objet, filtré pour n'avoir que des valeurs pour touches à liste blanche (ou tableau de touches valides).

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

_.pick(myJSONObject, "ircEvent", "method");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};

la Référence: lien _.omettre(objet, *clés)

retourner une copie de l'objet, filtré pour omettre le liste noire des clés (ou tableau de clés).

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

_.omit(myJSONObject, "regex");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};

pour les matrices, _.filter() et _.reject() peuvent être utilisés de manière similaire.

74
répondu Thaddeus Albers 2018-02-03 19:51:40

le terme que vous avez utilisé dans le titre de votre question Remove a property from a JavaScript object peut être interprété de différentes façons. L'un est de le supprimer pour la mémoire entière et la liste des clés d'objet ou l'autre est juste de le supprimer de votre objet. Comme il a été mentionné dans d'autres réponses, le delete mot-clé est la partie principale. Disons que vous avez votre objet comme:

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

si vous le faites:

console.log(Object.keys(myJSONObject));

le résultat serait:

["ircEvent", "method", "regex"]

vous pouvez supprimer cette clé spécifique de vos clés d'objet comme:

delete myJSONObject["regex"];

alors votre clé d'objets en utilisant Object.keys(myJSONObject) serait:

["ircEvent", "method"]

mais le point est que si vous vous souciez de la mémoire et que vous voulez tout l'objet est retiré de la mémoire, il est recommandé de le définir à null avant de supprimer la clé:

myJSONObject["regex"] = null;
delete myJSONObject["regex"];

L'autre point important ici est d'être attention à vos autres références pour le même objet. Par exemple, si vous créez une variable comme:

var regex = myJSONObject["regex"];

ou l'ajouter comme un nouveau pointeur à un autre objet comme:

var myOtherObject = {};
myOtherObject["regex"] = myJSONObject["regex"];

alors même si vous le retirez de votre objet myJSONObject , cet objet spécifique ne sera pas effacé de la mémoire, puisque la variable regex et myOtherObject["regex"] ont encore leurs valeurs. Alors comment pourrions-nous retirer l'objet de la mémoire pour vous?

la réponse serait supprimer toutes les références que vous avez dans votre code, a pointé à cet objet même et aussi de ne pas utiliser var déclarations pour créer de nouvelles références à cet objet . Ce dernier point concernant les déclarations var , est l'une des questions les plus cruciales auxquelles nous sommes habituellement confrontés, parce que l'utilisation des déclarations var empêcherait l'objet créé de se faire enlever.

ce qui signifie dans ce cas que vous ne pourrez pas supprimer cet objet parce que vous avez créé la variable regex via une déclaration var , et si vous le faites:

delete regex; //False

le résultat serait false , ce qui signifie que votre suppression n'a pas été exécutée comme vous vous y attendiez. Mais si vous n'aviez pas créé cette variable auparavant, et que vous aviez seulement myOtherObject["regex"] comme dernière référence existante, vous auriez pu le faire simplement en la supprimant. comme:

myOtherObject["regex"] = null;
delete myOtherObject["regex"];

en d'autres termes, un objet JavaScript est tué dès qu'il n'y a plus de référence dans votre code pointé vers cet objet.


Maj: Merci à @AgentME:

définir une propriété à null avant de la supprimer n'accomplit pas n'importe quoi (à moins que l'objet n'ait été scellé par L'objet.joint d'étanchéité et l' supprimer échoue. Ce n'est généralement pas le cas sauf si vous essayer.)

pour obtenir plus d'information sur Object.seal : objet.sceau ()

37
répondu Mehran Hatami 2015-06-02 22:18:26

supposons que vous ayez un objet qui ressemble à ceci:

var Hogwarts = {
    staff : [
        'Argus Filch',
        'Filius Flitwick',
        'Gilderoy Lockhart',
        'Minerva McGonagall',
        'Poppy Pomfrey',
        ...
    ],
    students : [
        'Hannah Abbott',
        'Katie Bell',
        'Susan Bones',
        'Terry Boot',
        'Lavender Brown',
        ...
    ]
};

supprimer une propriété d'objet

si vous voulez utiliser la totalité du tableau staff , la bonne façon de le faire, serait de faire ceci:

delete Hogwarts.staff;

alternativement, vous pouvez aussi faire ceci:

delete Hogwarts['staff'];

dans le même ordre d'idées, on supprimerait l'ensemble du tableau students en appelant delete Hogwarts.students; ou delete Hogwarts['students']; .

supprimer un index de tableau

maintenant, si vous voulez supprimer un seul membre du personnel ou un étudiant, la procédure est un peu différente, parce que les deux propriétés sont des tableaux eux-mêmes.

si vous connaissez l'index de votre employé, vous pouvez simplement faire ceci:

Hogwarts.staff.splice(3, 1);

Si vous ne connaissez pas l'index, vous aurez également à faire une recherche d'index:

Hogwarts.staff.splice(Hogwarts.staff.indexOf('Minerva McGonnagall') - 1, 1);

Note

alors que vous pouvez techniquement utiliser delete pour un tableau, l'utiliser aurait pour résultat d'obtenir des résultats incorrects en appelant par exemple Hogwarts.staff.length plus tard. En d'autres termes, delete supprimerait l'élément, mais ne mettrait pas à jour la valeur de la propriété length . Utiliser delete perturberait également votre indexation.

ainsi, lors de la suppression de valeurs d'un objet, toujours d'abord considérer si vous avez affaire à propriétés de l'objet ou si vous avez affaire à des valeurs de tableau, et choisissez la stratégie appropriée basée sur cela.

si vous voulez expérimenter avec cela, vous pouvez utiliser ce violon comme point de départ.

30
répondu John Slegers 2016-11-23 09:17:42

ECMAScript 2015 (ou ES6) est livré avec l'Objet intégré Reflect . Il est possible de supprimer une propriété d'objet en appelant Reflect.deleteProperty () fonction avec l'objet cible et la clé de propriété comme paramètres:

Reflect.deleteProperty(myJSONObject, 'regex');

qui est l'équivalent de:

delete myJSONObject['regex'];

mais si la propriété de l'objet n'est pas configurable il ne peut pas être supprimé ni avec la fonction deleteProperty ni supprimer l'opérateur:

let obj = Object.freeze({ prop: "value" });
let success = Reflect.deleteProperty(obj, "prop");
console.log(success); // false
console.log(obj.prop); // value

objet.freeze () rend toutes les propriétés de l'objet non configurables (en plus d'autres choses). La fonction deleteProperty (ainsi que supprimer l'opérateur ) renvoie false lorsqu'elle essaie de supprimer l'une de ses propriétés. Si la propriété est configurable il retourne true , même si la propriété n'existe pas.

la différence entre delete et deleteProperty est en mode strict:

"use strict";

let obj = Object.freeze({ prop: "value" });
Reflect.deleteProperty(obj, "prop"); // false
delete obj["prop"];
// TypeError: property "prop" is non-configurable and can't be deleted
29
répondu madox2 2016-01-25 17:22:10

le supprimer l'opérateur est la meilleure façon de le faire.

un exemple en direct à montrer:

var foo = {bar: 'bar'};
delete foo.bar;
console.log('bar' in foo); // Logs false, because bar was deleted from foo.
23
répondu Tarun Nagpal 2016-02-11 20:30:34

j'utilise personnellement Underscore.js pour objet et tableau de manipulation:

myObject = _.omit(myObject, 'regex');
20
répondu emil 2016-11-22 22:09:07

ce post est très ancien et je le trouve très utile, donc j'ai décidé de partager la fonction unset que j'ai écrit au cas où quelqu'un d'Autre voir ce post et de penser pourquoi ce n'est pas aussi simple que dans PHP fonction unset.

la raison d'écrire cette nouvelle fonction unset , est de conserver l'index de toutes les autres variables dans ce hash_map. Regardez l'exemple suivant, et voyez comment l'index de "test2" n'a pas changé après avoir supprimé une valeur de hash_map.

function unset(unsetKey, unsetArr, resort){
  var tempArr = unsetArr;
  var unsetArr = {};
  delete tempArr[unsetKey];
  if(resort){
    j = -1;
  }
  for(i in tempArr){
    if(typeof(tempArr[i]) !== 'undefined'){
      if(resort){
        j++;
      }else{
        j = i;
      }
      unsetArr[j] = tempArr[i];
    }
  }
  return unsetArr;
}

var unsetArr = ['test','deletedString','test2'];

console.log(unset('1',unsetArr,true)); // output Object {0: "test", 1: "test2"}
console.log(unset('1',unsetArr,false)); // output Object {0: "test", 2: "test2"}
16
répondu talsibony 2016-11-22 21:35:37

une autre solution, en utilisant Array#reduce .

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

myObject = Object.keys(myObject).reduce(function(obj, key) {
  if (key != "regex") {           //key you want to remove
    obj[key] = myObject[key];
  }
  return obj;
}, {});

console.log(myObject);

Cependant, il muter l'objet d'origine. Si vous voulez créer un nouvel objet sans la clé spécifiée, il suffit d'assigner la fonction reduce à une nouvelle variable, par exemple:

(ES6)

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

const myNewObject = Object.keys(myObject).reduce((obj, key) => {
  key !== 'regex' ? obj[key] = myObject[key] : null;
  return obj;
}, {});

console.log(myNewObject);
16
répondu kind user 2017-10-24 09:58:51

il y a beaucoup de bonnes réponses ici, mais je veux juste faire comme si en utilisant delete pour supprimer une propriété en JavaScript, il est souvent sage de vérifier d'abord si cette propriété existe pour prévenir les erreurs.

e. g

var obj = {"property":"value", "property2":"value"};

if (obj && obj.hasOwnProperty("property2")) {
  delete obj.property2;
} else {
  //error handling
}

en raison de la nature dynamique de JavaScript, il y a souvent des cas où vous ne savez tout simplement pas si la propriété existe ou non. Vérifier si obj existe avant le & & s'assure également que vous ne jetez pas une erreur due à appeler la fonction hasOwnProperty () sur un objet non défini.

désolé si cela n'a pas ajouté à votre cas d'utilisation spécifique, mais je crois que c'est un bon design à adapter lors de la gestion des objets et de leurs propriétés.

15
répondu Willem 2014-09-15 00:48:08

en utilisant supprimer méthode est la meilleure façon de faire que, selon la description MDN, l'opérateur Supprimer supprime une propriété d'un objet. Donc vous pouvez simplement écrire:

delete myObject.regex;
// OR
delete myObject['regex'];

l'opérateur Supprimer supprime une propriété donnée d'un objet. Sur suppression réussie, il retournera true, sinon false sera retourné. Cependant, il est important de considérer les scénarios suivants:

  • Si la propriété que vous cherchez à supprimer n'existe pas, supprimer n'aura aucun effet et retournera true

  • si une propriété du même nom existe sur le prototype de l'objet chaîne, puis, après suppression, l'objet utilisera la propriété de la chaîne prototype (en d'autres termes, supprimer n'a qu'un effet propre propriété.)

  • tout bien déclaré Avec var ne peut être supprimé du champ d'Application global ou à partir de la portée d'une fonction.

  • en tant que telle, supprimer ne peut supprimer aucune fonction dans le champ d'Application global (qu'il s'agisse d'une partie d'une définition de fonction ou d'une fonction (expression).

  • fonctions qui font partie d'un objet (à l'exception des

    )" de portée mondiale) peuvent être supprimés avec supprimer.

  • tout bien déclaré avec let ou const ne peut être supprimé du champ d'application dans lequel il a été défini. Les propriétés non configurables ne peuvent pas être supprimées. Cela inclut les propriétés des objets intégrés comme les mathématiques, les tableaux, les objets et les propriétés qui sont créés comme non configurables avec des méthodes comme objet.defineProperty ().

l'extrait suivant donne un autre exemple simple:

var Employee = {
      age: 28,
      name: 'abc',
      designation: 'developer'
    }
    
    console.log(delete Employee.name);   // returns true
    console.log(delete Employee.age);    // returns true
    
    // When trying to delete a property that does 
    // not exist, true is returned 
    console.log(delete Employee.salary); // returns true

pour plus d'informations et voir plus d'exemples, visitez le lien ci-dessous:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete

15
répondu Alireza 2018-07-31 06:56:03

si vous voulez supprimer une propriété profondément imbriquée dans l'objet, vous pouvez utiliser la fonction récursive suivante avec le chemin de la propriété comme second argument:

var deepObjectRemove = function(obj, path_to_key){
    if(path_to_key.length === 1){
        delete obj[path_to_key[0]];
        return true;
    }else{
        if(obj[path_to_key[0]])
            return deepObjectRemove(obj[path_to_key[0]], path_to_key.slice(1));
        else
            return false;
    }
};

exemple:

var a = {
    level1:{
        level2:{
            level3: {
                level4: "yolo"
            }
        }
    }
};

deepObjectRemove(a, ["level1", "level2", "level3"]);
console.log(a);

//Prints {level1: {level2: {}}}
10
répondu ayushgp 2016-06-23 09:38:58

Essayez la méthode suivante. Attribuer la valeur du bien Object à undefined . Puis stringify l'objet et parse .

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

myObject.regex = undefined;
myObject = JSON.parse(JSON.stringify(myObject));

console.log(myObject);
10
répondu Mohammed Safeer 2016-11-22 22:12:14

utilisant ramda#dissoc vous obtiendrez un nouvel objet sans l'attribut regex :

const newObject = R.dissoc('regex', myObject);
// newObject !== myObject

vous pouvez également utiliser d'autres fonctions pour obtenir le même effet - omit, pick, ...

10
répondu zatziky 2016-11-28 15:14:52

vous pouvez simplement supprimer n'importe quelle propriété d'un objet en utilisant le mot-clé delete .

par exemple:

var obj = {key1:"val1",key2:"val2",key3:"val3"}

pour supprimer une propriété, dites key1 , utilisez le delete mot-clé comme ceci:

delete obj.key1

ou vous pouvez également utiliser la notation de type tableau:

delete obj[key1]

Ref: MDN .

5
répondu Kalpesh Patel 2016-11-22 22:11:24

étendre la Syntaxe (ES6)

à qui en a besoin...

pour compléter la réponse de @Koen dans ce thread, si vous voulez supprimer une variable dynamique en utilisant la syntaxe spread, vous pouvez le faire comme suit:

const key = 'a';

const { [key]: foo, ...rest } = { a: 1, b: 2, c: 3 };

console.log(rest); // { b: 2, c: 3 }

* foo sera une nouvelle variable avec la valeur de a (qui est 1).

5
répondu Lior Elrom 2018-09-25 17:54:55

Essayez cette

delete myObject['key'];
3
répondu codemirror 2017-05-26 06:58:29

Bonjour, Vous Pouvez essayer cette simple une sorte de

var obj = [];

obj.key1 = {name: "John", room: 1234};
obj.key2 = {name: "Jim", room: 1234};

delete(obj.key1);
3
répondu Dhaval Gohel 2017-05-26 09:28:09

L'affirmation de Dan selon laquelle "supprimer" est très lente et le point de référence qu'il a affiché a été mis en doute. J'ai donc effectué le test moi-même dans Chrome 59. Il semble que 'delete' soit environ 30 fois plus lent:

var iterationsTotal = 10000000;  // 10 million
var o;
var t1 = Date.now(),t2;
for (let i=0; i<iterationsTotal; i++) {
   o = {a:1,b:2,c:3,d:4,e:5};
   delete o.a; delete o.b; delete o.c; delete o.d; delete o.e;
}
console.log ((t2=Date.now())-t1);  // 6135
for (let i=0; i<iterationsTotal; i++) {
   o = {a:1,b:2,c:3,d:4,e:5};
   o.a = o.b = o.c = o.d = o.e = undefined;
}
console.log (Date.now()-t2);  // 205

Notez que je purposedly effectué plus d'une "supprimer" dans l'un de la boucle afin de minimiser l'effet causé par les autres opérations.

3
répondu Chong Lip Phang 2017-07-26 07:19:30

envisagez de créer un nouvel objet sans la propriété "regex" parce que l'objet original pourrait toujours être référencé par d'autres parties de votre programme. Vous devez donc éviter de la manipuler.

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

const { regex, ...newMyObject } = myObject;

console.log(newMyObject);
3
répondu ideaboxer 2017-10-23 10:06:31

objet.assign() & Objet.les touches() & Matrice.carte ()

const obj = {
    "Filters":[
        {
            "FilterType":"between",
            "Field":"BasicInformationRow.A0",
            "MaxValue":"2017-10-01",
            "MinValue":"2017-09-01",
            "Value":"Filters value"
        }
    ]
};

let new_obj1 = Object.assign({}, obj.Filters[0]);
let new_obj2 = Object.assign({}, obj.Filters[0]);

/*

// old version

let shaped_obj1 = Object.keys(new_obj1).map(
    (key, index) => {
        switch (key) {
            case "MaxValue":
                delete new_obj1["MaxValue"];
                break;
            case "MinValue":
                delete new_obj1["MinValue"];
                break;
        }
        return new_obj1;
    }
)[0];


let shaped_obj2 = Object.keys(new_obj2).map(
    (key, index) => {
        if(key === "Value"){
            delete new_obj2["Value"];
        }
        return new_obj2;
    }
)[0];


*/


// new version!

let shaped_obj1 = Object.keys(new_obj1).forEach(
    (key, index) => {
        switch (key) {
            case "MaxValue":
                delete new_obj1["MaxValue"];
                break;
            case "MinValue":
                delete new_obj1["MinValue"];
                break;
            default:
                break;
        }
    }
);

let shaped_obj2 = Object.keys(new_obj2).forEach(
    (key, index) => {
        if(key === "Value"){
            delete new_obj2["Value"];
        }
    }
);
3
répondu xgqfrms-gildata 2017-11-10 06:36:12

suppression de propriété en JavaScript

il y a beaucoup d'options différentes présentées sur cette page, non pas parce que la plupart des options sont fausses-ou parce que les réponses sont des doubles-mais parce que la technique appropriée dépend de la situation dans laquelle vous êtes et les objectifs des tâches que vous et/ou votre équipe essayez d'accomplir. Pour vous répondre sans équivoque, il faut savoir:

  1. la version D'ECMAScript que vous ciblez
  2. la gamme des types d'objets sur lesquels vous voulez supprimer des propriétés et le type de noms de propriétés dont vous avez besoin pour être en mesure d'omettre (chaînes seulement? Symboles? Faibles références cartographiées à partir d'objets arbitraires? Ce sont tous des types de pointeurs de propriétés en JavaScript depuis des années maintenant)
  3. La programmation de l'ethos/motifs, vous et votre équipe, à utiliser. Favorisez-vous les approches fonctionnelles et la mutation est verboten dans votre équipe, ou utilisez-vous wild west mutative des techniques orientées objet?
  4. cherchez-vous à atteindre cet objectif en JavaScript pur ou Êtes-vous prêt et capable d'utiliser une bibliothèque tierce?

une fois que ces quatre questions ont été répondues, il y a essentiellement quatre catégories de" suppression de propriété " en JavaScript à choisir afin d'atteindre vos objectifs. Ce sont:

Mutative propriété de l'objet de la suppression, "dangereux

Cette catégorie est pour opérer sur des objets littéraux ou des instances d'objets quand vous voulez conserver/continuer à utiliser la référence originale et n'utilisez pas des principes fonctionnels apatrides dans votre code. Un exemple de syntaxe dans cette catégorie:

'use strict'
const iLikeMutatingStuffDontI = { myNameIs: 'KIDDDDD!', [Symbol.for('amICool')]: true }
delete iLikeMutatingStuffDontI[Symbol.for('amICool')] // true
Object.defineProperty({ myNameIs: 'KIDDDDD!', 'amICool', { value: true, configurable: false })
delete iLikeMutatingStuffDontI['amICool'] // throws

cette catégorie est la plus ancienne, la plus simple et la plus largement soutenue catégorie de l'enlèvement de la propriété. Il prend en charge les index Symbol & array en plus des chaînes et fonctionne dans toutes les versions de JavaScript, sauf pour le très la première version. Toutefois, il s'agit d'une méthode mutative qui viole certains principes de programmation et qui a des répercussions sur le rendement. Il peut également donner lieu à des exceptions uncaught lorsqu'il est utilisé sur propriétés non configurables en mode strict .

Rest propriété de chaîne d'omission

cette catégorie est pour fonctionner sur un objet simple ou un tableau d'instances dans les nouvelles saveurs ECMAScript quand une approche non-mutative est souhaitée et que vous n'avez pas besoin de tenir compte des touches de symboles:

const foo = { name: 'KIDDDDD!', [Symbol.for('isCool')]: true }
const { name, ...coolio } = foo // coolio doesn't have "name"
const { isCool, ...coolio2 } = foo // coolio2 has everything from `foo` because `isCool` doesn't account for Symbols :(

Mutative propriété de l'objet de la suppression, coffre-fort

cette catégorie est pour opérer sur des littérales d'objet ou des instances d'objet quand vous voulez conserver/continuer à utiliser la référence originale tout en gardant contre les exceptions étant lancées sur des propriétés non configurables:

'use strict'
const iLikeMutatingStuffDontI = { myNameIs: 'KIDDDDD!', [Symbol.for('amICool')]: true }
Reflect.deleteProperty(iLikeMutatingStuffDontI, Symbol.for('amICool')) // true
Object.defineProperty({ myNameIs: 'KIDDDDD!', 'amICool', { value: true, configurable: false })
Reflect.deleteProperty(iLikeMutatingStuffDontI, 'amICool') // false

en outre, bien que les objets en mutation sur place ne soit pas apatride, vous pouvez utiliser la nature fonctionnelle de Reflect.deleteProperty pour faire une application partielle et d'autres techniques fonctionnelles qui ne sont pas possibles avec les énoncés delete .

omission de propriété de chaîne de caractères basée sur la syntaxe

cette catégorie est pour fonctionner sur un objet simple ou un tableau d'instances dans les nouvelles saveurs ECMAScript quand une approche non-mutative est souhaitée et que vous n'avez pas besoin de tenir compte des clés de symbole:

const foo = { name: 'KIDDDDD!', [Symbol.for('isCool')]: true }
const { name, ...coolio } = foo // coolio doesn't have "name"
const { isCool, ...coolio2 } = foo // coolio2 has everything from `foo` because `isCool` doesn't account for Symbols :(

omission de biens de bibliothèque

cette catégorie permet généralement une plus grande souplesse fonctionnelle, y compris la comptabilisation des symboles et l'omission de plus d'un bien dans un même état:

const o = require("lodash.omit")
const foo = { [Symbol.for('a')]: 'abc', b: 'b', c: 'c' }
const bar = o(foo, 'a') // "'a' undefined"
const baz = o(foo, [ Symbol.for('a'), 'b' ]) // Symbol supported, more than one prop at a time, "Symbol.for('a') undefined"
3
répondu james_womack 2017-12-14 02:35:29

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

const { regex, ...other } = myObject;

console.log(myObject)
console.log(regex)
console.log(other)
3
répondu xiang 2018-02-06 04:28:57

utilisant ES6:

(destructeur + répartiteur)

    const myObject = {
      regex: "^http://.*",
      b: 2,
      c: 3
    };
    const { regex, ...noRegex } = myObject;
    console.log(noRegex); // => { b: 2, c: 3 }
3
répondu Srinivas 2018-07-23 15:52:01

très simple:

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

delete myObject.regex;
1
répondu Behnam Mohammadi 2017-07-09 18:26:35

utilisant lodash

import omit from 'lodash/omit';

const prevObject = {test: false, test2: true};
// Removes test2 key from previous object
const nextObject = omit(prevObject, 'test2');

Utilisant Ramda

R.omit(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, c: 3}
1
répondu johndavedecano 2017-09-14 14:14:07