ecmascript 6 - Varför kan jag ändra ett konstant objekt i JavaScript?


Jag vet att ES6 ännu inte är standardiserat, men många webbläsare stöder för närvarande const-nyckelordet i JS.

I specifikationen står det att:

Värdet av en konstant kan inte ändras genom omtilldelning, och en konstant kan inte deklareras på nytt. På grund av detta, även om det är möjligt att deklarera en konstant utan att initiera den, skulle det vara meningslöst att göra det.

och när jag gör något som detta:

const xxx = 6;
xxx = 999;
xxx++;
const yyy = [];
yyy = 'string';
yyy = [15, 'a'];

Jag ser att allt är okej: xxx är fortfarande 6 och yyy är [].

Men om jag gör yyy.push(6); yyy.push(1); , har min konstant array ändrats. Just nu är den [6, 1] och förresten kan jag fortfarande inte ändra den med yyy=1;.

Är detta ett fel, eller missar jag något? Jag har provat det i senaste Chrome och FF29

Svar #1

MDN-dokumentation anger:

...konstanten kan inte ändras genom omtilldelning
...konstanten kan inte deklareras om

När du lägger till i en array eller ett objekt omdefinierar eller deklarerar du inte konstanten; den är redan deklarerad och tilldelad. Du lägger bara till i listan över element eller egenskaper som konstanten pekar på.

Så detta fungerar bra:

const x = {};

x.foo = 'bar';

console.log(x); // {foo : 'bar'}

x.foo = 'bar2';

console.log(x); // {foo : 'bar2'}  

och detta:

const y = [];

y.push('foo');

console.log(y); // ['foo']

y.unshift("foo2");

console.log(y); // ['foo2', 'foo']

y.pop();

console.log(y); // ['foo2']

men inte någon av dessa:

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

Detta händer eftersom din konstant faktiskt lagrar en referens till arrayen. När du lägger till något i din array ändrar du inte ditt konstantvärde, utan arrayen som det pekar på. Samma sak skulle hända om du tilldelade ett objekt till en konstant och försökte ändra någon av dess egenskaper.

Om du vill frysa en array eller ett objekt så att det inte kan ändras, kan du använda Object.freeze-metoden, som redan är en del av ECMAScript 5.

const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]

Svar #3

Kom över denna artikel medan jag sökte på varför jag kunde uppdatera ett objekt även efter att ha definierat det som const. Så poängen här är att det inte är objektet direkt utan de attribut det innehåller som kan uppdateras.

Till exempel ser mitt objekt ut så här:

const number = {
    id:5,
    name:'Bob'
};

De ovanstående svaren påpekade korrekt att det är objektet som är konstant och inte dess attribut. Därför kommer jag att kunna uppdatera id eller namn genom att göra:

number.name = 'John';

Men jag kommer inte att kunna uppdatera själva objektet som:

number = {
    id:5,
    name:'John'
  };

TypeError: Assignment to constant variable.

Svar #4

Detta är konsekvent beteende med varje programmeringsspråk jag kan tänka mig.

Tänk på C - arrayer är bara förhöjda pekare. En konstant array betyder bara att värdet på pekaren inte kommer att förändras - men i själva verket är datan som finns på den adressen fri att förändra.

I JavaScript är du tillåten att kalla på metoder av konstanta objekt (naturligtvis - annars skulle konstanta objekt inte ha mycket nytta!) Dessa metoder kan ha bieffekten att ändra objektet. Eftersom arrayer i JavaScript är objekt gäller detta beteende även för dem.

Det enda du kan vara säker på är att konstanten alltid kommer att peka på samma objekt. Själva objektets egenskaper kan däremot ändras.

Svar #5

Nyckelordet const är lite missvisande.

Det definierar inte ett konstant värde. Det definierar en konstant referens till ett värde.

På grund av detta kan du INTE:

  • Tilldela ett konstant värde på nytt
  • Tilldela om en konstant array
  • Tilldela om ett konstant objekt

Men du KAN:

  • Ändra en konstant matris
  • Ändra ett konstant objekt

Relaterade artiklar