Kaip pašalinti turinį iš „JavaScript“ objekto?

Tarkime, aš sukuriu tokį objektą:

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

Koks yra geriausias būdas pašalinti „ regex nuosavybę, kad galėtumėte baigti naują „ myObject tokį:

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

Čia jis yra:

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

Demo

kangax parašė neįtikėtinai išsamią dienoraščio įrašą apie delete pareiškimą savo dienoraštyje „ Supratimas ištrynimas“ .  Labai rekomenduojama. 

7292
16 окт. atsakymas duotas nickf 16 okt. 2008-10-16 13:58 '08, 13:58 pm 2008-10-16 13:58

operatoriaus delete netikėtai sulėtėja!

Pažvelkite į etaloną .

Ištrinti yra vienintelis būdas pašalinti objekto savybes be jokių liekanų, tačiau jis veikia ~ 100 kartų lėčiau, palyginti su jo „alternatyviu“ nustatymo object[key] = undefined .

Ši alternatyva nėra teisingas atsakymas į šį klausimą! Tačiau, jei naudojate jį atsargiai, galite žymiai pagreitinti kai kuriuos algoritmus. Jei naudojate delete kilpose ir turite problemų dėl veikimo, perskaitykite išsamų paaiškinimą.

Kada turėtų būti delete ir kada yra nurodyta undefined vertė?

Objektas gali būti laikomas raktų vertės porų rinkiniu. Ką aš vadinu „verte“ yra primityvus arba nuoroda į kitą objektą, susijusį su šiuo „raktu“.

Naudodamiesi rezultatu, naudokite delete kodą, kuriame jūs neturite jokios kontrolės (arba kai nesate įsitikinę savo komanda ar sau).

Jis pašalina raktą iš maišos kortelės .

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

Jei nesate tikri dėl našumo, naudokite undefined parinktį . Tai gali rimtai paveikti jūsų kodą.

Raktas išlieka vietoje vietoje , tik reikšmė pakeičiama undefined . Supraskite, kad ciklui „ for..in vis dar eisite per šį klavišą.

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

Naudojant šį metodą, ne visi egzistavimo savybės nustatymo metodai veiks kaip tikėtasi.

Tačiau šis kodas:

object.field === undefined

abu metodai veiks panašiai.

bandymai

Apibendrinant galima for..in , kad egzistuoja skirtumai tarp nuosavybės egzistavimo nustatymo būdų ir už.

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. *'); 

Saugokitės atminties nutekėjimo!

Nors obj[prop] = undefined greitesnis nei delete obj[prop] , dar vienas svarbus aspektas yra tai, kad obj[prop] = undefined gali ne visada būti aktualus. delete obj[prop] pašalina iš obj ir ištrina jį iš atminties, o obj[prop] = undefined paprasčiausiai nustato obj[prop] = undefined prop reikšmę undefined kuri palieka atmintį. Todėl tais atvejais, kai yra daug sukurtų ir ištrintų raktų, naudojant obj[prop] = undefined gali sukelti brangų atminties nuoseklumą (dėl kurio puslapis užšaldomas) ir galbūt iš atminties. Išnagrinėkite šį 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 ); }); 

Pirmiau pateiktame kode tiesiog nodeRecords[i][lastTime] = undefined; dėl kiekvienos animacijos rėmelio atsiras didžiulis atminties nutekėjimas. Kiekvienas rėmelis, visi 65536 DOM elementai užims dar 65.536 atskiras lizdus, ​​tačiau ankstesnės 65536 lizdai bus nustatyti tik neapibrėžtiems, todėl palieka juos kabinti atmintyje. Pereikite, pabandykite paleisti aukščiau pateiktą kodą konsolėje ir pažiūrėkite sau. Po priverstinės atminties klaidos bandykite jį paleisti dar kartą, išskyrus kitą kodo versiją, kuri vietoj to naudoja delete operatorių.

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

Kaip matyti iš pirmiau pateikto kodo fragmento, delete operatoriui yra keli reti tinkami naudojimo būdai. Tačiau nesijaudinkite dėl šios problemos per daug. Tai taps problema tik ilgą gyvenimą turintiems objektams, kurie jiems nuolat prideda naujų raktų. Bet kokiu kitu atveju (tai beveik kiekvienas atvejis realiame programavime), patartina naudoti obj[prop] = undefined . Pagrindinis šio skirsnio tikslas yra tiesiog atkreipti jūsų dėmesį į tai, kad retais atvejais jis tampa problema jūsų kode, tada galite lengviau suprasti problemą ir todėl nenaudokite laiko analizuodami savo kodą, kad surastumėte ir suprastumėte šią problemą.

Ne visada nustatyta kaip undefined

Vienas iš svarbių Javascript aspektų yra polimorfizmas. Polimorfizmas yra identiškų kintamųjų / laiko tarpsnių priskyrimas įvairių tipų objektams, kaip parodyta žemiau.

 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 

Tačiau yra dvi pagrindinės problemos, kurių negalima pašalinti naudojant polimorfines masyvus:

  1. Jos yra lėtos ir neveiksmingos. Kai naudojate konkretų indeksą, vietoj to, kad paprasčiausiai gautumėte masyvo visuotinį tipą, naršyklė turėtų gauti tipą pagal indeksą, kuriame kiekvienas indeksas saugo papildomus jo tipo metaduomenis.
  2. Po polimorfinio, visada polimorfinis. Kai masyvas gaminamas polimorfiniu, polimorfizmas negali būti atšauktas „Webkit“ naršyklėse. Taigi, net jei atkursite polimorfinę masyvą kaip ne polimorfinę, ji vis tiek bus saugoma naršyklėje kaip polimorfinė masyvas.

Galite palyginti narkomanijos polimorfizmą. Iš pirmo žvilgsnio atrodo neįtikėtinai pelninga: gražus, gana purus kodas. Tada koduotojas įeina į masyvą į polimorfizmo vaistą. Nedelsiant, polimorfinė matrica tampa mažiau veiksminga ir ji niekada negali tapti tokia veiksminga kaip anksčiau, nes ji yra anestezuota. Siekiant suderinti šią aplinkybę su realiu gyvenimu, kažkas iš kokaino netgi negalės valdyti paprastos durų rankenos, daug mažiau galėtų apskaičiuoti PI numerius. Panašiai polimorfizmo paruošimo masyvas negali būti toks pat veiksmingas kaip monomorfinis masyvas.

Tačiau, kaip narkotikų analogija nurodo delete operaciją? Atsakyme yra paskutinė pirmiau minėto fragmento kodo eilutė. Taigi leiskite jį peržiūrėti, šį kartą su pasukimu.

 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 

Atkreipkite dėmesį. bar[1] = "" nesukelia polimorfizmo, o bar[1] = undefined . Todėl, kai įmanoma, visada reikia naudoti tinkamą objektų tipą, kad netyčia nebūtų polimorfizmo. Vienas toks asmuo gali naudoti šį sąrašą kaip bendrą nuorodą, kad juos gautų. Tačiau nenaudokite toliau pateiktų idėjų. Vietoj to, naudokite viską, kas gerai veikia jūsų kodui.

  • Naudojant masyvą / kintamąjį, įvestą Būlio primityvoje, naudokite vertę false arba undefined kaip tuščią vertę. Vengiant nereikalingo polimorfizmo yra geras, perrašant visą kodą, kad būtų aiškiai išjungta, tikėtina, kad rezultatas bus prastas. Naudokite patikimą sprendimą!
  • Naudojant masyvą / kintamąjį, įvestą skaitine primityve, kaip tuščią vertę naudokite 0 . Atkreipkite dėmesį, kad viduje yra dviejų tipų numeriai: greiti sveikieji skaičiai (nuo 2147483647 iki -2147483648 imtinai) ir lėtai dvigubi slankiojo taško taškai (bet kas ne NaN ir Infinity ). Kai sveikasis skaičius patenka į dvigubą, jis negali būti klasifikuojamas kaip sveikasis skaičius.
  • Naudojant eilutę / kintamąjį, įvestą eilutės primityvoje, naudokite "" kaip tuščią vertę.
  • Naudodami „Symbol“, palaukite, kodėl naudojate simbolį?!?! Blogi juju simboliai, skirti atlikti. Visi simboliai, užprogramuoti naudoti, gali būti perprogramuoti taip, kad nenaudotų simbolių, todėl kodas be kodo yra greitesnis. Simboliai iš tikrųjų yra tik neveiksmingi meta-cukrus.
  • Naudodamiesi bet kuriuo kitu naudokite null .

Tačiau būkite atsargūs! Nepradėkite to daryti su visais esamais kodais, nes tai gali sulaužyti tokį esamą kodą ir (arba) pateikti keistų klaidų. Atvirkščiai, tokia veiksminga praktika turėtų būti įgyvendinama nuo pat pradžių, o konvertuojant esamą kodą rekomenduojama dvigubai, trigubai, keturis kartus patikrinti visas su tuo susijusias linijas, nes bandymas atnaujinti senąjį kodą į šią naują praktiką gali būti toks rizikingas, kaip ir naudinga. .

770
12 февр. Atsakyti Dan 12 vas 2014-02-12 20:48 '14 ne 20:48 2014-02-12 20:48

215
16 окт. atsakymas pateikiamas redsquare 16 oct. 2008-10-16 14:03 '08 at 2:03 pm 2008-10-16 14:03

Atnaujinimas 2018-07-21: Ilgą laiką aš jaučiausi bėdamas dėl šio atsakymo, todėl manau, kad šiek tiek palietiau . Tik šiek tiek komentarų, paaiškinimų ir formatavimo, norint paspartinti nereikalingų ilgų ir painių šio atsakymo dalių skaitymą.


TRUMPAS VERSIJA

Faktinis atsakymas į klausimą

Kaip kiti sakė, galite naudoti delete .

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

Didelis ekvivalentas

Negalima delete iš masyvo. Šio naudojimo Array.prototype.splice .

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

LONG VERSION

„JavaScript“ yra OOP kalba, todėl viskas yra objektas, įskaitant masyvus. Todėl manau, kad būtina nurodyti konkretų įspėjimą.

Masyvuose, skirtingai nuo paprastų senų objektų, delete palieka šiukšles null pavidalu, sukuriant „skylę“ masyve.

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

Kaip matote, delete ne visada veikia taip, kaip tikėtasi. Vertė perrašoma, tačiau atmintis nėra perskirstoma. Kitaip tariant, array[4] neperkelia array[3] . Skirtingai nuo Array.prototype.unshift , kuris įterpia elementą masyvo pradžioje ir perkelia viską į viršų ( array[0] tampa array[1] ir tt),

Sąžiningai, be null ir undefined nustatymo, kuris yra visiškai keistas, šis elgesys neturėtų būti stebina, nes delete yra vieningas operatorius, pvz., typeof , kuris yra griežtai susuktas į kalbą ir neturėtų rūpintis naudojamo objekto tipu, Array yra Object poklasis, kurio metodai yra specialiai sukurti darbui su matricomis. Todėl nėra jokios priežasties delete , kad būtų specialus atvejis, pasirengęs iš naujo išstumti masyvą, nes tai paprasčiausiai sulėtins darbą be nereikalingo darbo. Žvelgiant atgal, mano lūkesčiai buvo nerealūs.

Žinoma, mane nustebino. Nes parašiau, kad galėčiau pateisinti savo kryžiaus žygį prieš „nulinę šiukšles“:

Nepaisydami pavojaus ir problemų, būdingų null ir švaistomoms erdvėms, tai gali būti problemiška, jei masyvas turi būti tikslus.

Kuris yra baisus pasiteisinimas atsikratyti null s - null yra pavojingas tik tuo atveju, jei jis naudojamas neteisingai ir neturi nieko bendro su „tikslumu“. Tikroji priežastis, dėl kurios neturėtumėte delete iš masyvo, yra ta, kad šiukšlių ir nešvarių duomenų struktūrų palikimas aplinkoje yra nepatogus ir klaidingas.

Žemiau yra sukurtas scenarijus, kuris tampa gana ilgas, todėl, jei norite, galite pereiti į skyrių „Sprendimas“ . Vienintelė priežastis, dėl kurios palieku šį skyrių, yra ta, kad manau, kad kai kurie žmonės, atrodo, juokauja, ir nenoriu būti „vaikinu“, kuris siunčia „juokingą“ atsakymą ir ištrina jį. visi „juokingi“,

... Tai kvaila, aš žinau.

Prognozuojamas ir ilgalaikis scenarijus PDP-11

Pvz., Tarkime, kad sukuriate žiniatinklį, kuris naudoja JSON serializaciją, kad išsaugotų seką naudojamą masyvą eilutėje ( localStorage šiuo atveju). Leiskite jiems taip pat pasakyti, kad kodas naudoja masyvo elementų skaitmeninius indeksus, kad juos „pavadintų“, kai piešiami ant ekrano. Kodėl tai darote, o ne tik išlaikote „titulą“? Nes ... priežastys.

Gerai, leiskite man pasakyti, kad bandote išsaugoti atmintį šio vieno naudotojo prašymu, kuris nuo 1960 m. Valdo PDP-11 mini kompiuterį, kuriame veikia UNIX, ir parašė savo „JavaScript“ suderinamą sąsają su „JavaScript“ naršyklės palaikymu, nes X11 nėra iš klausimo.

Vis daugiau kvailų scenarijaus ribinio scenarijaus, naudojant delete nurodytą masyvą, null masyvo taršą ir greičiausiai vėliau sukels klaidas programoje. Jei patikrinsite null , jis automatiškai praleidžia numerius, todėl rodomi skirtukai atrodo kaip [1] [2] [4] [5]...

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

Taip, tai tikrai ne tai, ko norėjote.

Dabar galite išsaugoti antrąjį iteratorių, pvz., j , didinti tik tada, kai iš masyvo skaitomos tikrosios vertės. Bet tai neabejotinai neišsprendžia null problemos, ir jums vis dar patinka šis „ Troll PDP-11“ vartotojas. Deja, jo kompiuteryje nėra pakankamai atminties, kad būtų galima išsaugoti šį paskutinį sveikojo skaičiaus numerį (nesakykite, kaip jis sugeba valdyti įvairaus pločio masyvą ...) .

Taigi jis siunčia jums pykčio laišką:

 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 

Dabar jūs esate savo pabaigoje. Šis vaikinas nuolat skundėsi dėl jūsų prašymo, ir jūs norėtumėte jam pasakyti, kad jis užsidarytų ir eiti į geriausią kompiuterį.

Sprendimas: Array.prototype.splice

Laimei, matricos turi specialų metodą indeksų pašalinimui ir atminties perskirstymui: Array.prototype.splice() . Galite rašyti kažką panašaus:

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

Ir taip, jūs esate patenkintas p. PDP-11. Hooray! (Aš vis tiek jam pasakysiu ...)

Array.prototype.splice vs Array.prototype.slice

Manau, svarbu pažymėti skirtumą tarp šių dviejų panašiai pavadintų funkcijų, nes jos abi yra labai naudingos.

Array.prototype.splice (pradžia, n)

.splice() masyvą ir grąžina nuotolinius indeksus. Masyvas supjaustomas pradedant nuo indekso, start ir n elementai supjaustomi. Jei n nenurodytas, visas masyvas po 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 (pradžia, pabaiga)

.slice() yra ne destruktyvus ir grąžina naują masyvą, kuriame yra nurodyti indeksai nuo start iki end . Jei end paliekamas neapibrėžtas, elgesys bus toks pat kaip .splice() ( end = array.length ). Elgesys yra šiek tiek sudėtingas, nes dėl tam tikrų priežasčių end indeksai prasideda nuo 1 vietoj 0. Nežinau, kodėl taip atsitinka, bet tai yra. Be to, jei end <= start , rezultatas yra tuščias masyvas.

 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] 

Tiesą sakant, tai ne tai, kas vyksta, bet apie tai lengviau galvoti. Pasak MDN, tai iš tikrųjų vyksta:

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

Galutinis indeksas paprasčiausiai pašalinamas iš gabalo. Skliausteliuose esantys indeksai rodo, kas yra supjaustyta. Bet kokiu atveju, elgesys nėra intuityvus ir dėl to, kad jis sukelia teisingą klaidų dalį „vienas po kito“, todėl jums gali būti naudinga įvesti įvyniojimo funkciją daugiau nei .splice() elgesio.

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

Atkreipkite dėmesį, kad įvyniojimo funkcija skirta labai stipriems tipams ir grąžina null jei kažkas išjungtas. Tai apima "3" tipo eilutę. Programuotojui išlieka rūpestingas savo tipais. Tai turėtų prisidėti prie geros programavimo praktikos.

Atnaujinimas dėl is_array()

Tai taikoma šiam (dabar ištrintam) fragmentui:

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

Taigi, kaip paaiškėjo, iš tikrųjų yra įmontuotas būdas nustatyti, ar masyvas tikrai yra masyvas, ir tai yra „ Array.isArray() , įvesta ECMAScript 5 (2009 m. Gruodžio mėn.). Я нашел это, глядя на вопрос, есть ли вопрос о том, чтобы сообщать массивы с объектов, чтобы увидеть, было ли лучшее решение, чем мое, или добавить мое, если их не было. Итак, если вы используете версию 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 };