Как удалить объекты из ассоциативного массива javascript?

619

Предположим, у меня есть этот код:

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

Теперь, если я хотел удалить «фамилию»? .... есть какой-то эквивалент
myArray["lastname"].remove()?

(Мне нужно убрать элемент, потому что количество элементов важно, и я хочу, чтобы все было чисто.)

djot
источник
27
Совет: не путайте массивы и карты. Некоторые языки, такие как php, имеют один объект для обоих. Хотя вы использовали правильный тип здесь (new Object ()), вы назвали его myArray, это просто вопрос стандартов для языка.
Хуан Мендес
Не забывайте, что JavaScript не имеет типа, и все является объектом. Смотрите ответ Саула ниже.
Stevek
4
@StephanKristyn - если быть точным, у JS есть типы, но динамично и слабо . Например, хотя его переменные действительно не имеют типов, их значения - нет. Это динамическая часть. Слабый означает, что операции между различными типами значений не являются строго определенными и основаны на закулисных преобразованиях; Например "Test" + {};, это совершенно правильный оператор JS.
Сол

Ответы:

1135

Объекты в JavaScript можно рассматривать как ассоциативные массивы, сопоставляющие ключи (свойства) со значениями.

Чтобы удалить свойство из объекта в JavaScript, вы используете deleteоператор:

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

Обратите внимание, что когда deleteприменяется к свойству index объекта an Array, вы создаете малонаселенный массив (т. Е. Массив с отсутствующим индексом).

При работе с экземплярами Array, если вы не хотите создавать малонаселенный массив - а вы обычно этого не делаете - тогда вам следует использовать Array#spliceили Array#pop.

Обратите внимание, что deleteоператор в JavaScript не освобождает память напрямую. Его целью является удаление свойств из объектов. Конечно, если удаляемое свойство содержит единственную оставшуюся ссылку на объект o, то oвпоследствии будет выполняться сбор мусора обычным способом.

Использование deleteоператора может повлиять на способность движков JavaScript оптимизировать код .

Деннис С
источник
18
Это вызовет проблемы при использовании на экземпляре объекта Array для удаления существующего элемента, например delete myArray[0]. См. Stackoverflow.com/a/9973592/426379 и Удаление элементов массива
Сол
4
Какие проблемы будут вызваны?
Gottox
26
@Gottox - lengthсвойство объекта Array остается неизменным.
Сол
12
@Saul: были бы проблемы, если бы myArrayон действительно использовался в качестве массива - но это не так ( myArrayэто неудачное имя), это объект. Так что в этом случае deleteвсе в порядке. Обратите внимание, что даже если бы он был создан как new Array()и использовался как ассоциативный массив, все равно все было бы в порядке. Тем не менее, ваше предупреждение - это то, о чем нужно знать, если вы используете реальные массивы.
Johndodo
2
@johndodo - правда. Вот почему я начал свой первый комментарий с Это вызовет проблемы при использовании на экземпляре объекта Array . Тем не менее я предпочитаю подход, который работает правильно во всех случаях, см. Мой ответ ниже.
Сол
79

Все объекты в JavaScript реализованы в виде хеш-таблиц / ассоциативных массивов. Итак, следующие являются эквивалентными:

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

И, как уже указывалось, вы «удаляете» свойство из объекта через deleteключевое слово, которое вы можете использовать двумя способами:

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

Надеюсь, что дополнительная информация поможет ...

Джейсон Бантинг
источник
10
Следует отметить, что точечная нотация не работает, если свойство не является простым термином. т.е. myObj['some;property']работает, но myObj.some;propertyне будет (по понятным причинам). Также может быть неочевидно, что вы можете использовать переменную в скобочных обозначениях, то естьvar x = 'SomeProperty'; alert(myObj[x])
Кип
2
«Все объекты в JavaScript реализованы как хеш-таблицы / ассоциативные массивы.» - false. V8 предпочитает хранить объект как скрытый класс + плотно упакованные поля. Только если вы делаете с ними странные вещи (такие как удаление полей), он сдается и использует хэш-карту за кулисами.
Джон Дворак
4
@JanDvorak - эй, вы понимаете, когда этот ответ был изначально написан, да? Это описание было и остается достаточным для большинства целей. Тем не менее, я понимаю, что скучно педантично. :)
Джейсон Бантинг
41

Ни в одном из предыдущих ответов не говорится о том факте, что в Javascript нет ассоциативных массивов для начала - arrayтипа нет как такового, видите typeof.

В Javascript есть экземпляры объектов с динамическими свойствами. Когда свойства перепутаны с элементами экземпляра объекта Array, тогда обязательно произойдут плохие вещи:

проблема

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

Решение

Чтобы иметь универсальную функцию удаления, которая не взорвет вас, используйте:

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
Сол
источник
8
У этого решения есть две проблемы: оно скрывает тот факт, что массивы и объекты - это совершенно разные звери в JS (вы это знаете, но, очевидно, OP этого не делает) и использует прототипы. OP был бы лучше, если бы он узнал о массивах и объектах (и назвал бы свои переменные соответственно) - попытка скрыть различия между ними только доставит ему больше проблем. ИМХО конечно.
Johndodo
1
@johndodo - все Arrayобъекты в JS являются объектами, попробуйте typeof new Array();или typeof []проверьте. Arrayэто просто определенный вид объекта, а вовсе не «другой зверь». В JS объекты различаются по имени конструктора и цепочке прототипов, см. Программирование на основе прототипов .
Сол
9
Вы упускаете суть. Я знаю, что массивы тоже являются объектами, но это не значит, что разумно использовать их как таковые. Программист должен решить, хочет ли он использовать что-либо как массив (с push, pop, [], ...) или как объект / «ассоциативный массив». Смешивать и сочетать не очень хороший рецепт, именно из-за проблем, которые ваше решение пытается скрыть. Если вы заранее решите, какой шаблон проектирования использовать (массив или объект), таких проблем не будет.
Johndodo
7
@johndodo - О каких конкретно проблемах ты говоришь? Цель приведенного выше кода состоит в том, чтобы устранить недостатки, которые deleteимеет оператор Array, предоставляя простую полиморфную функцию.
Сол
1
deleteне имеет недостатка. deleteпредназначен для удаления свойств. Вот и все. Применение оператора удаления к индексу массива удаляет этот индекс. Что еще нужно сделать? Вы остаетесь с разреженным массивом, который является особенностью языка. Если вам не нужен разреженный массив, не удаляйте индекс: используйте spliceили pop.
Бен Астон
35

Это только удаляет удаляет объект, но по-прежнему сохраняет длину массива той же.

Для удаления нужно сделать что-то вроде:

array.splice(index, 1);
Bipin
источник
11
Действительно, но в этом случае массив не используется, это просто старый объект, поэтому у него нет метода длины или соединения.
MooGoo
2
@Andreaa Panagiotidis За исключением случаев, когда мы не говорим о массивах, в этом случае это неправильно в 100% случаев 🙂
Дренай
17

Хотя принятый ответ является правильным, в нем отсутствует объяснение, почему он работает.

Прежде всего, ваш код должен отражать тот факт, что это НЕ массив:

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

Обратите внимание, что все объекты (включая Arrays) могут быть использованы таким образом. Однако не ожидайте, что стандартные функции массива JS (pop, push, ...) будут работать с объектами!

Как сказано в принятом ответе, вы можете затем использовать deleteдля удаления записи из объектов:

delete myObject["lastname"]

Вы должны решить, какой маршрут вы хотите выбрать - либо использовать объекты (ассоциативные массивы / словари), либо использовать массивы (карты). Никогда не смешивайте их обоих.

johndodo
источник
6
Очень хороший ответ Я бы посоветовал всем, кто читает это, что массивы в javascript должны быть абстрагированы не как «карты», а как «списки». Это потому, что вы не должны пытаться контролировать индекс элементов при использовании массивов. Если вы попробуете это ... ну, просто не надо: D
rodolfo42
6

Используйте метод, spliceчтобы полностью удалить элемент из массива объектов:

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
источник
1
это более общее решение, может быть добавлено в ваш файл js, и метод будет доступен для всех массивов, а не только для одного массива.
Хуссейн
6

Как уже отмечалось в других ответах, вы используете не массив Javascript, а объект Javascript, который работает почти как ассоциативный массив в других языках, за исключением того, что все ключи преобразуются в строки. Новая карта хранит ключи как их первоначальный тип.

Если у вас есть массив, а не объект, вы можете использовать функцию массива .filter , чтобы вернуть новый массив без элемента, который вы хотите удалить:

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

Если у вас более старый браузер и jQuery, у jQuery есть $.grepметод, который работает аналогично:

myArray = $.grep(myArray, function(item) {
    return item !== 'Smith';
});
Дзеймсас Звирблис
источник
идеальное объяснение. Я использовал фильтр для достижения желаемого результата. Не могли бы вы объяснить, как работает возвращаемый элемент для удаления объекта из массива. Я предполагаю, что он возвращает массив, если он не включает в себя строку, которую вы включили.
Эдвард
5

Вы используете Object, у вас нет ассоциативного массива для начала. С ассоциативным массивом добавление и удаление элементов происходит следующим образом:

    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
    }
Стефан Штайгер
источник
4

Вы можете удалить запись с вашей карты, явно присвоив ей значение «undefined». Как и в вашем случае:

myArray ["lastname"] = не определено;

Амитис
источник
Это может быть полезно в тех случаях, когда никто не уверен, существует ли ключ в словаре, но хочет очистить его в случае, если он существует. Поправь меня, если я ошибаюсь, Амитис.
Хасан Бэйг
3

Если по какой-либо причине ключ удаления не работает (как будто он не работает для меня)

Вы можете склеить его, а затем отфильтровать неопределенные значения

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

Не пытайтесь объединить их в цепочку, поскольку splice возвращает удаленные элементы;

Леон
источник
3

Мы можем использовать это как функцию тоже. Angular выдает некоторую ошибку, если используется в качестве прототипа. Спасибо @HarpyWar. Это помогло мне решить проблему.

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");
Омкар Камале
источник
2

Это очень просто, если у вас есть зависимость underscore.js в вашем проекте -

_.omit(myArray, "lastname")
vatsal
источник
1

Используя "delete"ключевое слово, он удалит элемент массива из массива в javascript.

Например,

Рассмотрим следующие утверждения.

var arrayElementToDelete = new Object();

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

delete arrayElementToDelete["status"];

Последняя строка кода удалит элемент массива, ключ которого «status», из массива.

Равиндра Мияни
источник
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);

Без зацикливания / повторения мы получаем тот же результат

Лалит Кумар
источник
0

Для "Массивов":

Если вы знаете индекс:

array.splice(index, 1);

Если вы знаете значение:

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

Ответ с наибольшим количеством голосов deleteхорошо подходит для объектов, но не для реальных массивов. Если я использую deleteэто, удаляет элементы из циклов, но сохраняет элемент как emptyи длина массива не изменится. Это может быть проблемой в некоторых сценариях.

Например, если я выполняю myArray.toString () на myArray после удаления через deleteнего, создается пустая запись, т.е.

Арвинд К.
источник
0

Единственный метод работы для меня:

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

Применение:

var new = removeItem( ["apple","banana", "orange"],  "apple");
// ---> ["banana", "orange"]
T.Todua
источник
Почему бы не использовать фильтр вместо этого? это идеальный вариант использования фильтра
Code Maniac