Comment supprimer des objets d'un tableau associatif javascript?

619

Supposons que j'ai ce code:

var myArray = new Object();
myArray["firstname"] = "Bob";
myArray["lastname"] = "Smith";
myArray["age"] = 25;

Maintenant, si je voulais supprimer "nom"? .... y a-t-il un équivalent de
myArray["lastname"].remove()?

(J'ai besoin que l'élément disparaisse parce que le nombre d'éléments est important et je veux garder les choses propres.)

djot
la source
27
Un conseil: ne confondez pas les tableaux et les cartes. Certaines langues, comme php, ont un seul objet pour les deux. Bien que vous ayez utilisé le bon type ici (nouvel objet ()), vous l'avez nommé myArray, ce n'est qu'une question de normes pour un langage.
Juan Mendes
N'oubliez pas que JavaScript est sans type et que tout est un objet. Voir la réponse de Saul ci-dessous.
stevek
4
@StephanKristyn - pour être précis, JS a des types mais de manière dynamique et faible . Par exemple, alors que ses variables sont en effet sans type, leurs valeurs ne le sont pas. C'est la partie dynamique . Faible indique que les opérations entre différents types de valeurs ne sont pas strictement définies et reposent sur des conversions en arrière-plan; par exemple, "Test" + {};est une instruction JS parfaitement valide.
Saul

Réponses:

1135

Les objets en JavaScript peuvent être considérés comme des tableaux associatifs, mappant des clés (propriétés) à des valeurs.

Pour supprimer une propriété d'un objet en JavaScript, vous utilisez l' deleteopérateur:

const o = { lastName: 'foo' }
o.hasOwnProperty('lastName') // true
delete o['lastName']
o.hasOwnProperty('lastName') // false

Notez que lorsqu'il deleteest appliqué à une propriété d'index d'un Array, vous créerez un tableau peu peuplé (c'est-à-dire un tableau avec un index manquant).

Lorsque vous travaillez avec des instances de Array, si vous ne souhaitez pas créer un tableau peu peuplé - et ce n'est généralement pas le cas -, vous devez utiliser Array#spliceou Array#pop.

Notez que l' deleteopérateur en JavaScript ne libère pas directement la mémoire. Son but est de supprimer les propriétés des objets. Bien sûr, si une propriété en cours de suppression contient la seule référence restante à un objet o, elle osera par la suite récupérée de manière normale.

L'utilisation de l' deleteopérateur peut affecter la capacité des moteurs JavaScript à optimiser le code .

Dennis C
la source
18
Cela causera des problèmes s'il est utilisé sur une instance d'objet Array pour supprimer un élément existant, par exemple delete myArray[0]. Voir stackoverflow.com/a/9973592/426379 et Suppression d'éléments de tableau
Saul
4
Quels problèmes seront causés?
Gottox
26
@Gottox - La lengthpropriété d'un objet Array reste inchangée.
Saul
12
@Saul: il y aurait des problèmes s'il myArrayétait vraiment utilisé comme un tableau - mais ce n'est pas le cas ( myArrayc'est un nom malheureux), c'est un objet. Donc, dans ce cas, deletec'est OK. Notez que même s'il était créé en tant new Array()que tableau associatif et utilisé, il serait toujours correct. Votre avertissement est toujours quelque chose à savoir si l'on utilise de vrais tableaux.
johndodo
2
@johndodo - Vrai. C'est pourquoi j'ai commencé mon commentaire initial avec Cela causera des problèmes s'il est utilisé sur une instance d'objet Array . Je préfère néanmoins une approche qui fonctionne correctement dans tous les cas, voir ma réponse ci-dessous.
Saul
79

Tous les objets en JavaScript sont implémentés en tant que tables de hachage / tableaux associatifs. Donc, ce qui suit est l'équivalent:

alert(myObj["SomeProperty"]);
alert(myObj.SomeProperty);

Et, comme déjà indiqué, vous "supprimez" une propriété d'un objet via le deletemot - clé, que vous pouvez utiliser de deux manières:

delete myObj["SomeProperty"];
delete myObj.SomeProperty;

J'espère que les informations supplémentaires vous aideront ...

Jason Bunting
la source
10
il convient de noter que la notation par points ne fonctionne pas si la propriété n'est pas un terme simple. c'est à dire myObj['some;property']fonctionne, mais myObj.some;propertyne serait pas (pour des raisons évidentes). De plus, il peut ne pas être évident que vous pouvez utiliser une variable dans la notation des crochets, c'estvar x = 'SomeProperty'; alert(myObj[x])
Kip
2
"Tous les objets en JavaScript sont implémentés en tant que tables de hachage / tableaux associatifs." - false. V8 préfère stocker un objet en tant que classe cachée + champs densément compressés. Seulement si vous leur faites des trucs bizarres (comme la suppression de champs), il abandonne et utilise une carte de hachage dans les coulisses.
John Dvorak
4
@JanDvorak - hé, vous savez quand cette réponse a été écrite à l'origine, oui? Cette description était et est toujours suffisante pour la plupart des fins. Cela dit, je comprends être fastidieusement pédant. :)
Jason Bunting
41

Aucune des réponses précédentes ne traite du fait que Javascript n'a pas de tableaux associatifs pour commencer - il n'y a pas de arraytype en tant que tel, voir typeof.

Ce que Javascript a, ce sont des instances d'objets avec des propriétés dynamiques. Lorsque les propriétés sont confondues avec des éléments d'une instance d'objet Array, alors Bad Things ™ est susceptible de se produire:

Problème

var elements = new Array()

elements.push(document.getElementsByTagName("head")[0])
elements.push(document.getElementsByTagName("title")[0])
elements["prop"] = document.getElementsByTagName("body")[0]

console.log("number of elements: ", elements.length)   // returns 2
delete elements[1]
console.log("number of elements: ", elements.length)   // returns 2 (?!)

for (var i = 0; i < elements.length; i++)
{
   // uh-oh... throws a TypeError when i == 1
   elements[i].onmouseover = function () { window.alert("Over It.")}
   console.log("success at index: ", i)
}

Solution

Pour avoir une fonction de suppression universelle qui ne vous explose pas, utilisez:

Object.prototype.removeItem = function (key) {
   if (!this.hasOwnProperty(key))
      return
   if (isNaN(parseInt(key)) || !(this instanceof Array))
      delete this[key]
   else
      this.splice(key, 1)
};

//
// Code sample.
//
var elements = new Array()

elements.push(document.getElementsByTagName("head")[0])
elements.push(document.getElementsByTagName("title")[0])
elements["prop"] = document.getElementsByTagName("body")[0]

console.log(elements.length)                        // returns 2
elements.removeItem("prop")
elements.removeItem(0)
console.log(elements.hasOwnProperty("prop"))        // returns false as it should
console.log(elements.length)                        // returns 1 as it should
Saul
la source
8
Cette solution a deux problèmes: elle cache le fait que les tableaux et les objets sont des bêtes entièrement différentes dans JS (vous le savez, mais apparemment OP ne le fait pas) et elle utilise des prototypes. OP serait mieux s'il apprenait les tableaux et les objets (et nommerait ses variables en conséquence) - essayer de cacher les différences entre les deux ne fera que lui causer plus de problèmes. À mon humble avis, bien sûr.
johndodo
1
@johndodo - tous les Arrays dans JS sont des objets, essayez typeof new Array();ou typeof []pour vérifier. Arrayest simplement un certain type d'objet et pas du tout une "bête différente". Dans JS, les objets se distinguent par leur nom de constructeur et leur chaîne de prototypes, voir Programmation basée sur des prototypes .
Saul
9
Vous manquez le point. Je sais que les tableaux sont également des objets, mais cela ne signifie pas qu'il est sage de les utiliser en tant que tels. Le programmeur doit décider s'il veut utiliser quelque chose comme tableau (avec push, pop, [], ...) ou comme objet / "tableau associatif". Mélanger et assortir n'est pas une bonne recette, précisément en raison des problèmes que votre solution tente de cacher. Si vous décidez à l'avance du modèle de conception à utiliser (tableau ou objet), il n'y aura pas de tels problèmes.
johndodo
7
@johndodo - De quels problèmes parlez-vous précisément? Le but du code ci-dessus est d'adresser l' deleteopérateur de carence en ce qui concerne Arrayen fournissant une fonction polymorphe simple.
Saul
1
deleten'a pas de carence. deleteest conçu pour supprimer les propriétés. C'est ça. L'application de l'opérateur de suppression à un index d'un tableau supprime cet index. Que faut-il de plus? Vous vous retrouvez avec un tableau clairsemé, qui est une caractéristique de la langue. Si vous ne voulez pas d'un tableau clairsemé, ne supprimez pas l'index: utilisez spliceou pop.
Ben Aston
35

Cela ne supprime que l'objet, mais conserve la même longueur de tableau.

Pour supprimer, vous devez faire quelque chose comme:

array.splice(index, 1);
Bipin
la source
11
En effet, mais dans ce cas, un tableau n'est pas utilisé, juste un vieil objet ordinaire, donc il n'a pas de méthode de longueur ou d'épissage.
MooGoo
2
@Andreaa Panagiotidis Sauf que nous ne parlons pas de tableaux, dans ce cas , il est faux à 100% du temps 🙂
Drenai
17

Bien que la réponse acceptée soit correcte, il manque l'explication pourquoi cela fonctionne.

Tout d'abord, votre code doit refléter le fait qu'il ne s'agit PAS d' un tableau:

var myObject = new Object();
myObject["firstname"] = "Bob";
myObject["lastname"] = "Smith";
myObject["age"] = 25;

Notez que tous les objets (y compris Arrays) peuvent être utilisés de cette façon. Cependant, ne vous attendez pas à ce que les fonctions de tableau JS standard (pop, push, ...) fonctionnent sur les objets!

Comme indiqué dans la réponse acceptée, vous pouvez ensuite utiliser deletepour supprimer les entrées des objets:

delete myObject["lastname"]

Vous devez décider de l'itinéraire que vous souhaitez emprunter - utilisez des objets (tableaux associatifs / dictionnaires) ou utilisez des tableaux (cartes). Ne mélangez jamais les deux.

johndodo
la source
6
Très bonne réponse. Je conseillerais seulement à tous ceux qui lisent ceci que les tableaux en javascript ne doivent pas être résumés en tant que «cartes», mais plutôt «listes». C'est parce que vous ne devez pas essayer de contrôler l'index des éléments lorsque vous utilisez des tableaux. Si vous essayez cela ... eh bien, ne le faites tout simplement pas: D
rodolfo42
6

Utilisez la méthode splicepour supprimer complètement l'élément d'un tableau d'objets:

Object.prototype.removeItem = function (key, value) {
    if (value == undefined)
        return;

    for (var i in this) {
        if (this[i][key] == value) {
            this.splice(i, 1);
        }
    }
};

var collection = [
    { id: "5f299a5d-7793-47be-a827-bca227dbef95", title: "one" },
    { id: "87353080-8f49-46b9-9281-162a41ddb8df", title: "two" },
    { id: "a1af832c-9028-4690-9793-d623ecc75a95", title: "three" }
];

collection.removeItem("id", "87353080-8f49-46b9-9281-162a41ddb8df");
HarpyWar
la source
1
il s'agit d'une solution plus générique, qui peut être ajoutée à votre fichier js et la méthode sera disponible pour tous les tableaux, pas seulement un tableau.
Hussain
6

Comme d'autres réponses l'ont noté, ce que vous utilisez n'est pas un tableau Javascript, mais un objet Javascript, qui fonctionne presque comme un tableau associatif dans d'autres langues, sauf que toutes les clés sont converties en chaînes. La nouvelle carte stocke les clés comme leur type d'origine.

Si vous aviez un tableau et non un objet, vous pouvez utiliser la fonction .filter du tableau , pour renvoyer un nouveau tableau sans l'élément que vous souhaitez supprimer:

var myArray = ['Bob', 'Smith', 25];
myArray = myArray.filter(function(item) {
    return item !== 'Smith';
});

Si vous avez un navigateur plus ancien et jQuery, jQuery a une $.grepméthode qui fonctionne de la même manière:

myArray = $.grep(myArray, function(item) {
    return item !== 'Smith';
});
Dzeimsas Zvirblis
la source
explication parfaite. J'ai utilisé un filtre pour obtenir le résultat souhaité. Pourriez-vous expliquer comment fonctionne l'élément de retour pour supprimer l'objet du tableau. Je suppose qu'il renvoie le tableau tant qu'il n'inclut pas la chaîne que vous avez incluse.
Edward
5

Vous utilisez Object, vous n'avez pas de tableau associatif pour commencer. Avec un tableau associatif, l'ajout et la suppression d'éléments se fait comme suit:

    Array.prototype.contains = function(obj) 
    {
        var i = this.length;
        while (i--) 
        {
            if (this[i] === obj) 
            {
                return true;
            }
        }
        return false;
    }


    Array.prototype.add = function(key, value) 
    {
        if(this.contains(key))
            this[key] = value;
        else
        {
            this.push(key);
            this[key] = value;
        }
    }


    Array.prototype.remove = function(key) 
    {
        for(var i = 0; i < this.length; ++i)
        {
            if(this[i] == key)
            {
                this.splice(i, 1);
                return;
            }
        }
    }



    // Read a page's GET URL variables and return them as an associative array.
    function getUrlVars()
    {
        var vars = [], hash;
        var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');

        for(var i = 0; i < hashes.length; i++)
        {
            hash = hashes[i].split('=');
            vars.push(hash[0]);
            vars[hash[0]] = hash[1];
        }

        return vars;
    }



    function ForwardAndHideVariables() {
        var dictParameters = getUrlVars();

        dictParameters.add("mno", "pqr");
        dictParameters.add("mno", "stfu");

        dictParameters.remove("mno");



        for(var i = 0; i < dictParameters.length; i++)
        {
            var key = dictParameters[i];
            var value = dictParameters[key];
            alert(key + "=" + value);
        }
        // And now forward with HTTP-POST
        aa_post_to_url("Default.aspx", dictParameters);
    }


    function aa_post_to_url(path, params, method) {
        method = method || "post";

        var form = document.createElement("form");

        //move the submit function to another variable
        //so that it doesn't get written over if a parameter name is 'submit'
        form._submit_function_ = form.submit;

        form.setAttribute("method", method);
        form.setAttribute("action", path);

        for(var i = 0; i < params.length; i++)
        {
            var key = params[i];

            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("type", "hidden");
            hiddenField.setAttribute("name", key);
            hiddenField.setAttribute("value", params[key]);

            form.appendChild(hiddenField);
        }

        document.body.appendChild(form);
        form._submit_function_(); //call the renamed function
    }
Stefan Steiger
la source
4

Vous pouvez supprimer une entrée de votre carte en l'affectant explicitement à «non défini». Comme dans votre cas:

myArray ["lastname"] = undefined;

Amytis
la source
Cela pourrait être utile dans les cas où l'on n'est pas sûr que la clé existe dans le dictionnaire, mais que l'on souhaite la nettoyer au cas où elle existe. Corrigez-moi si je me trompe Amytis.
Hassan Baig
3

Si pour une raison quelconque, la touche de suppression ne fonctionne pas (comme si elle ne fonctionnait pas pour moi)

Vous pouvez l'épisser puis filtrer les valeurs indéfinies

// to cut out one element via arr.splice(indexToRemove, numberToRemove);
array.splice(key, 1)
array.filter(function(n){return n});

N'essayez pas de les enchaîner car l'épissure renvoie les éléments supprimés;

Léon
la source
3

Nous pouvons également l'utiliser comme fonction. Angular génère une erreur s'il est utilisé comme prototype. Merci @HarpyWar. Cela m'a aidé à résoudre un problème.

var removeItem = function (object, key, value) {
    if (value == undefined)
        return;

    for (var i in object) {
        if (object[i][key] == value) {
            object.splice(i, 1);
        }
    }
};

var collection = [
    { id: "5f299a5d-7793-47be-a827-bca227dbef95", title: "one" },
    { id: "87353080-8f49-46b9-9281-162a41ddb8df", title: "two" },
    { id: "a1af832c-9028-4690-9793-d623ecc75a95", title: "three" }
];

removeItem(collection, "id", "87353080-8f49-46b9-9281-162a41ddb8df");
Omkar Kamale
la source
2

C'est très simple si vous avez une dépendance underscore.js dans votre projet -

_.omit(myArray, "lastname")
vatsal
la source
1

En utilisant le "delete"mot - clé, il supprimera l'élément de tableau du tableau en javascript.

Par exemple,

Considérez les déclarations suivantes.

var arrayElementToDelete = new Object();

arrayElementToDelete["id"]           = "XERTYB00G1"; 
arrayElementToDelete["first_name"]   = "Employee_one";
arrayElementToDelete["status"]       = "Active"; 

delete arrayElementToDelete["status"];

La dernière ligne du code supprimera l'élément du tableau dont la clé est "status" du tableau.

Ravindra Miyani
la source
0
var myArray = newmyArray = new Object(); 
myArray["firstname"] = "Bob";
myArray["lastname"] = "Smith";
myArray["age"] = 25;

var s = JSON.stringify(myArray);

s.replace(/"lastname[^,}]+,/g,'');
newmyArray = JSON.parse(p);

Sans boucle / itération nous obtenons le même résultat

Lalith kumar
la source
0

Pour les "tableaux":

Si vous connaissez l'indice:

array.splice(index, 1);

Si vous connaissez la valeur:

function removeItem(array, value) {
    var index = array.indexOf(value);
    if (index > -1) {
        array.splice(index, 1);
    }
    return array;
}

La réponse la plus appréciée pour deletefonctionne bien dans le cas d'objets mais pas pour les vrais tableaux. Si je l'utilise, deleteil supprime les éléments des boucles mais conserve l'élément au fur emptyet à mesure que la longueur du tableau ne change pas. Cela peut être un problème dans certains scénarios.

Par exemple, si je fais myArray.toString () sur myArray après la suppression via delete il crée une entrée vide, c'est-à-dire ,,

Arvind K.
la source
0

La seule méthode de travail pour moi:

function removeItem (array, value) {
    var i = 0;
    while (i < array.length) {
        if(array[i] === value) {
            array.splice(i, 1);
        } else {
            ++i;
        }
    }
    return array;
}

usage:

var new = removeItem( ["apple","banana", "orange"],  "apple");
// ---> ["banana", "orange"]
T.Todua
la source
Pourquoi ne pas utiliser le filtre à la place? c'est un cas d'utilisation parfait pour le filtre
Code Maniac