Как удалить свойство из объекта JavaScript? - PullRequest
5553 голосов
/ 16 октября 2008

Скажем, я создаю объект следующим образом:

var myObject = {
    "ircEvent": "PRIVMSG",
    "method": "newURI",
    "regex": "^http://.*"
};

Каков наилучший способ удалить свойство regex для получения нового myObject следующим образом?

var myObject = {
    "ircEvent": "PRIVMSG",
    "method": "newURI"
};

Ответы [ 38 ]

7618 голосов
/ 16 октября 2008

Как это:

delete myObject.regex;
// or,
delete myObject['regex'];
// or,
var prop = "regex";
delete myObject[prop];

Демо-версия

var myObject = {
    "ircEvent": "PRIVMSG",
    "method": "newURI",
    "regex": "^http://.*"
};
delete myObject.regex;

console.log(myObject);

Для всех, кто хочет больше узнать об этом, пользователь Stack Overflow kangax написал невероятно подробное сообщение в блоге о выражении delete в своем блоге, Понимание удаления . Настоятельно рекомендуется.

820 голосов
/ 12 февраля 2014

Оператор delete неожиданно медленно!

Посмотрите на тест .

Удалить - единственный верный способ удалить свойства объекта без остатков, но он работает в ~ 100 раз медленнее , по сравнению с его "альтернативой", настройка object[key] = undefined.

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

Когда следует использовать delete и когда установить значение undefined?

Объект может рассматриваться как набор пар ключ-значение. То, что я называю «значением», является примитивом или ссылкой на другой объект, связанный с этим «ключом».

Используйте delete, , когда вы передаете объект результата в код, над которым у вас нет контроля (или когда вы не уверены в своей команде или в себе).

Он удаляет ключ из хэш-карты .

 var obj = {
     field: 1     
 };
 delete obj.field;

Используйте настройку на undefined, , если вы заботитесь о производительности. Это может дать серьезный импульс вашему коду.

Ключ остается на своем месте в хэш-карте , только значение заменяется на undefined. Поймите, что цикл for..in все еще будет повторяться по этому ключу.

 var obj = {
     field: 1     
 };
 obj.field = undefined;

При использовании этого метода не все способы определения существования свойства будут работать должным образом.

Однако этот код:

object.field === undefined

будет вести себя одинаково для обоих методов.

Тесты

Подводя итог, можно сказать, что различия заключаются в способах определения существования свойства и в цикле for..in.

 console.log('* -> "Takes prototype inheritance into consideration, that means it lookups all over prototype chain too."');

 console.log(obj.field === undefined, 'obj.field === undefined', 'You get "undefined" value when querying for "field" in object-hashmap. *');

 console.log(obj["field"] === undefined, 'obj["field"] === undefined', 'Just another way to query (equivalent). *');

 console.log(typeof obj.field === "undefined", 'typeof obj.field === "undefined"', 'Get the value attached to "field" key, and check it\'s type is "undefined". *');

 console.log("field" in obj, '"field" in obj', 'This statement returns true if "field" key exists in the hashmap. False otherwise. *');

 console.log(obj.hasOwnProperty("field"), 'obj.hasOwnProperty("field")', 'This statement returns true if \'field\' key exists in the hashmap. The ONLY way NOT to lookup for property in the prototype chain!');
 //Object.keys().indexOf() is an overkill that runs much slower :)

 var counter = 0,
     key;
 for (key in obj) {
     counter++;
 }
 console.assert(counter === 0, 'counter === 0', '"field" is not iterated using "for .. in" loop. *');

Остерегайтесь утечек памяти!

Хотя использование obj[prop] = undefined выполняется быстрее, чем delete obj[prop], еще одно важное соображение заключается в том, что obj[prop] = undefined не всегда подходит. delete obj[prop] удаляет prop из obj и стирает его из памяти, тогда как obj[prop] = undefined просто устанавливает значение prop в undefined, что оставляет prop в памяти. Поэтому в обстоятельствах, когда создается и удаляется много ключей, использование obj[prop] = undefined может привести к дорогостоящему согласованию памяти (что приводит к зависанию страницы) и, возможно, к ошибке нехватки памяти. Изучите следующий код.

"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
    nodeRecords[i] = [];
    current = theNodeList[i] = document.createElement("div");
    current.textContent = i;
    document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
    var currentTime = Math.round( performance.now()*1000 )
    for (i = 0; i !== numberOfNodes; i++) {
        if (lastTime !== -1) {
            // the previously collected data is no longer in use
            /*************************************************/
            /****/ nodeRecords[i][lastTime] = undefined; /****/
            /*************************************************/
        }
        nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
    }
    lastTime = currentTime;
    requestAnimationFrame( recordUpdates );
});

В приведенном выше коде простое выполнение nodeRecords[i][lastTime] = undefined; вызовет значительную утечку памяти из-за каждого кадра анимации. Каждый кадр, все 65536 элементов DOM будут занимать еще 65536 отдельных слотов, но для предыдущих 65536 слотов будет установлено только значение undefined, что приведет к их зависанию в памяти. Продолжайте, попробуйте запустить приведенный выше код в консоли и убедитесь сами. После возникновения ошибки нехватки памяти попробуйте запустить ее снова, за исключением следующей версии кода, в которой вместо этого используется оператор delete.

"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
    nodeRecords[i] = [];
    current = theNodeList[i] = document.createElement("div");
    current.textContent = i;
    document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
    var currentTime = Math.round( performance.now()*1000 )
    for (i = 0; i !== numberOfNodes; i++) {
        if (lastTime !== -1) {
            // the previously collected data is no longer in use
            /********************************************/
            /****/ delete nodeRecords[i][lastTime]; /****/
            /********************************************/
        }
        nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
    }
    lastTime = currentTime;
    requestAnimationFrame( recordUpdates );
});

Как видно из приведенного выше фрагмента кода, есть несколько редких подходящих вариантов использования для оператора delete. Тем не менее, не беспокойтесь об этой проблеме слишком много. Это станет проблемой только для объектов с длительным сроком службы, к которым постоянно добавляются новые ключи. В любом другом случае (который есть почти в каждом случае в программировании реального мира) наиболее целесообразно использовать obj[prop] = undefined. Основная цель этого раздела - просто довести это до вашего сведения, чтобы в редких случаях, когда это становилось проблемой в вашем коде, вы могли легче понять проблему и, таким образом, не тратить часы на разбор кода для поиска и понять эту проблему.

Не всегда установлен на undefined

Одним из аспектов Javascript, который важно учитывать, является полиморфизм. Полиморфизм - это когда разные типы переменных / слотов в объекте назначаются разным типам, как показано ниже.

var foo = "str";
foo = 100;          // variable foo is now labeled polymorphic by the browser
var bar = ["Some", "example"];
bar[2] = "text";    // bar is a monomorphic array here because all its entries have the
                    // same type: string primitive
bar[1] = undefined; // bar is now a polymorphic array

Однако есть две основные неустранимые проблемы с полиморфными массивами:

  1. Они медленные, а память неэффективна. При доступе к определенному индексу вместо того, чтобы просто получать глобальный тип для массива, браузер вместо этого должен получать тип на основе индекса, причем каждый индекс хранит дополнительные метаданные своего типа.
  2. Однажды полиморфный, всегда полиморфный. Когда массив становится полиморфным, полиморфизм нельзя отменить в браузерах Webkit. Таким образом, даже если вы восстановите полиморфный массив в неполиморфный, он все равно будет сохранен браузером как полиморфный массив.

Можно сравнить полиморфизм с наркоманией. На первый взгляд, это кажется очень прибыльным: красивый, пушистый код. Затем кодер вводит свой массив в препарат полиморфизма. Моментально, полиморфный массив становится менее эффективным, и он никогда не может стать таким же эффективным, как это было раньше, так как он получает наркотики. Чтобы соотнести такое обстоятельство с реальной жизнью, кто-то, употребляющий кокаин, может даже не иметь возможности управлять простой дверной ручкой, а тем более вычислять цифры ПИ. Аналогично, массив лекарств от полиморфизма не может быть столь же эффективным, как мономорфный массив.

Но, как аналогия поездки с наркотиками связана с операцией delete? Ответ заключает в себе последнюю строку кода во фрагменте выше. Так пусть это будет пересмотрено, на этот раз с изюминкой.

var bar = ["Some", "example"];
bar[2] = "text";    // bar is not a polymorphic array here because all its entries have the
                    // same type: string primitive
bar[1] = "";        // bar is still a monomorphic array
bar[1] = undefined; // bar is now a polymorphic array

Обратите внимание. bar[1] = "" не вызывает полиморфизм, тогда как bar[1] = undefined делает. Поэтому всегда следует по возможности использовать соответствующий тип для своих объектов, чтобы случайно не вызвать полиморфизм. Один такой человек может использовать следующий список в качестве общего справочника, чтобы заставить их работать. Однако, пожалуйста, не используйте явно приведенные ниже идеи. Вместо этого используйте то, что хорошо работает для вашего кода.

  • При использовании массива / переменной, типизированной в логический примитив, используйте либо false, либо undefined в качестве пустого значения. Хотя избегать ненужного полиморфизма - это хорошо, переписывание всего кода с явным запретом, скорее всего, приведет к снижению производительности. Используйте здравый смысл!
  • При использовании массива / переменной, типизированной числовому примитиву, используйте 0 в качестве пустого значения. Обратите внимание, что внутри есть два типа чисел: быстрые целые числа (от 2147483647 до -2147483648 включительно) и двойные числа с плавающей запятой (что угодно, кроме NaN и Infinity). Когда целое число понижается до двойного, оно не может быть преобразовано обратно в целое число.
  • При использовании массива / переменной, типизированной для строкового примитива, используйте "" в качестве пустого значения.
  • Когда вы используете Символ, подождите, почему вы используете Символ?!?! Символы - это плохая игра для представления. Все, что запрограммировано для использования Символов, может быть перепрограммировано так, чтобы не использовать Символы, что приводит к более быстрому коду без Символов. Символы на самом деле просто супер неэффективный мета-сахар.
  • При использовании чего-либо еще используйте null.

Однако, будьте внимательны! Не начинайте внезапно делать это со всем вашим существующим кодом сейчас, так как это может привести к поломке такого существующего кода и / или появлению странных ошибок. Скорее такая эффективная практика должна быть реализована с самого начала, и при преобразовании существующего кода рекомендуется дважды, тройной, четырехкратная проверка всех строк, относящихся к этому, поскольку попытка обновить старый код до этой новой практики может быть рискованно, как это полезно.

223 голосов
/ 16 октября 2008

var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
    
delete myObject.regex;

console.log ( myObject.regex); // logs: undefined

Это работает в Firefox и Internet Explorer, и я думаю, что это работает во всех остальных.

178 голосов
/ 18 сентября 2012

Обновление 2018-07-21: В течение долгого времени мне было стыдно за этот ответ, поэтому я думаю, что пришло время немного его подправить. Просто небольшой комментарий, уточнение и форматирование, чтобы помочь ускорить чтение излишне длинных и запутанных частей этого ответа.


КРАТКАЯ ВЕРСИЯ

Фактический ответ на вопрос

Как уже говорили другие, вы можете использовать delete.

obj // {"foo": "bar"}
delete obj["foo"]
obj // {}
obj["foo"] // undefined

Эквивалент массива

Не delete из массива. Вместо этого используйте Array.prototype.splice.

arr // [1,2,3,4,5]
arr.splice(3,1); // 4
arr // [1,2,3,5]

ДЛИТЕЛЬНАЯ ВЕРСИЯ

JavaScript - это язык ООП, поэтому все является объектом, включая массивы . Таким образом, я считаю необходимым указать конкретную оговорку.

В массивах, в отличие от простых старых объектов, использование delete оставляет мусор в виде null, создавая «дыру» в массиве.

var array = [1, 2, 3, 4];
delete array[2];
/* Expected result --> [1, 2, 4]
 * Actual result   --> [1, 2, null, 4]
 */

Как видите, delete не всегда работает так, как можно было ожидать. Значение перезаписывается, но память не перераспределяется. То есть array[4] не перемещено в array[3]. В отличие от Array.prototype.unshift, который вставляет элемент в начало массива и сдвигает все вверх (array[0] становится array[1] и т. Д.)

Честно говоря, кроме установки null, а не undefined - что на самом деле странно - такое поведение не должно быть удивительным, поскольку delete является унарным оператором, как typeof, который жестко вписывается в язык и не должен заботиться о типе объекта, на котором он используется, тогда как Array является подклассом Object с методами специально предназначен для работы с массивами. Так что для delete нет веской причины готовить специальный случай для повторного смещения массива, поскольку это просто замедлит работу с ненужной работой. Оглядываясь назад, мои ожидания были нереальными.

Конечно, это удивило меня . Потому что я написал это, чтобы оправдать свой крестовый поход против «нулевого мусора»:

Игнорирование опасностей и проблем, присущих null, и пространства, потраченного впустую, это может быть проблематично, если массив должен быть точным.

Что является ужасным оправданием для избавления от null s - null, опасно только при неправильном использовании и не имеет ничего общего с «точностью». Реальная причина, по которой вы не должны delete из массива, состоит в том, что оставление заполненных мусором и грязных структур данных вокруг является небрежным и подверженным ошибкам.

Ниже приведен надуманный сценарий, который становится довольно многословным, поэтому вы можете перейти к разделу Решение , если хотите. Единственная причина, по которой я покидаю этот раздел, заключается в том, что я думаю, что некоторые люди, вероятно, считают это смешным, и я не хочу быть «тем парнем», который публикует «смешной» ответ, а затем удаляет из него все «смешные» ,

... Это глупо, я знаю.

Придуманный и многословный сценарий PDP-11

Например, допустим, вы создаете веб-приложение, которое использует JSON-сериализацию для хранения массива, используемого для «вкладок» в строке (в данном случае localStorage). Скажем также, что код использует числовые индексы элементов массива для «заголовка» их при рисовании на экране. Почему вы делаете это, а не просто сохраняете «заголовок»? Потому что ... причины .

Хорошо, давайте просто скажем, что вы пытаетесь сэкономить память по запросу этого одного пользователя, который запускает мини-компьютер PDP-11 из UNIX 1960-х годов и написал свой собственный JavaScript на основе Elinks совместимый с линейным принтером браузер, потому что X11 исключен .

За исключением все более и более глупого сценария с крайним регистром, использование delete в указанном массиве приведет к null загрязнению массива и, возможно, позже к ошибкам в приложении. И если вы проверите для null, он будет пропускать цифры, в результате чего вкладки будут отображаться как [1] [2] [4] [5] ....

if (array[index] == null)
    continue;
else
    title = (index + 1).toString();
/* 0 -> "1"
 * 1 -> "2"
 * 2 -> (nothing)
 * 3 -> "4"
 */

Да, это определенно не то, что вы хотели.

Теперь, вы могли бы сохранить второй итератор, например j, для приращения только при считывании допустимых значений из массива. Но это точно не решит проблему null, и вам все равно придется порадовать этого пользователя troll PDP-11. Увы, его компьютер просто не имеет достаточно памяти для хранения последнего целого числа (не спрашивайте, как ему удается обрабатывать массив переменной ширины ...) .

Итак, он отправляет вам письмо в гневе:

Hey, your webapp broke my browser! I checked my localStorage database after your stupid code made my browser segfault, and this is what I found:

>"tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... ]"

After clearing my precious data, it segfaulted again, and I did a backtrace, and what do I find? WHAT DO I FIND!? YOU USE TOO MANY VARIABLES!

>var i = index;
>var j = 1;

Grr, I am angry now.
-Troll Davidson

Примерно сейчас ты в своем уме. Этот парень без конца жаловался на ваше приложение, и вы хотите сказать ему, чтобы он заткнулся и взял лучший компьютер.

Решение: Array.prototype.splice

К счастью, массивы do имеют специальный метод удаления индексов и перераспределения памяти: Array.prototype.splice(). Вы могли бы написать что-то вроде этого:

Array.prototype.remove = function(index){
  this.splice(index,1);
}
...
array = [1, 2, 3, 4];
array.remove(2);
// Result -> [1, 2, 4]

И именно так вы порадовали мистера PDP-11. Ура! (я бы все равно отчитал его ...)

Array.prototype.splice против Array.prototype.slice

Мне кажется, важно указать на разницу между этими двумя функциями с одинаковыми именами, поскольку они обе очень полезны.

Array.prototype.splice (начало, n)

.splice() мутирует массив и возвращает удаленные индексы. Массив нарезается, начиная с индекса, элементы start и n нарезаются. Если n не указано, весь массив после start выделяется (n = array.length - start).

let a = [5,4,3,2,1];
let chunk = a.splice(2,2);

// a     [5,4,3,2,1]
// start  0 1 2 - -
// n      - - 1 2 -

chunk; // [3,2]
a;     // [5,4,1]

Array.prototype.slice (начало, конец)

.slice() является неразрушающим и возвращает новый массив, содержащий указанные индексы, от start до end. Если end не указан, поведение аналогично .splice() (end = array.length). Поведение немного сложнее, поскольку по какой-то причине end индексирует от 1 вместо 0. Я не знаю, почему это происходит, но так оно и есть. Также, если end <= start, результатом будет пустой массив.

let a = [5,4,3,2,1];
let chunks = [
    a.slice(2,0),
    a.slice(2,2),
    a.slice(2,3),
    a.slice(2,5) ];

// a             [5,4,3,2,1]
// start          0 1 2 - -
// end, for...    - - - - -
//   chunks[0]  0 - - - - -   
//   chunks[1]    1 2 - - -
//   chunks[2]    1 2 3 - -
//   chunks[3]    1 2 3 4 5

chunks; // [ [], [], [3], [3,2,1] ]
a;      // [5,4,3,2,1]

На самом деле это не то, что происходит, но так проще думать. Согласно MDN, вот что на самом деле происходит:

// a             [5,4,3,2,1]
// start          0 1 2 - - -
// end, for...    - - - - - -
//   chunks[0]    0 - - - - -
//   chunks[1]    0 1 2 - - -
//   chunks[2]    0 1(2)3 - -
//   chunks[3]    0 1(2 3 4)5

Индекс, указанный end, просто исключается из среза. Индексы в скобках указывают на то, что вырезано. В любом случае, поведение не является интуитивно понятным, и оно неизбежно вызовет значительную долю ошибок «один на один», поэтому может оказаться полезным создать функцию-обертку, чтобы более точно имитировать поведение .splice():

function ez_slice(array, start = 0, n = null){
    if(!Array.isArray(array) || !is_number(start))
        return null;

    if(is_number(n))
        return array.slice(start, start + n);

    if(n === null)
        return array.slice(start);

    return null;
}

ez_slice([5,4,3,2,1], 2, 1) // [3]
ez_slice([5,4,3,2,1], 2)    // [3,2,1]

/* Fun fact: isNaN is unreliable.
 * [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(isNaN)
 * [NaN, {}, undefined, "Hi"]
 *
 * What we want is...
 *
 * [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(is_nan)
 * [NaN]
 */
function is_nan(num){
    return typeof num === "number"
        && num !== num;
}

function is_number(num){
    return !is_nan(num)
        && typeof num === "number"
        && isFinite(num);
}

Обратите внимание, что функция-обертка разработана очень строго к типам и возвращает null, если что-то отключено. Это включает в себя строку типа "3". Программист должен быть усердным в своих типах. Это должно поощрять хорошую практику программирования.

Обновление относительно is_array()

Это относится к этому (теперь удаленному) фрагменту:

function is_array(array){
    return array !== null
        && typeof array === "object"
        && typeof array.length !== "undefined"
        && array.__proto__ === Array.prototype;
}

Итак, как выясняется, на самом деле есть встроенный способ определить, является ли массив действительно массивом, и это Array.isArray(), введенное в ECMAScript 5 (декабрь 2009 г.). Я нашел это, когда смотрел, нет ли вопроса о том, как сказать массивы от объектов, чтобы узнать, есть ли лучшее решение, чем у меня, или добавить мое, если его нет. Так что, если вы используете версию JavaScript, более раннюю, чем ECMA 5, есть ваш polyfill. Однако я настоятельно рекомендую не использовать мою функцию is_array(), поскольку продолжать поддерживать старые версии JavaScript означает продолжать поддерживать старые браузеры, которые их реализуют, то есть поощрять использование небезопасного программного обеспечения и подвергать пользователей риску вредоносного ПО. Поэтому, пожалуйста, используйте Array.isArray(). Используйте let и const. Используйте новые функции, которые добавляются в язык. Не использовать префиксы поставщиков. Удалите , что IE polyfill дерьмо с вашего сайта. Удалите и эту хрень XHTML <!CDATA[[... - мы перешли на HTML5 еще в 2014 году. Чем раньше все откажутся от поддержки этих старых / эзотерических браузеров, тем скорее производители браузеров фактически последуют веб-стандарту и примут новую технологию раньше мы сможем перейти к более безопасной сети.

145 голосов
/ 08 ноября 2016

Старый вопрос, современный ответ. Используя деструктуризацию объекта, функцию ECMAScript 6 , это просто:

const { a, ...rest } = { a: 1, b: 2, c: 3 };

Или с образцом вопросов:

const myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
const { regex, ...newObject } = myObject;
console.log(newObject);

Вы можете увидеть это в действии в редакторе пробной игры Babel.


Edit:

Чтобы переназначить одну и ту же переменную, используйте let:

let myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
({ regex, ...myObject } = myObject);
console.log(myObject);
87 голосов
/ 24 мая 2014

Другой альтернативой является использование библиотеки Underscore.js .

Обратите внимание, что _.pick() и _.omit() оба возвращают копию объекта и не изменяют напрямую исходный объект. Присвоение результата исходному объекту должно помочь (не показано).

Ссылка: ссылка _. Pick (объект, * ключи)

Возвращает копию объекта, отфильтрованного, чтобы иметь только значения для ключи из белого списка (или массив допустимых ключей).

var myJSONObject = 
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

_.pick(myJSONObject, "ircEvent", "method");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};

Ссылка: ссылка _. Опустить (объект, * ключи)

Возвращает копию объекта, отфильтрованного, чтобы пропустить черные ключи (или массив ключей).

var myJSONObject = 
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

_.omit(myJSONObject, "regex");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};

Для массивов _.filter() и _.reject() могут использоваться аналогичным образом.

58 голосов
/ 12 сентября 2018

Синтаксис распространения (ES6)

Для тех, кто в этом нуждается ...

Чтобы завершить ответ @Koen в этой теме, на случай, если вы хотите удалить динамическую переменную с использованием синтаксиса распространения, вы можете сделать это так:

const key = 'a';

const { [key]: foo, ...rest } = { a: 1, b: 2, c: 3 };

console.log(rest); // { b: 2, c: 3 }

* foo будет новой переменной со значением a (что равно 1).


ОБНОВЛЕНИЕ :
Существует несколько распространенных способов удаления свойства из объекта.
У каждого есть свои плюсы и минусы ( проверьте это сравнение производительности ):

Оператор удаления
Однако, если вы работаете с большим количеством объектов, это может быть не лучшим выбором, поскольку его производительность не оптимизирована.

delete obj[key];


Переназначение
Более чем в 2 раза быстрее, чем delete, однако свойство не удалено и может быть повторено.

obj[key] = null;
obj[key] = false;
obj[key] = undefined;


Оператор спреда
Этот оператор ES6 позволяет нам возвращать новый объект, исключая любые свойства, не изменяя существующий объект. Недостатком является то, что он имеет худшую производительность из вышеперечисленных и не рекомендуется использовать, когда необходимо удалить много свойств одновременно.

{ [key]: val, ...rest } = obj;
45 голосов
/ 12 февраля 2014

Термин, который вы использовали в заголовке вопроса Remove a property from a JavaScript object, может интерпретироваться по-разному. Один из них - удалить всю память и список ключей объекта, а другой - просто удалить его из вашего объекта. Как уже упоминалось в некоторых других ответах, ключевое слово delete является основной частью. Допустим, у вас есть объект вроде:

myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

Если вы делаете:

console.log(Object.keys(myJSONObject));

результат будет:

["ircEvent", "method", "regex"]

Вы можете удалить этот конкретный ключ из ваших ключей объекта, например:

delete myJSONObject["regex"];

Тогда ключ вашего объекта с помощью Object.keys(myJSONObject) будет:

["ircEvent", "method"]

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

myJSONObject["regex"] = null;
delete myJSONObject["regex"];

Другим важным моментом здесь является осторожность в отношении других ваших ссылок на тот же объект. Например, если вы создаете переменную вроде:

var regex = myJSONObject["regex"];

Или добавьте его в качестве нового указателя на другой объект, например:

var myOtherObject = {};
myOtherObject["regex"] = myJSONObject["regex"];

Тогда даже если вы удалите его из вашего объекта myJSONObject, этот конкретный объект не будет удален из памяти, поскольку переменные regex и myOtherObject["regex"] все еще имеют свои значения. Тогда как мы можем точно удалить объект из памяти?

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

Это означает, что в этом случае вы не сможете удалить этот объект, потому что вы создали переменную regex с помощью оператора var, и если вы сделаете:

delete regex; //False

Результат будет false, что означает, что ваш оператор удаления не был выполнен так, как вы ожидали. Но если вы ранее не создавали эту переменную, и у вас была только myOtherObject["regex"] в качестве вашей последней существующей ссылки, вы могли бы сделать это, просто удалив ее как:

myOtherObject["regex"] = null;
delete myOtherObject["regex"];

Другими словами, объект JavaScript уничтожается, как только в вашем коде не остается ссылки на этот объект.


Обновление: Благодаря @AgentME:

Установка свойства в null перед удалением не завершается что-нибудь (если объект не был запечатан Object.seal и удалить не удалось. Обычно это не так, если вы попробовать).

Для получения дополнительной информации о Object.seal: Object.seal ()

38 голосов
/ 10 января 2016

ECMAScript 2015 (или ES6) поставляется со встроенным отражающим объектом. Удалить свойство объекта можно, вызвав Reflect.deleteProperty () с целевым объектом и ключом свойства в качестве параметров:

Reflect.deleteProperty(myJSONObject, 'regex');

, что эквивалентно:

delete myJSONObject['regex'];

Но если свойство объекта не настраивается, его нельзя удалить ни с помощью функции deleteProperty, ни с помощью оператора delete:

let obj = Object.freeze({ prop: "value" });
let success = Reflect.deleteProperty(obj, "prop");
console.log(success); // false
console.log(obj.prop); // value

Object.freeze () делает все свойства объекта неконфигурируемыми (кроме прочего). Функция deleteProperty (а также оператор удаления ) возвращает false, когда пытается удалить любое из своих свойств. Если свойство настраивается, оно возвращает true, даже если свойство не существует.

Разница между delete и deleteProperty заключается в использовании строгого режима:

"use strict";

let obj = Object.freeze({ prop: "value" });
Reflect.deleteProperty(obj, "prop"); // false
delete obj["prop"];
// TypeError: property "prop" is non-configurable and can't be deleted
37 голосов
/ 21 февраля 2016

Предположим, у вас есть объект, который выглядит следующим образом:

var Hogwarts = {
    staff : [
        'Argus Filch',
        'Filius Flitwick',
        'Gilderoy Lockhart',
        'Minerva McGonagall',
        'Poppy Pomfrey',
        ...
    ],
    students : [
        'Hannah Abbott',
        'Katie Bell',
        'Susan Bones',
        'Terry Boot',
        'Lavender Brown',
        ...
    ]
};

Удаление свойства объекта

Если вы хотите использовать весь массив staff, правильный способ сделать это:

delete Hogwarts.staff;

Кроме того, вы также можете сделать это:

delete Hogwarts['staff'];

Аналогично, удаление всего массива студентов будет выполнено путем вызова delete Hogwarts.students; или delete Hogwarts['students'];.

Удаление индекса массива

Теперь, если вы хотите удалить одного сотрудника или студента, процедура немного отличается, поскольку оба свойства являются самими массивами.

Если вам известен индекс вашего сотрудника, вы можете просто сделать это:

Hogwarts.staff.splice(3, 1);

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

Hogwarts.staff.splice(Hogwarts.staff.indexOf('Minerva McGonnagall') - 1, 1);

Примечание

Хотя технически вы можете использовать delete для массива, его использование приведет к неправильным результатам при вызове, например, Hogwarts.staff.length позже. Другими словами, delete удалит элемент, но не обновит значение свойства length. Использование delete также может испортить вашу индексацию.

Таким образом, при удалении значений из объекта всегда сначала учитывайте, имеете ли вы дело со свойствами объекта или со значениями массива, и выбирайте соответствующую стратегию на основе этого.

Если вы хотите поэкспериментировать с этим, вы можете использовать эту скрипку в качестве отправной точки.

...