Скажем, я создаю объект следующим образом:
let myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
Каков наилучший способ удалить свойство regex
для получения нового myObject
следующим образом?
let myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI"
};
29 ответов
Нравится:
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);
Для тех, кто хочет больше узнать об этом, пользователь Staa Overflow kangax написал невероятно подробное сообщение в блоге о {{ X0}} в своем блоге, Общие сведения об удалении . Настоятельно рекомендуется.
Вы можете использовать ES6 деструктурирование с оператором отдыха.
Свойства можно удалить с помощью деструктурирования в сочетании с оператором покоя . В вашем примере регулярное выражение удалено (игнорируется), а остальные свойства возвращаются как остальные.
const noRegex = ({ regex, ...rest }) => rest;
const myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
console.log(noRegex(myObjext)) //=> { "ircEvent": "PRIVMSG","method": "newURI" }
Или вы можете динамически исключать такие свойства, как
const myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
const removeProperty = prop => ({ [prop]: _, ...rest }) => rest
const removeRegex = removeProperty('regex') //=> { "ircEvent": "PRIVMSG","method":"newURI" }
const removeMethod = removeProperty('method') //=> { "ircEvent": "PRIVMSG", "regex":"^http://.*" }
Попробуйте следующий метод. Назначьте значение свойства Object
для undefined
. Тогда stringify
объект и parse
.
var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
myObject.regex = undefined;
myObject = JSON.parse(JSON.stringify(myObject));
console.log(myObject);
Другой альтернативой является использование библиотеки Underscore.js.
Обратите внимание, что _.pick()
и _.omit()
возвращают копию объекта и напрямую не изменяют исходный объект. Присвоение результата исходному объекту должно помочь (не показано).
Ссылка: ссылка _. Pick (объект, * ключи)
Возвращает копию объекта, отфильтрованного, чтобы иметь только значения для ключей из белого списка (или массива допустимых ключей).
var myJSONObject =
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
_.pick(myJSONObject, "ircEvent", "method");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};
Ссылка: ссылка _. Omit (объект, * ключи)
Возвращает копию объекта, отфильтрованного для исключения ключей из черного списка (или массива ключей).
var myJSONObject =
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
_.omit(myJSONObject, "regex");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};
Для массивов _.filter()
и _.reject()
могут использоваться аналогичным образом.
Попробуйте создать новый объект без свойства "regex"
, поскольку на исходный объект всегда могут ссылаться другие части вашей программы. Таким образом, вы должны избегать манипулирования им.
const myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
const { regex, ...newMyObject } = myObject;
console.log(newMyObject);
Используя ramda # disococ, вы получите новый объект без атрибута regex
:
const newObject = R.dissoc('regex', myObject);
// newObject !== myObject
Вы также можете использовать другие функции для достижения того же эффекта - опустить, выбрать, ...
Этот пост очень старый, и я нахожу его очень полезным, поэтому я решил поделиться функцией unset, которую я написал, на тот случай, если кто-то еще увидит этот пост и подумает, почему это не так просто, как в функции unset PHP.
Причина написания этой новой функции unset
состоит в том, чтобы сохранить индекс всех других переменных в этом hash_map. Посмотрите на следующий пример и посмотрите, как индекс «test2» не изменился после удаления значения из hash_map.
function unset(unsetKey, unsetArr, resort){
var tempArr = unsetArr;
var unsetArr = {};
delete tempArr[unsetKey];
if(resort){
j = -1;
}
for(i in tempArr){
if(typeof(tempArr[i]) !== 'undefined'){
if(resort){
j++;
}else{
j = i;
}
unsetArr[j] = tempArr[i];
}
}
return unsetArr;
}
var unsetArr = ['test','deletedString','test2'];
console.log(unset('1',unsetArr,true)); // output Object {0: "test", 1: "test2"}
console.log(unset('1',unsetArr,false)); // output Object {0: "test", 2: "test2"}
Я лично использую Underscore.js или Lodash для манипулирования объектами и массивами:
myObject = _.omit(myObject, 'regex');
оператор удаления - лучший способ сделать это так.
Живой пример, чтобы показать:
var foo = {bar: 'bar'};
delete foo.bar;
console.log('bar' in foo); // Logs false, because bar was deleted from foo.
Синтаксис распространения (ES6)
Для тех, кто нуждается в этом ...
Чтобы завершить ответ @Koen в этой теме, на случай, если вы хотите удалить динамическую переменную с использованием синтаксиса распространения, вы можете сделать это так:
const key = 'a';
const { [key]: foo, ...rest } = { a: 1, b: 2, c: 3 };
console.log(foo); // 1
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;
Предположим, у вас есть объект, который выглядит следующим образом:
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
также может испортить вашу индексацию.
Таким образом, при удалении значений из объекта всегда сначала учитывайте, имеете ли вы дело со свойствами объекта или со значениями массива, и выбирайте соответствующую стратегию на основе этого.
Если вы хотите поэкспериментировать с этим, вы можете использовать эту скрипку в качестве отправной точки.
var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
delete myObject.regex;
console.log ( myObject.regex); // logs: undefined
Это работает в Firefox и Internet Explorer, и я думаю, что это работает во всех остальных.
Используя ES6:
(Разрушение + Оператор распространения)
const myObject = {
regex: "^http://.*",
b: 2,
c: 3
};
const { regex, ...noRegex } = myObject;
console.log(noRegex); // => { b: 2, c: 3 }
Здесь есть много хороших ответов, но я просто хочу сказать, что при использовании delete для удаления свойства в JavaScript часто целесообразно сначала проверить, существует ли это свойство, чтобы избежать ошибок.
Например
var obj = {"property":"value", "property2":"value"};
if (obj && obj.hasOwnProperty("property2")) {
delete obj.property2;
} else {
//error handling
}
Из-за динамической природы JavaScript часто бывают случаи, когда вы просто не знаете, существует свойство или нет. Проверка существования obj перед тем, как && также гарантирует, что вы не выдадите ошибку из-за вызова функции hasOwnProperty () для неопределенного объекта.
Извините, если это не добавилось к вашему конкретному варианту использования, но я считаю, что это хороший дизайн для адаптации при управлении объектами и их свойствами.
Вы можете просто удалить любое свойство объекта, используя ключевое слово delete
.
Например:
var obj = {key1:"val1",key2:"val2",key3:"val3"}
Чтобы удалить любое свойство, скажем, key1
, используйте ключевое слово delete
, например:
delete obj.key1
Или вы также можете использовать массивную запись:
delete obj[key1]
Ссылка: MDN.
Использование метода delete - лучший способ сделать это, согласно описанию MDN, оператор delete удаляет свойство из объекта. Так что вы можете просто написать:
delete myObject.regex;
// OR
delete myObject['regex'];
Оператор удаления удаляет данное свойство из объекта. При успешном удалении он вернет true, иначе будет возвращено false. Тем не менее, важно учитывать следующие сценарии:
Если свойство, которое вы пытаетесь удалить, не существует, удалите не будет иметь никакого эффекта и вернет true
Если в прототипе объекта есть свойство с таким же именем цепочки, то после удаления объект будет использовать свойство из цепочка прототипов (другими словами, удаление только влияет на собственный свойства). р >
Любое свойство, объявленное с помощью var, не может быть удалено из глобальной области видимости. или из области видимости функции.
Таким образом, delete не может удалять какие-либо функции в глобальной области (будь то часть из определения функции или функция (выражение).
Функции, которые являются частью объекта (кроме
глобальная область) можно удалить с помощью delete.Любое свойство, объявленное с помощью let или const, не может быть удалено из области, в которой они были определены. Ненастраиваемые свойства не могут быть удалены. Это включает в себя свойства встроенных объектов, таких как Math, Array, Object и свойства, которые создаются как неконфигурируемые с помощью методов, таких как Object.defineProperty ().
Следующий фрагмент дает еще один простой пример:
var Employee = {
age: 28,
name: 'Alireza',
designation: 'developer'
}
console.log(delete Employee.name); // returns true
console.log(delete Employee.age); // returns true
// When trying to delete a property that does
// not exist, true is returned
console.log(delete Employee.salary); // returns true
Для получения дополнительной информации и увидеть больше примеров, перейдите по ссылке ниже:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
Object.assign () и Object.keys () и Array.map ()
const obj = {
"Filters":[
{
"FilterType":"between",
"Field":"BasicInformationRow.A0",
"MaxValue":"2017-10-01",
"MinValue":"2017-09-01",
"Value":"Filters value"
}
]
};
let new_obj1 = Object.assign({}, obj.Filters[0]);
let new_obj2 = Object.assign({}, obj.Filters[0]);
/*
// old version
let shaped_obj1 = Object.keys(new_obj1).map(
(key, index) => {
switch (key) {
case "MaxValue":
delete new_obj1["MaxValue"];
break;
case "MinValue":
delete new_obj1["MinValue"];
break;
}
return new_obj1;
}
)[0];
let shaped_obj2 = Object.keys(new_obj2).map(
(key, index) => {
if(key === "Value"){
delete new_obj2["Value"];
}
return new_obj2;
}
)[0];
*/
// new version!
let shaped_obj1 = Object.keys(new_obj1).forEach(
(key, index) => {
switch (key) {
case "MaxValue":
delete new_obj1["MaxValue"];
break;
case "MinValue":
delete new_obj1["MinValue"];
break;
default:
break;
}
}
);
let shaped_obj2 = Object.keys(new_obj2).forEach(
(key, index) => {
if(key === "Value"){
delete new_obj2["Value"];
}
}
);
Другое решение, использующее {{X0} } сильный > .
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
myObject = Object.keys(myObject).reduce(function(obj, key) {
if (key != "regex") { //key you want to remove
obj[key] = myObject[key];
}
return obj;
}, {});
console.log(myObject);
Однако он будет мутировать исходного объекта. Если вы хотите создать новый объект без указанного ключа, просто назначьте функцию Reduce новой переменной, например:
( ES6 )
const myObject = {
ircEvent: 'PRIVMSG',
method: 'newURI',
regex: '^http://.*',
};
const myNewObject = Object.keys(myObject).reduce((obj, key) => {
key !== 'regex' ? obj[key] = myObject[key] : null;
return obj;
}, {});
console.log(myNewObject);
Попробуй это
delete myObject['key'];
Здравствуйте, вы можете попробовать это просто сортировка
var obj = [];
obj.key1 = {name: "John", room: 1234};
obj.key2 = {name: "Jim", room: 1234};
delete(obj.key1);
Утверждение Дэна о том, что «удаление» очень медленное, и опубликованный им тест были поставлены под сомнение. Итак, я провел тест самостоятельно в Chrome 59. Кажется, что «delete» примерно в 30 раз медленнее:
var iterationsTotal = 10000000; // 10 million
var o;
var t1 = Date.now(),t2;
for (let i=0; i<iterationsTotal; i++) {
o = {a:1,b:2,c:3,d:4,e:5};
delete o.a; delete o.b; delete o.c; delete o.d; delete o.e;
}
console.log ((t2=Date.now())-t1); // 6135
for (let i=0; i<iterationsTotal; i++) {
o = {a:1,b:2,c:3,d:4,e:5};
o.a = o.b = o.c = o.d = o.e = undefined;
}
console.log (Date.now()-t2); // 205
Обратите внимание, что я намеренно выполнил более одной операции удаления в одном цикле цикла, чтобы минимизировать эффект, вызванный другими операциями.
Оператор 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
, что оставляет {{X9} } еще в памяти. Следовательно, в ситуациях, когда создается и удаляется много ключей, использование 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
Однако с полиморфными массивами есть две основные нерешаемые проблемы:
- Они медленные и память неэффективна. При доступе к определенному индексу вместо того, чтобы просто получать глобальный тип для массива, браузер вместо этого должен получать тип на основе индекса, причем каждый индекс хранит дополнительные метаданные своего типа.
- Однажды полиморфная, всегда полиморфная. Когда массив становится полиморфным, полиморфизм нельзя отменить в браузерах 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
.
Однако будьте внимательны! Не начинайте внезапно делать это со всем вашим ранее существующим кодом, так как это может привести к поломке такого существующего кода и / или появлению странных ошибок. Скорее такая эффективная практика должна быть реализована с самого начала, и при преобразовании существующего кода рекомендуется дважды, тройной, четырехкратная проверка всех строк, относящихся к этому, поскольку попытка обновить старый код до этой новой практики может быть рискованно, как это полезно.
Если вы хотите удалить свойство, глубоко вложенное в объект, то вы можете использовать следующую рекурсивную функцию с путем к свойству в качестве второго аргумента:
var deepObjectRemove = function(obj, path_to_key){
if(path_to_key.length === 1){
delete obj[path_to_key[0]];
return true;
}else{
if(obj[path_to_key[0]])
return deepObjectRemove(obj[path_to_key[0]], path_to_key.slice(1));
else
return false;
}
};
Примере:
var a = {
level1:{
level2:{
level3: {
level4: "yolo"
}
}
}
};
deepObjectRemove(a, ["level1", "level2", "level3"]);
console.log(a);
//Prints {level1: {level2: {}}}
const myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
const { regex, ...other } = myObject;
console.log(myObject)
console.log(regex)
console.log(other)
Старый вопрос, современный ответ. Используя деструктуризацию объекта, 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);
Чтобы клонировать объект без свойства:
Например:
let object = { a: 1, b: 2, c: 3 };
И нам нужно удалить «а».
1. С явным ключом реквизита:
const { a, ...rest } = object;
object = rest;
2.С переменной переменной ключ:
const propKey = 'a';
const { [propKey]: propValue, ...rest } = object;
object = rest;
Функция стрелки 3.Cool 😎:
const removePropery = (propKey, { [propKey]: propValue, ...rest }) => rest;
object = removePropery('a', object);
4. Для нескольких свойств
const removeProperties = (object, ...keys) => Object.entries(object).reduce((prev, [key, value]) => ({...prev, ...(!keys.includes(key) && { [key]: value }) }), {})
< Сильный > < EM> Использование
object = removeProperties(object, 'a', 'b') // result => { c: 3 }
< Сильный > < EM> Или
const propsToRemove = ['a', 'b']
object = removeProperties(object, ...propsToRemove) // result => { c: 3 }
ECMAScript 2015 (или ES6) поставлялся со встроенным объектом Reflect. Удалить свойство объекта можно, вызвав 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
Термин, который вы использовали в заголовке вашего вопроса 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"]
Но дело в том, что если вы заботитесь о памяти и хотите, чтобы весь объект был удален из памяти, рекомендуется установить его в null перед удалением ключа:
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 уничтожается, как только в вашем коде не остается ссылки на этот объект.
< Сильный > Update : Благодаря @AgentME:
Установка свойства в null перед его удалением ничего не делает (если только объект не был запечатан Object.seal и удаление завершилось неудачно. Обычно это не так, если вы не попытались это сделать).
Чтобы получить дополнительную информацию о Object.seal
: Object.seal ( )
Обновление 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
, и вам все равно придется порадовать этоготролляпользователя 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 vs 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 с вашего сайта. Удалите и эту хрень XHTML <!CDATA[[...
- мы перешли на HTML5 еще в 2014 году. Чем раньше все откажутся от поддержки этих старых / эзотерических браузеров, тем скорее производители браузеров будут фактически следовать веб-стандарту и внедрять новую технологию, и чем раньше мы сможем перейти к более безопасной сети.
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript/JS) и его различных диалектах/реализациях (кроме ActionScript). Имейте в виду, что JavaScript — это НЕ то же самое, что Java! Включите все ярлыки, относящиеся к вашему вопросу; например, [node.js], [jQuery], [JSON], [ReactJS], [angular], [ember.js], [vue.js], [typescript], [svelte] и т. д.