Чому я можу змінити значення константи в javascript?


101

Я знаю, що ES6 ще не стандартизований, але в даний час багато браузерів підтримують const ключові слова в JS.

У специфікації написано, що:

Значення константи не може змінюватися шляхом повторного призначення, а константа не може бути повторно оголошена. Через це, хоча можливо оголосити константу, не ініціалізуючи її, робити це було б марно.

і коли я роблю щось подібне:

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

Я бачу, що все нормально xxx- це все ще 6і yyyє [].

Але якщо я це зроблю yyy.push(6); yyy.push(1);, мій постійний масив було змінено. Зараз це так, [6, 1]і, до речі, я все ще не можу це змінити yyy = 1;.

Я це помилка, чи мені чогось не вистачає? Я спробував це в останньому хромі та FF29


1
Чи можете ви просто створити клас, оголосити змінну та призначити її значення всередині класу. Потім створіть GETTER для цієї змінної; і не застосовуйте сеттер. Він повинен реалізувати константу ...
Ендрю

8
@Andrew дякую, але я не питаю, як я можу це зробити. Мені цікаво, чому ключове слово const поводиться так.
Сальвадор Далі,

Відповіді:


172

У документації зазначено:

... константа не може змінитися через перепризначення
... константа не може бути повторно оголошена

Коли ви додаєте до масиву або об'єкта, який не перепризначаєте або не оголошуєте константу, вона вже оголошена і призначена, ви просто додаєте до "списку", на який вказує константа.

Отже, це чудово працює:

const x = {};

x.foo = 'bar';

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

x.foo = 'bar2';

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

і це:

const y = [];

y.push('foo');

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

y.unshift("foo2");

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

y.pop();

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

але жоден із цих:

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

4
отже, ви маєте на увазі, що це не помилка, але вона повинна працювати так? Тому що я думав, що ідея константи полягає в тому, що її не можна змінити. В основному програміст має довіру, що незалежно від того, що станеться, ніщо не може змінити значення всередині моєї константи.
Сальвадор Далі,

2
Я думаю, що це не так просто, у цьому випадку значення константи є масивом конкретних елементів. Зміна чого-небудь означає, що ви змінюєте значення .
veritas

6
Так, це повинно працювати таким чином, ви не перепризначаєте константу, це все те саме посилання, ви просто додаєте до масиву посилання на константу, а масиви та об'єкти схожі на "списки", їх зміна робить не змінювати посилання або повторно оголошувати константу.
adeneo

26
@SalvadorDali: постійне та лише для читання - це дві різні речі. Ваша змінна є постійною , але масив, на який вона вказує, не доступний лише для читання
Matt Burland

43

Це відбувається тому, що ваша константа насправді зберігає посилання на масив. Коли ви приєднуєте щось у своєму масиві, ви змінюєте не своє постійне значення, а масив, на який він вказує. Те ж саме сталося б, якби ви призначили об’єкт константі і спробували змінити будь-яку його властивість.

Якщо ви хочете заморозити масив або об’єкт, щоб його не можна було змінити, ви можете скористатися Object.freezeметодом, який уже є частиною ECMAScript 5.

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

1
За цією ж логікою константа, fiveвстановлена ​​на 5, насправді не має значення 5, це просто посилання на число 5. Отже, якщо я це five++роблю, я не змінюю константу, а просто число, на яке вона вказує.
Ентоні

3
@Anthony посилальна річ працює лише для масивів та об'єктів, а не примітивних значень
Guilherme Sehn

1
@Anthony У вашому прикладі ви змінюєте число, на яке fiveвказує змінна (раніше змінна fiveбула міткою для числа 5, тепер вона вказує на інше число: 6). У прикладі у питанні (і цій відповіді) xзавжди вказує на один і той же список; якщо xце const, ви не можете вказати на інший список. Єдина відмінність полягає в тому, що один і той же список може зростати або зменшуватися; це можливо лише для масивів та об'єктів, а не для примітивів.
ShreevatsaR

9

Це послідовно поводиться з кожною мовою програмування, яку я можу придумати.

Розглянемо С - масиви - це просто прославлені вказівники. Постійний масив означає лише те, що значення покажчика не зміниться - але насправді дані, що містяться за цією адресою, вільні.

У javascript вам дозволено викликати методи постійних об'єктів (звичайно - інакше постійні об'єкти не мали б особливої ​​мети!) Ці методи можуть мати побічний ефект модифікації об'єкта. Оскільки масиви в javascript є об'єктами, така поведінка стосується і них.

Все, що ви впевнені, це те, що константа завжди буде вказувати на один і той же об’єкт. Властивості самого об’єкта можна вільно змінювати.


4

Оголошення const створює посилання лише на читання на значення. Це не означає, що значення, яке він має, є незмінним, просто ідентифікатор змінної не може бути перепризначений. Наприклад, у випадку, коли вміст є об'єктом, це означає, що вміст об'єкта (наприклад, його параметри) може бути змінений.

Крім того, також важлива примітка:

Глобальні константи не стають властивостями віконного об'єкта ...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const


3

Думаю, це дасть вам більше ясності у питанні: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0 .

В основному це зводиться до constзавжди вказує на ту саму адресу в пам'яті. Ви можете змінити значення, що зберігається в цій адресі, але також не можете змінити адресу, на яку constвказує.

Визначене constвами згадане буде справедливим, коли constвказує на адресу, яка має примітивне значення. Це пов’язано з тим, що ви не можете призначити цьому значення constбез зміни його адреси (оскільки саме так працює присвоєння примітивних значень) і змінити адресу a constне дозволяється.

Де так, ніби the constвказує на непримітивне значення, можна змінити значення адреси.


1

Прочитав цю статтю під час пошуку, чому я зміг оновити Об’єкт навіть після визначення його як const. Отже, справа тут у тому, що оновити можна не безпосередньо об’єкт, а атрибути, які він містить.

Наприклад, мій Object виглядає так:

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

Наведені вище відповіді правильно вказали, що це Об’єкт, який є const, а не його атрибут. Отже, я зможу оновити ідентифікатор або ім'я, виконавши:

number.name = 'John';

Але я не зможу оновити сам Об'єкт, як:

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

TypeError: Assignment to constant variable.

1
ваш приклад практичний та правильні описи
Ебрагім,

0

Оскільки в const ви можете змінювати значення об’єкта, тож об’єкт насправді не зберігає дані призначення, а натомість вказує на нього. тому існує різниця між примітивами та об’єктами в Javascript.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.