Kako ukloniti nekretninu iz objekta javascript?

Recimo da stvorim objekt poput ovog:

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

Koji je najbolji način za uklanjanje regex svojstva, kako biste završili s novim myObject kao što je ovaj:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI" }; 
5276
16 окт. set johnstok 16 list . 2008-10-16 13:57 '08 u 13:57 2008-10-16 13:57
@ 37 odgovora
  • 1
  • 2

Evo ga:

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

demo

kangax napisao je nevjerojatno detaljan blog o članku delete na svom blogu, Understanding Deletion .  Vrlo preporučljivo. 

7292
16 окт. odgovor je dan 16 okt. 2008-10-16 13:58 '08 u 13:58 2008-10-16 13:58

operater delete neočekivano usporava!

Pogledajte mjerilo .

Brisanje je jedini siguran način za uklanjanje svojstava objekta bez ostataka, ali radi ~ 100 puta sporije u usporedbi s njegovim "alternativnim" object[key] = undefined postavke object[key] = undefined .

Ova alternativa nije pravi odgovor na ovo pitanje! Ali, ako ga koristite s pažnjom, možete znatno ubrzati neke algoritme. Ako koristite delete u petljama i imate probleme s performansama, pročitajte detaljno objašnjenje.

Kada treba delete i kada je navedena vrijednost undefined ?

Objekt se može smatrati skupom parova ključ-vrijednost. Ono što ja zovem "vrijednost" je primitiv ili referenca na drugi objekt povezan s ovim "ključem".

Koristite delete kada proslijedite objekt rezultata kodu u kojem nemate kontrolu (ili kada niste sigurni u svoj tim ili sebe).

Uklanja ključ s hash kartice .

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

Ako niste sigurni u izvedbu, upotrijebite undefined opciju . To može ozbiljno utjecati na vaš kod.

Ključ ostaje na svom mjestu u hashmapu , samo se vrijednost zamjenjuje undefined . Shvatite da će ciklus for..in i dalje prolaziti kroz ovaj ključ.

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

Koristeći ovu metodu, neće sve metode za određivanje svojstva postojanja funkcionirati kako se očekuje.

Međutim, ovaj kôd:

object.field === undefined

će se ponašati jednako za obje metode.

testovi

Sumirajući, postoje razlike u načinima utvrđivanja postojanja svojstva i za for..in petlji 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. *'); 

Čuvajte se curenja memorije!

Iako je obj[prop] = undefined brži od delete obj[prop] , još jedno važno razmatranje je da obj[prop] = undefined nije uvijek relevantno. delete obj[prop] uklanja prop iz obj i briše ga iz memorije, dok obj[prop] = undefined jednostavno postavlja prop vrijednost na undefined što ostavlja prop u memoriji. Stoga, u situacijama gdje postoji mnogo ključeva koji su stvoreni i izbrisani, upotrebom obj[prop] = undefined može doći do skupih memorijskih dosljednosti (uzrokujući da se stranica zamrzne) i potencijalno greške iz memorije. Pregledajte sljedeći kod.

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

U gornjem kodu, samo nodeRecords[i][lastTime] = undefined; rezultirat će masovnim curenjem memorije zbog svakog okvira animacije. Svaki okvir, svi elementi 65536 DOM-a zauzimaju još 65.536 pojedinačnih mjesta, ali prethodni utori 65.536 bit će postavljeni samo na nedefinirano, što ih ostavlja u memoriji. Nastavite, pokušajte pokrenuti gornji kod u konzoli i uvjerite se sami. Nakon prisilne pogreške u memoriji, pokušajte je ponovno pokrenuti, osim sljedeće verzije koda, koja umjesto toga koristi operatora 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 ); }); 

Kao što se može vidjeti iz gornjeg isječka koda, postoje neke rijetke prikladne upotrebe za operatora delete . Međutim, ne brinite previše o ovom problemu. To će postati problem samo s predmetima dugog života koji im stalno dodaju nove ključeve. U svakom drugom slučaju (to je gotovo svaki slučaj u stvarnom programiranju), najbolje je koristiti obj[prop] = undefined . Glavna svrha ovog odjeljka je da jednostavno skrenete vašu pozornost na činjenicu da u rijetkim slučajevima to postaje problem u vašem kodu, onda možete lakše razumjeti problem i stoga ne gubite vrijeme analizirajući svoj kôd kako biste pronašli i razumjeli ovaj problem.

Nije uvijek postavljeno na undefined

Jedan aspekt Javascripta koji je važno uzeti u obzir je polimorfizam. Polimorfizam je dodjeljivanje identičnih varijabli / mjesta u objektima različitih tipova, kao što je prikazano u nastavku.

 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 

Međutim, postoje dva glavna problema koji se ne mogu eliminirati kada se koriste polimorfni nizovi:

  1. Oni su spori i nedjelotvorni. Prilikom pristupa određenom indeksu, umjesto jednostavnog dobivanja globalnog tipa za polje, preglednik bi umjesto toga trebao primiti vrstu na temelju indeksa, u kojem svaki indeks pohranjuje dodatne metapodatke tog tipa.
  2. Nakon polimorfnog, uvijek polimorfnog. Kada je niz polimorfan, polimorfizam se ne može poništiti u Webkit preglednicima. Stoga, čak i ako obnovite polimorfni niz kao nepolimorfan, preglednik će ga i dalje pohranjivati ​​kao polimorfni niz.

Možete usporediti polimorfizam ovisnosti o drogama. Na prvi pogled, čini se nevjerojatno profitabilnim: lijep, prilično pahuljast kod. Enkoder zatim ulazi u svoj niz u lijek polimorfizma. Odmah polimorfna matrica postaje manje učinkovita i nikada ne može postati tako učinkovita kao prije, budući da je anestezirana. Kako bi se ta okolnost povezala sa stvarnim životom, netko iz kokaina možda čak neće moći upravljati jednostavnom kvakom, a još manje moći izračunati PI brojeve. Slično tome, niz na preparatu polimorfizma ne može biti tako učinkovit kao monomorfni niz.

Ali, kako se analogija lijeka odnosi na operaciju delete ? Odgovor sadrži posljednji redak koda u gornjem isječku. Neka bude revidirana, ovaj put s preokretom.

 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 

Obratite pozornost. bar[1] = "" ne uzrokuje polimorfizam, dok bar[1] = undefined ne. Stoga je uvijek potrebno, kada je to moguće, koristiti odgovarajući tip za vaše predmete kako ne biste slučajno izazvali polimorfizam. Jedna takva osoba može koristiti sljedeći popis kao opću vezu kako bi ih dobila. Međutim, nemojte koristiti niže navedene ideje. Umjesto toga, upotrijebite bilo što dobro za svoj kôd.

  • Kada koristite polje / varijablu unesenu u Booleovu primitivu, koristite vrijednost false ili undefined kao praznu vrijednost. Iako je izbjegavanje nepotrebnog polimorfizma dobro, prepisivanje cijelog koda kako biste ga izričito onemogućili vjerojatno će rezultirati lošom izvedbom. Koristite razumnu prosudbu!
  • Kada koristite niz / varijablu unesenu u numeričku primitivnu vrijednost, koristite 0 kao praznu vrijednost. Imajte na umu da postoje unutar dvije vrste brojeva: brzi cijeli brojevi (od 2147483647 do -2147483648 uključivo) i spore dvostruke točke s pomičnim zarezom (bilo što drugo osim NaN i Infinity ). Kada cijeli broj padne na dvostruki, ne može se klasificirati kao cijeli broj.
  • Kada koristite niz / varijablu unesenu u primitivni niz, koristite "" kao praznu vrijednost.
  • Kada koristite simbol, pričekajte, zašto koristite simbol?!?! Loši juju znakovi za izvedbu. Svi znakovi programirani za upotrebu mogu se reprogramirati tako da ne koriste znakove, što rezultira bržim kodom bez koda. Simboli su zapravo samo neučinkoviti meta-šećer.
  • Kada koristite bilo što drugo, koristite null .

Međutim, budite oprezni! Nemojte to činiti sa svim postojećim kodom, jer je vjerojatno da će razbiti takav postojeći kôd i / ili predstaviti čudne pogreške. Umjesto toga, takva bi se praksa trebala provoditi od samog početka, a kada se pretvori postojeći kod preporuča se dvostruka, trostruka, četverostruka provjera svih linija povezanih s tim, kao pokušaj ažuriranja starog koda na ovu novu praksu, može biti rizično kao što je korisno. ,

770
12 февр. Odgovor Dan 12. veljače 2014-02-12 20:48 '14 u 20:48 2014-02-12 20:48

215
16 окт. odgovor je dao redsquare 16. listopada. 2008-10-16 14:03 '08 u 14:03 2008-10-16 14:03

Ažuriranje 2018-07-21: Dugo sam se osjećao neugodno zbog ovog odgovora, pa mislim da sam ga malo dotaknuo. Samo mali komentar, pojašnjenje i oblikovanje kako bi se ubrzalo čitanje nepotrebnih dugih i zbunjujućih dijelova ovog odgovora.


KRATKA VERZIJA

Stvarni odgovor na pitanje

Kao što su drugi rekli, možete koristiti delete .

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

Masivni ekvivalent

Nemojte delete iz niza. Array.prototype.splice upotrijebite Array.prototype.splice .

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

DUGA VERZIJA

JavaScript je OOP jezik, tako da je sve objekt, uključujući nizove. Stoga smatram potrebnim istaknuti posebno upozorenje.

U nizovima, za razliku od jednostavnih starih objekata, korištenje delete ostavlja smeće u obliku null , stvarajući "rupu" u nizu.

 var array = [1, 2, 3, 4]; delete array[2];  

Kao što možete vidjeti, delete ne funkcionira uvijek kako je očekivano. Vrijednost se prepisuje, ali se memorija ne distribuira. Drugim riječima, array[4] se ne pomiče u array[3] . Za razliku od Array.prototype.unshift , koji umeće element na početku niza i pomiče sve gore ( array[0] postaje array[1] , itd.),

Iskreno, osim postavljanja null i ne undefined što je to sasvim čudno - ovo ponašanje ne bi trebalo biti iznenađujuće, jer je delete unarni operator, kao što je typeof , koji je kruto upleten u jezik i ne bi trebao brinuti o vrsti korištenog objekta, Array je podklasa Object s metodama posebno dizajniranim za rad s nizovima. Stoga, nema razloga za delete posebnog slučaja pripremljenog za ponovno premještanje niza, jer će to jednostavno usporiti rad s nepotrebnim radom. Gledajući unatrag, moja očekivanja su bila nerealna.

Naravno da me to iznenadilo. Zato što sam ga napisao kako bih opravdao svoj križarski rat protiv "nula smeća":

Ignorirajući opasnosti i probleme koji su svojstveni null i izgubljenom prostoru, to može biti problematično ako polje mora biti točno.

Koji je strašan izgovor za oslobađanje od null s-- null je opasno samo ako se koristi na pogrešan način i nema nikakve veze s "točnost". Pravi razlog zbog kojeg ne biste trebali delete iz niza je to što je ostavljanje smeća i prljavih struktura podataka uokolo neurednim i podložnim pogreškama.

Ispod je skripta koja je prilično duga, pa možete otići u odjeljak "Rješenje" ako želite. Jedini razlog zbog kojeg odlazim iz ovog dijela je da mislim da je nekima vjerojatno smiješno, i ne želim biti "tip" koji šalje "smiješni" odgovor, a zatim ga briše. sve "smiješno",

Ovo je glupo, znam.

Izrađeni i dugoročni scenarij PDP-11

Na primjer, pretpostavimo da izradite web-aplikaciju koja koristi JSON serijalizaciju za pohranu niza koji se koristi za kartice u nizu (u ovom slučaju localStorage ). Neka i oni kažu da kod koristi numeričke indekse elemenata niza za njihovo "imenovanje" prilikom crtanja na zaslonu. Zašto to radite i ne samo zadržavate "titulu"? Zato ... razlozi.

Pa, dopustite mi da kažem da pokušavate uštedjeti memoriju na zahtjev ovog korisnika koji upravlja PDP-11 minikompjuterom od 1960. godine, pokreće UNIX i piše svoje sučelje kompatibilno s JavaScriptom s podrškom za JavaScript preglednik, jer X11 nije ne dolazi u obzir.

Sve glupija skripta marginalne skripte koja koristi delete u navedenom nizu će delete zagađenje polja i vjerojatno će kasnije dovesti do grešaka u primjeni. A ako provjeravate null , automatski će preskočiti brojeve, tako da će prikazane kartice izgledati kao [1] [2] [4] [5]...

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

Da, ovo definitivno nije ono što si želio.

Sada možete spremiti drugi iterator, na primjer j , da se poveća samo kada se čitaju stvarne vrijednosti iz niza. Ali to definitivno ne rješava null problem, i još uvijek vam se sviđa ovaj Troll PDP-11 korisnik. Nažalost, njegovo računalo jednostavno nema dovoljno memorije za pohranjivanje ovog zadnjeg broja (ne pitajte kako uspijeva upravljati nizom promjenjive širine ...) .

Zato vam šalje pismo u ljutnji:

 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 

Sada ste na svome kraju. Ovaj se čovjek stalno žalio na vašu prijavu, a vi mu želite reći da zašuti i ode na najbolje računalo.

Rješenje: Array.prototype.splice

Srećom, nizovi imaju posebnu metodu za uklanjanje indeksa i preraspodjelu memorije: Array.prototype.splice() . Možete napisati nešto poput ovoga:

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

I baš tako, zadovoljni ste s gospodinom PDP-11. Hura! (Ipak bih mu ipak rekao ...)

Array.prototype.splice vs Array.prototype.slice

Smatram da je važno uočiti razliku između ove dvije slično imenovane funkcije, jer su obje vrlo korisne.

Array.prototype.splice (početak, n)

.splice() mutira niz i vraća udaljene indekse. Niz se reže počevši od indeksa, start i n elementi su izrezani. Ako n nije specificiran, cijeli niz nakon 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 (početak, kraj)

.slice() je nedestruktivna i vraća novi niz s navedenim indeksima od start do end . Ako je end nepoznat, ponašanje će biti isto kao i .splice() ( end = array.length ). Ponašanje je pomalo komplicirano, jer iz nekog razloga end indeksi počinju od 1 umjesto 0. Ne znam zašto se to događa, ali jest. Osim toga, ako je end <= start , rezultat je prazan niz.

 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] 

U stvari, to nije ono što se događa, ali je lakše razmišljati o tome. Prema MDN-u, to se zapravo događa:

 // 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 

Indeks specificiran prema end jednostavno je isključen iz dijela. Indeksi u zagradama ukazuju na to što se narezuje. U svakom slučaju, ponašanje nije intuitivno i posljedica je činjenice da uzrokuje pravedan udio grešaka "jedan za drugim", tako da vam može biti korisno učiniti funkciju omotača više od .splice() ponašanja .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); } 

Imajte na umu da je funkcija omotača vrlo jaka i vraća null ako je nešto onemogućeno. To uključuje niz tipova "3" . Programeru ostaje da bude marljiv u svojim tipovima. To bi trebalo doprinijeti dobroj praksi programiranja.

Ažuriraj u vezi is_array()

To se odnosi na ovaj (sada izbrisani) fragment:

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

Dakle, kako se ispostavilo, zapravo postoji ugrađeni način za određivanje je li polje stvarno polje, a to je Array.isArray() , uveden u ECMAScript 5 (prosinac 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 };