ecmascript 6 - Hvorfor kan jeg endre et konstant objekt i JavaScript?
Jeg vet at ES6 ikke er standardisert ennå, men mange nettlesere støtter for tiden const-nøkkelordet i JS.
I spesifikasjonen står det at:
Verdien av en konstant kan ikke endres gjennom ny tildeling, og en konstant kan ikke erklæres på nytt. På grunn av dette, selv om det er mulig å erklære en konstant uten å initialisere den, ville det være meningsløst å gjøre det.
og når jeg gjør noe sånt som dette:
const xxx = 6;
xxx = 999;
xxx++;
const yyy = [];
yyy = 'string';
yyy = [15, 'a'];
Jeg ser at alt er ok: xxx er fortsatt 6 og yyy er [].
Men hvis jeg gjør yyy.push(6); yyy.push(1); , har min konstante array blitt endret. Akkurat nå er den [6, 1] og forresten kan jeg fortsatt ikke endre den med yyy=1;.
Er dette en feil, eller går jeg glipp av noe? Jeg prøvde det i den nyeste versjonen av Chrome og FF29
Svar #1
MDN-dokumentasjonen sier:
...konstanten kan ikke endres gjennom ny tildeling
...konstanten kan ikke deklareres på nytt
Når du legger til i et array eller objekt, tildeler eller erklærer du ikke konstanten på nytt; den er allerede erklært og tildelt. Du legger bare til i listen over elementer eller egenskaper som konstanten peker på.
Så dette fungerer fint:
const x = {};
x.foo = 'bar';
console.log(x); // {foo : 'bar'}
x.foo = 'bar2';
console.log(x); // {foo : 'bar2'}
og dette:
const y = [];
y.push('foo');
console.log(y); // ['foo']
y.unshift("foo2");
console.log(y); // ['foo2', 'foo']
y.pop();
console.log(y); // ['foo2']
men ingen av disse:
const x = {};
x = {foo: 'bar'}; // error - re-assigning
const y = ['foo'];
const y = ['bar']; // error - re-declaring
const foo = 'bar';
foo = 'bar2'; // error - can not re-assign
var foo = 'bar3'; // error - already declared
function foo() {}; // error - already declared
Svar #2
Dette skjer fordi konstanten din faktisk lagrer en referanse til arrayen. Når du legger noe inn i arrayen din, endrer du ikke konstantverdien din, men arrayen den peker til. Det samme ville skjedd hvis du tildelte et objekt til en konstant og prøvde å endre en hvilken som helst egenskap ved det.
Hvis du vil fryse et array eller objekt slik at det ikke kan endres, kan du bruke Object.freeze-metoden, som allerede er en del av ECMAScript 5.
const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]
Svar #3
Kom over denne artikkelen mens jeg søkte på hvorfor jeg kunne oppdatere et objekt selv etter å ha definert det som const. Så poenget her er at det ikke er objektet direkte, men attributtene det inneholder som kan oppdateres.
For eksempel ser objektet mitt slik ut:
const number = {
id:5,
name:'Bob'
};
De ovennevnte svarene påpekte korrekt at det er objektet som er konstant og ikke dets attributt. Derfor vil jeg kunne oppdatere id eller navn ved å gjøre:
number.name = 'John';
Men jeg vil ikke kunne oppdatere selve objektet slik som:
number = {
id:5,
name:'John'
};
TypeError: Assignment to constant variable.
Svar #4
Dette er konsekvent oppførsel med alle programmeringsspråk jeg kan tenke meg.
Tenk på C - arrayer er bare glorifiserte pekere. En konstant array betyr bare at verdien til pekeren ikke vil endre seg - men faktisk er dataene som ligger på den adressen fri til det.
I JavaScript er du tillatt å kalle metoder på konstante objekter (selvfølgelig - ellers ville konstante objekter ikke ha mye nytte!) Disse metodene kan ha bieffekten av å endre objektet. Siden arrays i JavaScript er objekter, gjelder denne oppførselen også for dem.
Det eneste du er sikker på er at konstanten alltid vil peke på det samme objektet. Egenskapene til selve objektet kan derimot endres.
Svar #5
Nøkkelordet const er litt misvisende.
Det definerer ikke en konstant verdi. Det definerer en konstant referanse til en verdi.
På grunn av dette kan du IKKE:
- Tildele en konstant verdi på nytt
- Tildele en konstant matrise på nytt
- Tildel et konstant objekt på nytt
Men du KAN:
- Endre en konstant array
- Endre et konstant objekt
