Stel dat ik een object als volgt maak:
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
Wat is de beste manier om de eigenschap regex
te verwijderen om te eindigen met nieuw myObject
als volgt?
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI"
};
Zoals dit:
delete myObject.regex;
// or,
delete myObject['regex'];
// or,
var prop = "regex";
delete myObject[prop];
Demo
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
delete myObject.regex;
console.log(myObject);
Voor iedereen die er meer over wil lezen, Stack Overflow gebruiker kangax heeft een ongelofelijk diepgaande blog post geschreven over het delete
statement op hun blog, Understanding delete. Het is een echte aanrader.
var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
delete myObject.regex;
console.log ( myObject.regex); // logs: undefined
Dit werkt in Firefox en Internet Explorer, en ik denk dat het werkt in alle andere.
Update 2018-07-21: Voor een lange tijd heb ik me beschaamd gevoeld over dit antwoord, dus ik denk dat het tijd is dat ik het een beetje bijwerk. Gewoon een beetje commentaar, verduidelijking en opmaak om het lezen van de nodeloos lange en ingewikkelde delen van dit antwoord te helpen bespoedigen.
obj // {"foo": "bar"}
delete obj["foo"]
obj // {}
obj["foo"] // undefined
Gebruik niet delete
van een array. Gebruik in plaats daarvan Array.prototype.splice
.
arr // [1,2,3,4,5]
arr.splice(3,1); // 4
arr // [1,2,3,5]
var array = [1, 2, 3, 4];
delete array[2];
/* Expected result --> [1, 2, 4]
* Actual result --> [1, 2, null, 4]
*/
Zoals je kunt zien, werkt delete
niet altijd zoals je zou verwachten. De waarde wordt overschreven, maar het geheugen wordt niet opnieuw toegewezen. Dat wil zeggen, array[4]
wordt niet verplaatst naar array[3]
. Dit in tegenstelling tot Array.prototype.unshift
, die een element aan het begin van de array plaatst en alles omhoog schuift (array[0]
wordt array[1]
, etc.)
Eerlijk gezegd, afgezien van het instellen op null
in plaats van undefined
- wat legitiem vreemd is - zou dit gedrag niet verrassend moeten zijn, omdat delete
een unary operator is, net als typeof
, die in de taal is ingebakken en zich niets hoeft aan te trekken van het type object waarop het wordt gebruikt, terwijl Array
een subklasse is van Object
met methodes die specifiek ontworpen zijn voor het werken met arrays. Er is dus geen goede reden voor delete
om een speciaal geval in te bouwen voor het verschuiven van de array, want dat zou de dingen alleen maar vertragen met onnodig werk. Achteraf gezien waren mijn verwachtingen onrealistisch.
Natuurlijk, het verraste me. Omdat ik dit schreef om mijn kruistocht tegen "null garbage" te rechtvaardigen:
De gevaren en problemen inherent aan
null
negerend, en de verspilde ruimte, kan dit problematisch zijn als de array nauwkeurig moet zijn. Dat is een verschrikkelijke rechtvaardiging om van denull
s af te komen--null
is alleen gevaarlijk als het verkeerd gebruikt wordt, en het heeft niets te maken met "precisie". De echte reden om een array niet tedeleten
is dat het slordig en foutgevoelig is om rommelige en rommelige datastructuren te laten bestaan. Wat volgt is een verzonnen scenario dat nogal langdradig wordt, dus je kunt naar de sectie De oplossing gaan als je wilt. De enige reden waarom ik dit gedeelte laat staan is dat ik denk dat sommige mensen het waarschijnlijk grappig vinden, en ik wil niet "die vent" zijn die een "grappig" antwoord plaatst en dan later al het "grappige" eruit verwijdert. ...Het is stom, ik weet het.Het PDP-11 scenario
Stel bijvoorbeeld dat je een webapp maakt die JSON-serialisatie gebruikt om een array die gebruikt wordt voor 'tabs' op te slaan in een string (in dit geval,
localStorage
). Laten we ook zeggen dat de code de numerieke indexen van de leden van de array gebruikt om ze te "titelen" bij het tekenen naar het scherm. Waarom doe je dit in plaats van gewoon de "titel" ook op te slaan? Omdat... redenen. Oké, laten we zeggen dat je probeert geheugen te besparen op verzoek van één gebruiker die een PDP-11 minicomputer uit de jaren 1960 draait met UNIX en zijn eigen Elinks-gebaseerde, JavaScript-compliant, lijn-printer-vriendelijke browser schreef omdat X11 uit den boze is. Afgezien van het steeds dommer wordende edge-case scenario, zal het gebruik vandelete
op de genoemde array resulteren innull
dat de array vervuilt, en waarschijnlijk later bugs in de app veroorzaakt. En als je controleert opnull
, dan worden de nummers overgeslagen, met als resultaat dat de tabs worden weergegeven als[1] [2] [4] [5] ...
. als (array[index] == null) ga verder; anders title = (index + 1).toString(); /* 0 -> "1"
- 1 -> "2"
- 2 -> (niets)
- 3 -> "4" / Ja, dat is zeker niet wat je wilde. Nu, je kunt een tweede iterator houden, zoals
j
, om alleen te incrementeren als er geldige waarden uit de array worden gelezen. Maar dat zou niet echt hetnull
probleem oplossen, en je moet nog steeds dietrollPDP-11 gebruiker tevreden stellen. Helaas, zijn computer heeft niet* genoeg geheugen om die laatste integer op te slaan (vraag niet hoe hij een array met variabele breedte aankan...). Dus stuurt hij je boos een e-mail: Hé, jouw webapp heeft mijn browser kapot gemaakt! Ik controleerde mijn localStorage database nadat jouw stomme code mijn browser deed segfouten, en dit is wat ik vond: "tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... ]" Na het wissen van mijn kostbare gegevens, het segfaulted weer, en ik deed een backtrace, en wat vind ik? WAT VIND IK!? JE GEBRUIKT TE VEEL VARIABELEN! var i = index;var j = 1; Grr, ik ben boos nu. -Troll Davidson Ongeveer nu, ben je op het einde van je latijn. Deze kerel klaagt non-stop over je app, en je wilt hem vertellen dat hij zijn mond moet houden en een betere computer moet kopen.
De oplossing:
Array.prototype.splice
Gelukkig hebben arrays wel een gespecialiseerde methode om indices te verwijderen en geheugen toe te wijzen:
Array.prototype.splice()
. Je zou iets als dit kunnen schrijven:
Array.prototype.remove = function(index){
this.splice(index,1);
}
...
array = [1, 2, 3, 4];
array.remove(2);
// Result -> [1, 2, 4]
En zo heb je Mr. PDP-11 tevreden gesteld. Hoera! (Ik zou hem nog steeds uitschelden, dat wel...)
Ik vind het belangrijk om het verschil aan te geven tussen deze twee functies met dezelfde naam, omdat ze allebei erg nuttig zijn.
.splice()
muteert de array, en geeft de verwijderde indices terug. De array wordt in stukken gesneden vanaf de index, start
, en n
elementen worden eruit gesneden. Als n niet is opgegeven, wordt de hele array na start
weggesneden (n = array.lengte - 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]
.slice()
is niet-destructief en geeft een nieuwe array terug met de aangegeven indexen van start
tot eind
. Als eind
niet is opgegeven, is het gedrag hetzelfde als .splice()
(eind = array.lengte
). Het gedrag is een beetje lastig omdat, om een of andere reden, end
indexeert vanaf 1 in plaats van 0. Ik weet niet waarom het zo doet, maar zo is het nu eenmaal. Ook, als end <= start
, is het resultaat een lege array.
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]
Dat is eigenlijk niet wat er gebeurt, maar het is makkelijker om het op die manier te zien. Volgens MDN, is dit wat er echt gebeurt:
// 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
De index gespecificeerd door end
wordt simpelweg uitgesloten van de slice. De indices tussen haakjes geven aan wat er gesneden wordt. Hoe dan ook, het gedrag is niet intuïtief en het zal zeker zijn deel van de off-by-one fouten veroorzaken, dus je zou het nuttig kunnen vinden om een wrapper functie te maken om het gedrag van .splice()
beter te emuleren:
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);
}
Merk op dat de wrapper functie ontworpen is om zeer strikt te zijn over types, en zal null
teruggeven als er iets fout is. Dat is inclusief het invoeren van een string als "3"
. Het wordt aan de programmeur overgelaten om zorgvuldig met zijn types om te gaan. Dit is om goed programmeren aan te moedigen.
is_array()
Dit is met betrekking tot deze (nu verwijderde) snippet:
function is_array(array){
return array !== null
&& typeof array === "object"
&& typeof array.length !== "undefined"
&& array.__proto__ === Array.prototype;
}
Het blijkt dat er een ingebouwde manier is om te bepalen of een array echt een array is, en dat is Array.isArray()
, geïntroduceerd in ECMAScript 5 (December 2009). Ik vond dit terwijl ik aan het kijken was of er een vraag was over het verschil tussen arrays en objecten, om te zien of er een betere oplossing was dan de mijne, of om de mijne toe te voegen als die er niet was. Dus, als je een versie van JavaScript gebruikt die ouder is dan ECMA 5, dan is daar je polyfill. Ik raad je echter sterk af om mijn is_array()
functie te gebruiken, omdat het blijven ondersteunen van oude versies van JavaScript betekent dat je de oude browsers die deze implementeren blijft ondersteunen, wat betekent dat je het gebruik van onveilige software aanmoedigt en gebruikers in gevaar brengt voor malware. Dus alsjeblieft, gebruik Array.isArray()
. Gebruik let
en const
. Gebruik de nieuwe functies die aan de taal worden toegevoegd. Gebruik geen vendor prefixes. Verwijder die IE polyfill onzin van je website. Verwijder ook die XHTML <!CDATA[[...
rotzooi - we zijn al in 2014 overgestapt op HTML5. Hoe sneller iedereen de ondersteuning voor die oude/esoterische browsers intrekt, hoe sneller de browserleveranciers de webstandaard zullen volgen en de nieuwe technologie zullen omarmen, en hoe sneller we kunnen overstappen op een veiliger web.