Tại sao tôi có thể thay đổi giá trị của một hằng số trong javascript


101

Tôi biết rằng ES6 chưa được chuẩn hóa, nhưng rất nhiều trình duyệt hiện hỗ trợ const từ khóa trong JS.

Trong đặc tả, nó được viết rằng:

Giá trị của một hằng số không thể thay đổi thông qua việc gán lại và một hằng số không thể được khai báo lại. Do đó, mặc dù có thể khai báo một hằng số mà không cần khởi tạo nó, nhưng làm như vậy sẽ vô ích.

và khi tôi làm điều gì đó như thế này:

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

Tôi thấy rằng tất cả mọi thứ là ok xxxvẫn còn 6yyy[].

Nhưng nếu tôi làm vậy yyy.push(6); yyy.push(1);, mảng hằng số của tôi đã bị thay đổi. Ngay bây giờ nó là [6, 1]và bằng cách này tôi vẫn không thể thay đổi nó với yyy = 1;.

Tôi đây là một lỗi, hay tôi đang thiếu một cái gì đó? Tôi đã thử nó trong chrome và FF29 mới nhất


1
Bạn chỉ cần tạo một lớp, khai báo biến và gán giá trị của nó bên trong lớp. Sau đó, tạo một GETTER cho biến đó; và không triển khai bộ định vị. Nó sẽ triển khai một hằng số ...
Andrew

8
@Andrew cảm ơn, nhưng tôi không hỏi làm thế nào tôi có thể làm điều này. Tôi tò mò tại sao từ khóa const lại hoạt động theo cách này.
Salvador Dali

Câu trả lời:


171

Tài liệu cho biết:

... hằng không thể thay đổi thông qua gán lại
... hằng không thể được khai báo lại

Khi bạn thêm vào một mảng hoặc đối tượng, bạn không gán lại hoặc khai báo lại hằng số, nó đã được khai báo và gán, bạn chỉ thêm vào "danh sách" mà hằng trỏ tới.

Vì vậy, điều này hoạt động tốt:

const x = {};

x.foo = 'bar';

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

x.foo = 'bar2';

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

và điều này:

const y = [];

y.push('foo');

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

y.unshift("foo2");

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

y.pop();

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

nhưng cả hai đều không:

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
vì vậy ý ​​bạn là đây không phải là một lỗi, nhưng nó sẽ hoạt động theo cách này? Bởi vì tôi nghĩ rằng ý tưởng về hằng số là nó không thể thay đổi. Về cơ bản, một lập trình viên tin tưởng rằng không có vấn đề gì sẽ xảy ra, không có gì có thể thay đổi giá trị bên trong hằng số của tôi.
Salvador Dali

2
Tôi nghĩ nó không dễ dàng như vậy, trong trường hợp này giá trị của hằng số là một mảng các phần tử cụ thể. Thay đổi bất cứ điều gì có nghĩa là bạn thay đổi giá trị .
veritas

6
Có, nó phải hoạt động theo cách này, bạn không phải gán lại hằng số, nó vẫn là tham chiếu giống nhau, bạn chỉ thêm vào mảng các tham chiếu hằng số và các mảng và đối tượng giống như "danh sách", sửa đổi chúng. không thay đổi tham chiếu hoặc khai báo lại hằng số.
adeneo

26
@SalvadorDali: hằng số và chỉ đọc là hai thứ khác nhau. Biến của bạn là không đổi , nhưng mảng mà nó trỏ đến không ở chế độ chỉ đọc
Matt Burland

43

Điều này xảy ra bởi vì hằng số của bạn thực sự đang lưu trữ một tham chiếu đến mảng. Khi bạn nối một cái gì đó vào mảng của mình, bạn không sửa đổi giá trị hằng số của mình, mà là mảng mà nó trỏ đến. Điều tương tự sẽ xảy ra nếu bạn gán một đối tượng cho một hằng số và cố gắng sửa đổi bất kỳ thuộc tính nào của nó.

Nếu bạn muốn cố định một mảng hoặc đối tượng để không thể sửa đổi nó, bạn có thể sử dụng Object.freezephương pháp này, đã là một phần của ECMAScript 5.

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

1
Theo cùng một logic đó, hằng số fiveđược đặt thành 5 không thực sự có giá trị là 5, nó chỉ là một tham chiếu đến số 5. ​​Vì vậy, nếu tôi làm vậy, five++tôi sẽ không thay đổi hằng số, chỉ là số mà nó trỏ đến.
Anthony

3
@Anthony điều tham khảo chỉ hoạt động cho các mảng và các đối tượng, giá trị không nguyên thủy
Guilherme Sehn

1
@Anthony Trong ví dụ của bạn, bạn đang thay đổi số mà biến fivetrỏ tới (biến fivetừng là nhãn cho số 5, bây giờ nó trỏ đến một số khác: 6). Trong ví dụ trong câu hỏi (và câu trả lời này), xluôn trỏ đến cùng một danh sách; nếu xlà const, bạn không thể làm cho nó trỏ đến một danh sách khác. Sự khác biệt duy nhất là cùng một danh sách có thể phát triển hoặc thu nhỏ; đây là một cái gì đó chỉ có thể cho các mảng và đối tượng và không cho các nguyên thủy.
ShreevatsaR

9

Đây là hành vi nhất quán với mọi ngôn ngữ lập trình mà tôi có thể nghĩ đến.

Coi C - mảng chỉ là con trỏ được tôn vinh. Một mảng không đổi chỉ có nghĩa là giá trị của con trỏ sẽ không thay đổi - nhưng trên thực tế, dữ liệu chứa tại địa chỉ đó là miễn phí.

Trong javascript, bạn được phép gọi các phương thức của các đối tượng hằng số (tất nhiên - nếu không các đối tượng hằng số sẽ không phục vụ nhiều mục đích!) Các phương thức này có thể có tác dụng phụ là sửa đổi đối tượng. Vì các mảng trong javascript là các đối tượng, hành vi này cũng áp dụng cho chúng.

Tất cả những gì bạn yên tâm là hằng số sẽ luôn trỏ đến cùng một đối tượng. Các thuộc tính của đối tượng tự do thay đổi.


4

Khai báo const tạo ra một tham chiếu chỉ đọc cho một giá trị. Điều đó không có nghĩa là giá trị mà nó giữ là không thay đổi, chỉ là không thể gán lại định danh biến. Ví dụ, trong trường hợp nội dung là một đối tượng, điều này có nghĩa là nội dung của đối tượng (ví dụ: các tham số của nó) có thể bị thay đổi.

Ngoài ra, một lưu ý cũng quan trọng:

Hằng số toàn cục không trở thành thuộc tính của đối tượng cửa sổ ...

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


3

Tôi nghĩ điều này sẽ giúp bạn hiểu rõ hơn về vấn đề: https://codeburst.io/explain-value-vs-reference-in-javascript-647a975e12a0 .

Về cơ bản, nó kết hợp với việc constluôn trỏ đến cùng một địa chỉ trong bộ nhớ. Bạn có thể thay đổi giá trị được lưu trong địa chỉ đó nhưng cũng không thể thay đổi địa chỉ mà constnó đang trỏ tới.

Định nghĩa constmà bạn đã đề cập sẽ đúng khi consttrỏ đến một địa chỉ có giá trị nguyên thủy. Điều này là do bạn không thể gán một giá trị cho nó constmà không thay đổi địa chỉ của nó (vì đây là cách gán các giá trị nguyên thủy hoạt động) và việc thay đổi địa chỉ của a constlà không được phép.

Trong trường hợp như thể consttrỏ tới giá trị không phải nguyên thủy, có thể chỉnh sửa giá trị của địa chỉ.


1

Xem qua bài viết này trong khi tìm kiếm lý do tại sao tôi có thể cập nhật một Đối tượng ngay cả sau khi xác định nó là const. Vì vậy, mấu chốt ở đây là nó không phải là đối tượng trực tiếp mà là các thuộc tính mà nó chứa có thể được cập nhật.

Ví dụ: Đối tượng của tôi trông giống như:

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

Các câu trả lời trên đã chỉ ra một cách chính xác rằng đó là Đối tượng là const chứ không phải thuộc tính của nó. Do đó, tôi sẽ có thể cập nhật id hoặc tên bằng cách:

number.name = 'John';

Tuy nhiên, tôi sẽ không thể cập nhật chính Đối tượng như:

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

TypeError: Assignment to constant variable.

1
ví dụ của bạn là một ví dụ thực tế và mô tả chính xác
Ebrahim

0

Bởi vì trong const bạn có thể thay đổi các giá trị của một đối tượng, vì vậy đối tượng không thực sự lưu trữ dữ liệu gán mà thay vào đó, nó trỏ đến nó. vì vậy có sự khác biệt giữa nguyên thủy và đối tượng trong Javascript.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.