Como faço para remover objetos de uma matriz associativa javascript?

619

Suponha que eu tenha esse código:

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

Agora, se eu queria remover "sobrenome"? .... existe algum equivalente a
myArray["lastname"].remove()?

(Preciso que o elemento seja removido porque o número de elementos é importante e quero manter as coisas limpas.)

djot
fonte
27
Uma dica: não confunda matrizes e mapas. Alguns idiomas, como o php, têm um único objeto para ambos. Embora você tenha usado o tipo certo aqui (novo Object ()) com o nome myArray, é apenas uma questão de padrões para uma linguagem.
Juan Mendes
Não se esqueça que o JavaScript é sem tipo e tudo é um objeto. Veja a resposta de Saul abaixo.
SteveK
4
@StephanKristyn - para ser mais preciso, o JS tem tipos, mas de maneira dinâmica e fraca . Por exemplo, embora suas variáveis ​​não sejam realmente sem tipo, seus valores não são. Essa é a parte dinâmica . Fraco indica que as operações entre diferentes tipos de valor não são estritamente definidas e dependem de conversões nos bastidores; por exemplo, "Test" + {};é uma instrução JS perfeitamente válida.
Saul

Respostas:

1135

Objetos em JavaScript podem ser vistos como matrizes associativas, mapeando chaves (propriedades) para valores.

Para remover uma propriedade de um objeto em JavaScript, use o deleteoperador:

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

Observe que quando deleteaplicado a uma propriedade de índice de um Array, você criará uma matriz escassamente povoada (ou seja, uma matriz com um índice ausente).

Ao trabalhar com instâncias de Array, se você não deseja criar uma matriz escassamente povoada - e geralmente não o faz -, use Array#spliceou Array#pop.

Observe que o deleteoperador em JavaScript não libera memória diretamente. Seu objetivo é remover propriedades dos objetos. Obviamente, se uma propriedade que está sendo excluída tiver a única referência restante para um objeto o, ela oserá posteriormente coletada como lixo normalmente.

O uso do deleteoperador pode afetar a capacidade dos mecanismos JavaScript de otimizar o código .

Dennis C
fonte
18
Isso causará problemas se usado em uma instância de objeto Array para remover um elemento existente, por exemplo delete myArray[0]. Consulte stackoverflow.com/a/9973592/426379 e Excluindo elementos da matriz
Saul
4
Que problemas serão causados?
Gottox
26
@Gottox - A lengthpropriedade de um objeto Array permanece inalterada.
Saul
12
@ Saul: haveria problemas se myArrayrealmente fosse usado como uma matriz - mas não é ( myArrayé um nome lamentável), é um objeto. Então, neste caso, deleteestá OK. Observe que, mesmo que tenha sido criado como new Array()e usado como matriz associativa, ainda estará OK. Seu aviso ainda é algo a ter em atenção se estiver usando matrizes reais.
amigos estão dizendo sobre johndodo
2
@johndodo - Verdade. É por isso que iniciei meu comentário inicial com Isso causará problemas se usado em uma instância de objeto Array . No entanto, prefiro uma abordagem que funcione corretamente em todos os casos, veja minha resposta abaixo.
Saul
79

Todos os objetos em JavaScript são implementados como hashtables / matrizes associativas. Portanto, o seguinte é o equivalente:

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

E, como já indicado, você "remove" uma propriedade de um objeto por meio da deletepalavra - chave, que pode ser usada de duas maneiras:

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

Espero que a informação extra ajude ...

Jason Bunting
fonte
10
Note-se que a notação de ponto não funciona se a propriedade não for um termo simples. ou seja myObj['some;property'], funciona, mas myObj.some;propertynão funcionaria (por razões óbvias). Além disso, pode não ser óbvio que você pode usar uma variável na notação de colchete, ou seja,var x = 'SomeProperty'; alert(myObj[x])
Kip
2
"Todos os objetos em JavaScript são implementados como hashtables / matrizes associativas." - false. A V8 prefere armazenar um objeto como uma classe oculta + campos densamente compactados. Somente se você fizer coisas estranhas para eles (como remover campos), ele desiste e usa um mapa de hash nos bastidores.
John Dvorak
4
@JanDvorak - ei, você reconhece quando esta resposta foi originalmente escrita, sim? Essa descrição foi e ainda é suficiente para a maioria dos propósitos. Dito isto, eu entendo ser tediosamente pedante. :)
Jason Bunting
41

Nenhuma das respostas anteriores aborda o fato de que o Javascript não possui matrizes associativas para começar - não há nenhum arraytipo como tal, consulte typeof.

O que o Javascript possui, são instâncias de objetos com propriedades dinâmicas. Quando as propriedades são confundidas com elementos de uma instância de objeto Array, Bad Things ™ acontece:

Problema

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)
}

Solução

Para ter uma função de remoção universal que não explode em você, use:

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
fonte
8
Essa solução tem dois problemas: oculta o fato de que matrizes e objetos são bestas totalmente diferentes em JS (você sabe disso, mas aparentemente OP não) e usa protótipos. O OP seria melhor se ele aprendesse sobre matrizes e objetos (e nomeasse suas variáveis ​​de acordo) - tentar esconder as diferenças entre os dois só o colocará em mais problemas. IMHO é claro.
Johndodo 04/04
1
@johndodo - todos os Arrays em JS são objetos, tente typeof new Array();ou typeof []verifique. Arrayé simplesmente um certo tipo de objeto e não um "animal diferente". Em JS, os objetos são diferenciados pelo nome do construtor e pela cadeia de protótipos, consulte Programação baseada em protótipo .
Saul
9
Você está perdendo o ponto. Eu sei que matrizes também são objetos, mas isso não significa que é aconselhável usá-las como tal. O programador deve decidir se deseja usar algo como array (com push, pop, [], ...) ou como objeto / "array associativo". Misturar e combinar não é uma boa receita, exatamente por causa dos problemas que sua solução está tentando ocultar. Se você decidir com antecedência qual padrão de design usar (matriz ou objeto), não haverá esses problemas.
Johndodo #
7
@johndodo - De que problemas você está falando especificamente? O objetivo do código acima é abordar o deleteoperador de deficiência em relação ao Arrayfornecimento de uma função polimórfica simples.
Saul
1
deletenão tem deficiência. deletefoi projetado para remover propriedades. É isso aí. A aplicação do operador de exclusão a um índice de uma matriz remove esse índice. O que mais precisa fazer? Você fica com uma matriz esparsa, que é um recurso do idioma. Se você não deseja uma matriz esparsa, não exclua o índice: use spliceou pop.
Ben Aston
35

Isso remove apenas exclui o objeto, mas ainda mantém o mesmo comprimento da matriz.

Para remover, você precisa fazer algo como:

array.splice(index, 1);
Bipin
fonte
11
De fato, mas neste caso uma matriz não está sendo usada, apenas um objeto antigo simples, portanto, não possui método de comprimento ou de emenda.
MooGoo 13/09/10
2
@Andreaa Panagiotidis Exceto quando não estamos a falar de matrizes, caso em que é errado 100% do tempo 🙂
Drenai
17

Embora a resposta aceita esteja correta, falta a explicação do motivo pelo qual ela funciona.

Primeiro de tudo, seu código deve refletir o fato de que NÃO é uma matriz:

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

Observe que todos os objetos (incluindo Arrays) podem ser usados ​​dessa maneira. No entanto, não espere que as funções padrão da matriz JS (pop, push, ...) funcionem em objetos!

Como dito na resposta aceita, você pode usar deletepara remover as entradas dos objetos:

delete myObject["lastname"]

Você deve decidir qual rota deseja seguir - use objetos (matrizes / dicionários associativos) ou use matrizes (mapas). Nunca misture os dois.

johndodo
fonte
6
Resposta muito boa. Eu recomendaria apenas a quem lê isso que Arrays em javascript não devem ser abstraídos como 'mapas', mas 'listas'. Isso ocorre porque você não deve tentar controlar o índice dos elementos ao usar matrizes. Se você tentar isso ... bem, apenas não: D
rodolfo42 4/14
6

Use o método splicepara remover completamente o item de uma matriz de objetos:

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
fonte
1
esta é uma solução mais genérica, pode ser adicionada ao seu arquivo js e o método estará disponível para todas as matrizes, não apenas uma matriz.
Hussain
6

Como outras respostas observaram, o que você está usando não é uma matriz Javascript, mas um objeto Javascript, que funciona quase como uma matriz associativa em outros idiomas, exceto que todas as chaves são convertidas em strings. O novo mapa armazena chaves como seu tipo original.

Se você tivesse uma matriz e não um objeto, poderia usar a função .filter da matriz para retornar uma nova matriz sem o item que você deseja remover:

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

Se você possui um navegador mais antigo e o jQuery, o jQuery possui um $.grepmétodo que funciona da mesma forma:

myArray = $.grep(myArray, function(item) {
    return item !== 'Smith';
});
Dzeimsas Zvirblis
fonte
explicação perfeita. Eu usei filtro para alcançar o resultado desejado. Você explicaria como o item de retorno funciona para remover o objeto da matriz. Estou assumindo que ele retorna a matriz, desde que não inclua a string que você incluiu.
Edward
5

Você está usando Objeto, não está tendo uma matriz associativa para começar. Com uma matriz associativa, adicionar e remover itens é assim:

    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
fonte
4

Você pode remover uma entrada do seu mapa atribuindo-a explicitamente a 'indefinida'. Como no seu caso:

myArray ["lastname"] = indefinido;

Amytis
fonte
Isso pode ser útil nos casos em que não se tem certeza se a chave existe no dicionário, mas deseja limpá-la caso exista. Corrija-me se eu estiver errado, Amytis.
Hassan Baig
3

Se, por qualquer motivo, a chave de exclusão não estiver funcionando (como se não estivesse funcionando para mim)

Você pode dividir e filtrar os valores indefinidos

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

Não tente encadeá-los, pois a emenda retorna os elementos removidos;

Leon
fonte
3

Também podemos usá-lo como uma função. Angular gera algum erro se usado como protótipo. Obrigado @HarpyWar. Isso me ajudou a resolver um problema.

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
fonte
2

É muito simples se você tiver dependência de underscore.js no seu projeto -

_.omit(myArray, "lastname")
vatsal
fonte
1

Usando a "delete"palavra-chave, ele excluirá o elemento da matriz em javascript.

Por exemplo,

Considere as seguintes instruções.

var arrayElementToDelete = new Object();

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

delete arrayElementToDelete["status"];

A última linha do código removerá o elemento da matriz cuja chave é "status" da matriz.

Ravindra Miyani
fonte
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);

Sem repetir / iterar, obtemos o mesmo resultado

Lalith kumar
fonte
0

Para "Matrizes":

Se você conhece o índice:

array.splice(index, 1);

Se você conhece o valor:

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

A resposta mais votada para deletefunciona bem no caso de objetos, mas não para as matrizes reais. Se eu usá- deletelo remove elementos de loops, mas mantém o elemento como emptye o comprimento da matriz não muda. Isso pode ser um problema em alguns cenários.

Por exemplo, se eu executar myArray.toString () no myArray após a remoção, deleteele criará uma entrada vazia, ou seja,

Arvind K.
fonte
0

O único método de trabalho para mim:

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

uso:

var new = removeItem( ["apple","banana", "orange"],  "apple");
// ---> ["banana", "orange"]
T.Todua
fonte
Por que não usar filtro? este é um caso de uso perfeito para filtro
Código Maniac