Как да премахнете имот от обект на javascript?

Да речем, че създавам обект като този:

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

Какъв е най-добрият начин да премахнете собствеността на regex , за да получите нов myObject като този:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI" }; 
5276
16 окт. комплект johnstok 16 окт. 2008-10-16 13:57 '08 в 13:57 2008-10-16 13:57
@ 37 отговора
  • 1
  • 2

Ето го:

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

демонстрация

kangax написа невероятно подробен блог по повод delete изявление в своя блог, Understanding Deletion .  Силно се препоръчва. 

7292
16 окт. Отговор nickf 16 ок 2008-10-16 13:58 '08 в 1:58 pm 2008-10-16 13:58

операторът delete неочаквано забавя се!

Вижте бенчмарка .

Изтриването е единственият сигурен начин за премахване на свойствата на обект без никакви остатъци, но той работи ~ 100 пъти по-бавно в сравнение с неговия "алтернативен" object[key] = undefined .

Тази алтернатива не е правилният отговор на този въпрос! Но ако го използвате внимателно, можете значително да ускорите някои алгоритми. Ако използвате delete в цикли и имате проблеми с производителността, прочетете подробното обяснение.

Кога трябва 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 веригата за .. в.

border=0
  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\ 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 ще заема още 65,536 отделни слота, но предишните слотове 65,536 ще бъдат настроени само на 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 браузърите. Така, дори ако възстановите полиморфния масив като неполиморфен, той все пак ще бъде съхранен от браузъра като полиморфен масив.

Можете да сравните полиморфизма с наркотичната зависимост. На пръв поглед изглежда невероятно печеливш: красив, доста пухкав код. След това енкодерът въвежда своя масив в лекарство за полиморфизъм. Моментално, полиморфната матрица става по-малко ефективна и никога не може да стане толкова ефективна, както преди, тъй като е анестезирана. За да се обвърже такова обстоятелство с реалния живот, някой от кокаина може дори да не може да управлява обикновена дръжка на вратата, много по-малко да може да изчисли PI номера. По същия начин, масив върху препарат на полиморфизъм не може да бъде толкова ефективен, колкото мономорфния масив.

Но как се анализира лекарството за операция по 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 . Затова винаги е необходимо, когато е възможно, да се използва подходящия тип за вашите обекти, за да не се получи случайно полиморфизъм. Един такъв човек може да използва следния списък като обща връзка, за да ги получи. Моля, не използвайте идеите по-долу. Вместо това използвайте всичко, което работи добре за вашия код.

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

Но внимавайте! Не започвайте да правите това с всички съществуващи кодове, тъй като има вероятност да нарушите такъв съществуващ код и / или да покажете странни грешки. По-скоро такава ефективна практика трябва да се прилага от самото начало и при преобразуването на съществуващия код се препоръчва да се удвоят, тройни, четворни проверки на всички линии, свързани с това, като опит за актуализиране на стария код към тази нова практика, може да бъде толкова рискован, колкото е полезен. ,

770
12 февр. Отговор Дан 12 фев 2014-02-12 20:48 '14 в 20:48 2014-02-12 20:48

215
16 окт. отговор, даден на redsquare 16 октомври 2008-10-16 14:03 '08 в 14:03 2008-10-16 14:03

Актуализация 2018-07-21: За дълго време се чувствах неудобно за този отговор, така че мисля, че го докоснах малко. Само малко коментар, изясняване и форматиране, за да се ускори четенето на ненужни дълги и объркващи части на този отговор.


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

Действителният отговор на въпроса

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

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

Голям еквивалент

Не delete от масива. Array.prototype.splice това използвайте 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];  

Както виждате, delete не винаги работи както трябва. Стойността е презаписана, но паметта не се преразпределя. С други думи, array[4] не се премества в array[3] . За разлика от Array.prototype.unshift , който вмъква елемент в началото на масив и премества всичко нагоре ( array[0] става array[1] и т.н.),

Честно казано, в допълнение към настройката null и не undefined - това, което е напълно странно - това поведение не бива да е изненадващо, защото delete е unary оператор, като typeof , който е твърдо усукан в езика и не трябва да се грижи за вида на използвания обект, Array е подклас на Object с методи, специално предназначени за работа с масиви. Следователно няма причина delete да има специален случай, подготвен за преместване на масив, тъй като това просто ще забави работата с ненужна работа. Поглеждайки назад, очакванията ми бяха нереалистични.

Разбира се, че ме изненада. Защото го написах, за да оправдая кръстоносен поход срещу "нулеви боклуци":

Игнорирайки опасностите и проблемите, присъщи на null и пропиляното пространство, това може да бъде проблематично, ако масивът трябва да бъде точен.

Което е ужасно извинение за да се отървем от null - null е опасно само ако се използва неправилно и няма нищо общо с "точност". Истинската причина, поради която не трябва да delete от масив, е, че оставяте напълнените с боклук и мръсни структури с данни наоколо са объркани и податливи на грешки.

По-долу е измислен скрипт, който е доста дълъг, така че можете да отидете в секцията “Решение”, ако желаете. Единствената причина да напусна този раздел е, че някои хора вероятно смятат, че е смешно, а аз не искам да бъда „човекът“, който изпраща „забавен“ отговор и след това го изтрива. всички "смешни",

... Това е глупаво, знам.

Изобретателният и дългосрочен сценарий PDP-11

Например, да предположим, че създавате уеб приложение, което използва JSON сериализация, за да съхранява масива, използван за разделите в низ (в този случай localStorage ). Нека също така да кажат, че кодът използва цифровите индекси на елементите на масива, за да ги "именува", когато рисува на екрана. Защо правите това и не само запазвате "титлата"? Защото ... причини.

Позволете ми да кажа, че се опитвате да спестите памет по искане на този един потребител, който управлява миникомпютъра PDP-11 от 1960 г., изпълнявайки UNIX и написал свой собствен JavaScript-съвместим интерфейс с поддръжка на браузъра на JavaScript, защото X11 не е не може да се реши.

Все по-глупав скрипт на маргиналния скрипт, използващ delete в посочения масив, ще доведе до null замърсяването на масива и вероятно ще доведе до грешки в приложението по-късно. И ако проверите null , той автоматично ще прескочи номерата, в резултат на което показаните табове ще изглеждат така [1] [2] [4] [5]...

 if (array[index] == null) continue; else title = (index + 1).toString();  

Да, това определено не е това, което искате.

Сега можете да запишете втория итератор, например 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

За щастие масивите имат специален метод за премахване на индекси и преразпределяне на паметта: 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 ( 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 . Ако .splice() остане неопределен, поведението ще бъде същото като .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() поведението на .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]  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, там ваш полипол. Тем не менее, я настоятельно рекомендую не использовать is_array() , так как продолжение поддержки старых версий JavaScript означает продолжение поддержки старых браузеров, которые их реализуют, что означает поощрение использования небезопасного программного обеспечения и помещение пользователей под угрозу для вредоносного ПО. Поэтому, пожалуйста, используйте Array.isArray() . Используйте let и const . Используйте новые функции, которые добавляются в язык. Не используйте префиксы поставщиков. Удалите это полисплощадку IE с вашего сайта. Удалите этот XHTML <!CDATA[[... crap, тоже - мы переместились в HTML5 еще в 2014 году.). Чем раньше все откажутся от поддержки этих старых/эзотерических браузеров, тем скорее поставщики браузеров будут действительно следовать веб-стандарту и охватывают новые технологии, и чем скорее мы сможем перейти к более безопасной сети.

164
ответ дан Braden Best 18 сент. '12 в 3:56 2012-09-18 03:56

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

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