¿Cómo elimino objetos de una matriz asociativa de JavaScript?

619

Supongamos que tengo este código:

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

Ahora, si quisiera eliminar "apellido" ... ¿hay algún equivalente de
myArray["lastname"].remove()?

(Necesito que el elemento desaparezca porque la cantidad de elementos es importante y quiero mantener las cosas limpias).

djot
fuente
27
Un consejo: no confunda las matrices y los mapas. Algunos lenguajes, como php, tienen un solo objeto para ambos. Aunque usó el tipo correcto aquí (nuevo Object ()) lo llamó myArray, es solo una cuestión de estándares para un idioma.
Juan Mendes
No olvides que JavaScript no tiene tipo y que todo es un objeto. Ver la respuesta de Saúl a continuación.
stevek
44
@StephanKristyn: para ser precisos, JS tiene tipos pero de forma dinámica y débil . Por ejemplo, si bien sus variables son sin tipo, sus valores no lo son. Esa es la parte dinámica . Débil denota que las operaciones entre diferentes tipos de valores no están estrictamente definidas y dependen de conversiones detrás de escena; Por ejemplo, "Test" + {};es una declaración JS perfectamente válida.
Saul

Respuestas:

1135

Los objetos en JavaScript pueden considerarse como matrices asociativas, claves de mapeo (propiedades) a valores.

Para eliminar una propiedad de un objeto en JavaScript, utilice el deleteoperador:

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

Tenga en cuenta que cuando deletese aplica a una propiedad de índice de un Array, creará una matriz escasamente poblada (es decir, una matriz con un índice faltante).

Cuando trabaje con instancias de Array, si no desea crear una matriz escasamente poblada, y generalmente no lo hace, entonces debe usar Array#spliceo Array#pop.

Tenga en cuenta que el deleteoperador en JavaScript no libera memoria directamente. Su propósito es eliminar propiedades de los objetos. Por supuesto, si una propiedad que se elimina contiene la única referencia restante a un objeto o, ose recolectará basura de la manera normal.

El uso del deleteoperador puede afectar la capacidad de los motores de JavaScript para optimizar el código .

Dennis C
fuente
18
Esto causará problemas si se usa en una instancia de objeto Array para eliminar un elemento existente, por ejemplo delete myArray[0]. Ver stackoverflow.com/a/9973592/426379 y Eliminar elementos de la matriz
Saul
44
¿Qué problemas se causarán?
Gottox
26
@Gottox: la lengthpropiedad de un objeto Array permanece sin cambios.
Saul
12
@Saul: habría problemas si myArrayrealmente se usara como una matriz, pero no lo es ( myArrayes un nombre desafortunado), es un objeto. Entonces en este caso deleteestá bien. Tenga en cuenta que incluso si fue creado como new Array()y utilizado como matriz asociativa, todavía estaría bien. Sin embargo, su advertencia todavía es algo a tener en cuenta si uno está usando matrices reales.
johndodo
2
@johndodo - Cierto. Es por eso que comencé mi comentario inicial con Esto causará problemas si se usa en una instancia de objeto Array . Sin embargo, prefiero un enfoque que funcione correctamente en todos los casos, vea mi respuesta a continuación.
Saul
79

Todos los objetos en JavaScript se implementan como tablas hash / matrices asociativas. Entonces, los siguientes son equivalentes:

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

Y, como ya se indicó, "elimina" una propiedad de un objeto mediante la deletepalabra clave, que puede usar de dos maneras:

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

Espero que la información adicional ayude ...

Jason Bunting
fuente
10
Cabe señalar que la notación de puntos no funciona si la propiedad no es un término simple. es decir myObj['some;property'], funciona, pero myObj.some;propertyno lo haría (por razones obvias). Además, puede que no sea obvio que puede usar una variable en la notación de corchetes, es decirvar x = 'SomeProperty'; alert(myObj[x])
Kip
2
"Todos los objetos en JavaScript se implementan como tablas hash / matrices asociativas". Falso. V8 prefiere almacenar un objeto como una clase oculta + campos densamente empaquetados. Solo si les haces cosas raras (como eliminar campos), se da por vencido y usa un mapa hash detrás de escena.
John Dvorak
44
@ JanDvorak - oye, reconoces cuando esta respuesta se escribió originalmente, ¿sí? Esa descripción fue y sigue siendo suficiente para la mayoría de los propósitos. Dicho esto, entiendo ser tediosamente pedante. :)
Jason Bunting
41

Ninguna de las respuestas anteriores aborda el hecho de que Javascript no tiene matrices asociativas para empezar, no hay ningún arraytipo como tal, vea typeof.

Lo que tiene Javascript son instancias de objetos con propiedades dinámicas. Cuando las propiedades se confunden con elementos de una instancia de objeto Array, es probable que sucedan cosas malas:

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

Solución

Para tener una función de eliminación universal que no explote, 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
Saulo
fuente
8
Esta solución tiene dos problemas: oculta el hecho de que las matrices y los objetos son bestias completamente diferentes en JS (lo sabes, pero aparentemente OP no) y usa prototipos. OP estaría mejor si se enterara de las matrices y los objetos (y nombraría sus variables en consecuencia): tratar de ocultar las diferencias entre los dos solo lo meterá en más problemas. En mi humilde opinión, por supuesto.
johndodo
1
@johndodo: todos los Arrays en JS son objetos, pruebe typeof new Array();o typeof []verifique. Arrayes simplemente un cierto tipo de objeto y no es en absoluto una "bestia diferente". En JS, los objetos se distinguen por su nombre de constructor y cadena de prototipos, consulte Programación basada en prototipos .
Saul
99
Estas perdiendo el punto. Sé que las matrices también son objetos, pero eso no significa que sea prudente usarlas como tales. El programador debe decidir si quiere usar algo como matriz (con push, pop, [], ...) o como objeto / "matriz asociativa". Mezclar y combinar no es una buena receta, precisamente por los problemas que su solución está tratando de ocultar. Si decide de antemano qué patrón de diseño usar (matriz u objeto) no habrá tales problemas.
johndodo
77
@johndodo - ¿De qué problemas estás hablando específicamente? El propósito del código anterior es abordar el deleteoperador de deficiencia con respecto a Arrayproporcionar una función polimórfica simple.
Saul
1
deleteno tiene deficiencia deleteestá diseñado para eliminar propiedades. Eso es. La aplicación del operador de eliminación a un índice de una matriz elimina ese índice. ¿Qué más necesitas hacer? Te queda una matriz dispersa, que es una característica del lenguaje. Si no desea una matriz dispersa, no elimine el índice: use spliceo pop.
Ben Aston
35

Eso solo elimina elimina el objeto pero aún mantiene la longitud de la matriz igual.

Para eliminar debes hacer algo como:

array.splice(index, 1);
Bipin
fuente
11
De hecho, pero en este caso no se está utilizando una matriz, solo un objeto antiguo simple, por lo que no tiene un método de longitud o empalme.
MooGoo
2
@Andreaa Panagiotidis Excepto cuando no estamos hablando de matrices, en cuyo caso está mal el 100% del tiempo 🙂
Drenai
17

Si bien la respuesta aceptada es correcta, le falta la explicación de por qué funciona.

En primer lugar, su código debe reflejar el hecho de que esto NO es una matriz:

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

Tenga en cuenta que todos los objetos (incluidos los Arrays) se pueden usar de esta manera. Sin embargo, ¡no espere que las funciones estándar de matriz JS (pop, push, ...) funcionen en objetos!

Como se dijo en la respuesta aceptada, puede usar deletepara eliminar las entradas de los objetos:

delete myObject["lastname"]

Debe decidir qué ruta desea tomar: utilice objetos (matrices / diccionarios asociativos) o utilice matrices (mapas). Nunca mezcles los dos.

johndodo
fuente
66
Muy buena respuesta. Solo aconsejaría a cualquiera que lea esto que las matrices en javascript no se resumen como 'mapas', sino como 'listas'. Esto se debe a que no debe intentar tener control sobre el índice de los elementos cuando use matrices. Si intentas eso ... bueno, simplemente no lo hagas: D
rodolfo42
6

Use el método splicepara eliminar completamente el elemento de una 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
fuente
1
Esta es una solución más genérica, se puede agregar a su archivo js y el método estará disponible para todas las matrices, no solo para una.
Hussain
6

Como han señalado otras respuestas, lo que está utilizando no es una matriz de Javascript, sino un objeto de Javascript, que funciona casi como una matriz asociativa en otros idiomas, excepto que todas las teclas se convierten en cadenas. El nuevo Mapa almacena las claves como su tipo original.

Si tenía una matriz y no un objeto, podría usar la función .filter de la matriz para devolver una nueva matriz sin el elemento que desea eliminar:

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

Si tiene un navegador y jQuery anteriores, jQuery tiene un $.grepmétodo que funciona de manera similar:

myArray = $.grep(myArray, function(item) {
    return item !== 'Smith';
});
Dzeimsas Zvirblis
fuente
explicación perfecta Usé filtro para lograr el resultado deseado. ¿Podría explicar cómo funciona el elemento devuelto para eliminar el objeto de la matriz? Supongo que devuelve la matriz siempre que no incluya la cadena que incluiste.
Edward
5

Estás utilizando Object, no tienes una matriz asociativa para empezar. Con una matriz asociativa, agregar y eliminar elementos es así:

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

Puede eliminar una entrada de su mapa asignándola explícitamente a 'indefinido'. Como en tu caso:

myArray ["apellido"] = indefinido;

Amytis
fuente
Esto podría ser útil en casos en los que uno no está seguro de si la clave existe en el diccionario, pero quiere desinfectarla en caso de que exista. Corrígeme si me equivoco Amytis.
Hassan Baig
3

Si por alguna razón la tecla Eliminar no funciona (como si no funcionara para mí)

Puede empalmarlo y luego filtrar los valores indefinidos

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

No intente encadenarlos ya que el empalme devuelve los elementos eliminados;

León
fuente
3

También podemos usarlo como una función. Angular arroja algún error si se usa como prototipo. Gracias @HarpyWar. Me ayudó a resolver un 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
fuente
2

Es muy sencillo si tiene dependencia de subrayado.js en su proyecto:

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

Al usar la "delete"palabra clave, eliminará el elemento de matriz de la matriz en javascript.

Por ejemplo,

Considere las siguientes declaraciones.

var arrayElementToDelete = new Object();

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

delete arrayElementToDelete["status"];

La última línea del código eliminará el elemento de matriz cuya clave es "estado" de la matriz.

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

Sin bucles / iteraciones obtenemos el mismo resultado

Lalith Kumar
fuente
0

Para "matrices":

Si conoces el índice:

array.splice(index, 1);

Si conoce el valor:

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

La respuesta más votada para deletefunciona bien en el caso de los objetos, pero no para las matrices reales. Si lo uso delete, elimina elementos de los bucles pero mantiene el elemento como emptyy la longitud de la matriz no cambiará. Esto puede ser un problema en algunos escenarios.

Por ejemplo, si hago myArray.toString () en myArray después de eliminarlo delete, crea una entrada vacía, es decir,

Arvind K.
fuente
0

El único método de trabajo para mí:

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
fuente
¿Por qué no usar filtro en su lugar? este es un caso de uso perfecto para el filtro
Code Maniac