ecmascript 6 - Proč mohu měnit konstantní objekt v JavaScriptu?
Vím, že ES6 ještě není standardizováno, ale hodně prohlížečů aktuálně podporuje klíčové slovo const v JS.
Ve specifikaci je napsáno, že:
Hodnota konstanty nemůže být změněna při znovupřiřazení a konstanta nemůže být znovu deklarována. Kvůli tomu, ačkoli je možné deklarovat konstantu bez jejího inicializování, bylo by to k ničemu.
a když udělám něco takového:
const xxx = 6;
xxx = 999;
xxx++;
const yyy = [];
yyy = 'string';
yyy = [15, 'a'];
Vidím, že je všechno v pořádku: xxx je stále 6 a yyy je [].
Ale pokud udělám yyy.push(6); yyy.push(1); , moje konstantní pole se změnilo. Teď je to [6, 1] a mimochodem ho stále nemohu změnit pomocí yyy=1;.
Je to chyba, nebo něco přehlížím? Zkoušel jsem to v nejnovějším Chromu a FF29.
Odpověď č. 1
Dokumentace MDN uvádí:
...konstantu nelze změnit přesměrováním
...konstantu nelze znovu deklarovat
Když něco přidáváte do pole nebo objektu, nepřiřazujete ho znovu ani znovu nevyhlašujete; už je deklarován a přiřazen. Jen přidáváte do seznamu prvků nebo vlastností, na které konstanta odkazuje.
Takže to funguje dobře:
const x = {};
x.foo = 'bar';
console.log(x); // {foo : 'bar'}
x.foo = 'bar2';
console.log(x); // {foo : 'bar2'}
a toto:
const y = [];
y.push('foo');
console.log(y); // ['foo']
y.unshift("foo2");
console.log(y); // ['foo2', 'foo']
y.pop();
console.log(y); // ['foo2']
ale ani jeden z těchto:
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
Odpověď č. 2
To se stane, protože vaše konstanta ve skutečnosti ukládá odkaz na pole. Když něco přidáte do svého pole, neměníte hodnotu své konstanty, ale pole, na které odkazuje. Totéž by se stalo, kdybyste přiřadili objekt ke konstantě a pokusili se změnit jakoukoli jeho vlastnost.
Pokud chcete zamrazit pole nebo objekt, aby nemohl být upravován, můžete použít metodu Object.freeze, která je již součástí ECMAScript 5.
const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]
Odpověď č. 3
Narazil jsem na tento článek při hledání, proč jsem mohl aktualizovat objekt i poté, co jsem ho definoval jako const. Takže pointa je v tom, že se nejedná přímo o objekt, ale o atributy, které obsahuje a které lze aktualizovat.
Například můj objekt vypadá takto:
const number = {
id:5,
name:'Bob'
};
Výše uvedené odpovědi správně poukázaly na to, že je to objekt, který je konstantní, a nikoli jeho atribut. Proto budu schopen aktualizovat id nebo jméno tímto způsobem:
number.name = 'John';
Ale nebudu schopen aktualizovat samotný objekt, jako například:
number = {
id:5,
name:'John'
};
TypeError: Assignment to constant variable.
Odpověď č. 4
To je konzistentní chování se všemi programovacími jazyky, na které si dokážu vzpomenout.
Uvažujte C - pole jsou jen povýšené ukazatele. Konstantní pole znamená jen to, že hodnota ukazatele se nebude měnit - ale ve skutečnosti mohou být data uložená na této adrese libovolně měněna.
V JavaScriptu je povoleno volat metody konstantních objektů (samozřejmě - jinak by konstantní objekty neměly moc smysl!). Tyto metody mohou mít vedlejší efekt změny objektu. Protože pole v JavaScriptu jsou objekty, toto chování se na ně také vztahuje.
Jediné, čeho si můžete být jisti, je, že konstanta bude vždy ukazovat na stejný objekt. Vlastnosti samotného objektu se mohou měnit.
Odpověď č. 5
Klíčové slovo const je trochu zavádějící.
Neurčuje konstantní hodnotu. Určuje konstantní odkaz na hodnotu.
Kvůli tomu NEMŮŽETE:
- Přiřadit konstantní hodnotu znovu
- Přiřadit konstantní pole znovu
- Přiřadit konstantní objekt znovu
Ale TY MŮŽEŠ:
- Změnit konstantní pole
- Změnit konstantní objekt
