Як видалити об'єкти з асоціативного масиву javascript?


619

Припустимо, у мене є цей код:

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

Тепер, якщо я хотів видалити "прізвище"? .... Чи є якийсь еквівалент
myArray["lastname"].remove()?

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


27
Порада: не плутайте масиви та карти. Деякі мови, як-от php, мають один об'єкт для обох. Хоча ви тут використовували правильний тип (новий 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застосуванні до властивості індексу Array, ви створите малонаселений масив (тобто масив із відсутнім індексом).

Якщо ви працюєте з екземплярами Array, якщо ви не хочете створювати малонаселений масив - а зазвичай цього не робите, - слід використовувати Array#spliceабо Array#pop.

Зауважте, що deleteоператор у JavaScript не вільно звільняє пам'ять. Його мета - видалення властивостей з об’єктів. Звичайно, якщо видалений ресурс містить єдине посилання на об'єкт o, то oзгодом сміття збирається звичайним чином.

Використання deleteоператора може вплинути на можливість двигунів JavaScript оптимізувати код .


18
Це спричинить проблеми при використанні в екземплярі об'єкта Array для видалення наявного елемента, наприклад delete myArray[0]. Дивіться stackoverflow.com/a/9973592/426379 та Видалення елементів масиву
Saul

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])
Kip

2
"Усі об'єкти в JavaScript реалізовані як хештелі / асоціативні масиви." - помилково. V8 вважає за краще зберігати об’єкт як прихований клас + щільно упаковані поля. Тільки якщо ви робите для них дивні речі (наприклад, видалення полів), він відмовляється і використовує хеш-карту за кадром.
Джон Дворак

4
@JanDvorak - ага, ти визнаєш, коли ця відповідь була написана спочатку, так? Цей опис був і все ще є достатнім для більшості цілей. Це сказало, що я розумію, як нудно педантично. :)
Джейсон Бантінг

41

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

Javascript - це об'єкти з динамічними властивостями. Якщо властивості плутати з елементами екземпляра об'єкта Array, тоді Bad Things ™ обов'язково відбудеться:

Проблема

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 (ви це знаєте, але, очевидно, що ОП це не так), і він використовує прототипи. ОП було б краще, якби він дізнався про масиви та об’єкти (і назвав би його змінні відповідно) - спроба приховати відмінності між двома лише доставить йому більше проблем. ІМХО, звичайно.
johndodo

1
@johndodo - всі Arrays в 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);

11
Дійсно, але в цьому випадку масив не використовується, а лише звичайний старий об'єкт, таким чином він не має методу довжини чи сплайсингу.
MooGoo

2
@Andreaa Panagiotidis За винятком випадків, коли ми не говоримо про масиви, і в цьому випадку це неправильно 100% часу 🙂
Дренай

17

Хоча прийнята відповідь правильна, у неї відсутнє пояснення, чому це працює.

Перш за все, ваш код повинен відображати той факт, що це НЕ масив:

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

Зауважте, що всі об'єкти (включаючи їх Array) можна використовувати таким чином. Однак не очікуйте, що стандартні функції масиву JS (pop, push, ...) працюватимуть на об'єктах!

Як сказано в прийнятій відповіді, ви можете використовувати deleteдля видалення записів з об'єктів:

delete myObject["lastname"]

Ви повинні вирішити, яким маршрутом ви хочете скористатися - або використовувати об'єкти (асоціативні масиви / словники), або використовувати масиви (карти). Ніколи їх не змішуйте.


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");

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

Ви можете видалити запис зі своєї карти, чітко призначивши її "невизначеною". Як у вашому випадку:

myArray ["прізвище"] = невизначено;


Це може бути корисно у випадках, коли не впевнені, чи існує ключ у словнику, але хочуть його переосмислити на випадок. Виправте мене, якщо я помиляюся Амітіс.
Хассан Байг

3

Якщо з будь-якої причини ключ видалення не працює (як би він не працював для мене)

Ви можете їх сплайсувати, а потім відфільтрувати невизначені значення

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

Не намагайтеся зв'язати їх з ланцюгом, оскільки сплайс повертає видалені елементи;


3

Ми можемо використовувати його і як функцію. Кутовий кидає деяку помилку, якщо використовується як прототип. Дякую @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");


1

Використовуючи "delete"ключове слово, він видалить елемент масиву з масиву в javascript.

Наприклад,

Розглянемо наступні твердження.

var arrayElementToDelete = new Object();

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

delete arrayElementToDelete["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"]

Чому б замість цього не використовувати фільтр? це ідеальний випадок використання фільтра
Code Maniac
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.