Mengapa saya bisa mengubah nilai konstanta di javascript

102

Saya tahu bahwa ES6 belum terstandarisasi, tetapi banyak browser saat ini mendukung const kata kunci dalam JS.

Secara spesifik, tertulis bahwa:

Nilai konstanta tidak dapat diubah melalui penetapan ulang, dan konstanta tidak dapat dideklarasikan ulang. Karena itu, meskipun mungkin untuk mendeklarasikan sebuah konstanta tanpa memulainya, hal itu akan sia-sia.

dan ketika saya melakukan sesuatu seperti ini:

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

Saya melihat bahwa semuanya ok xxxmasih 6dan yyyadalah [].

Tetapi jika saya melakukannya yyy.push(6); yyy.push(1);, array konstan saya telah diubah. Sekarang ini [6, 1]dan omong-omong saya masih tidak bisa mengubahnya dengan yyy = 1;.

Apakah ini bug, atau saya melewatkan sesuatu? Saya mencobanya di chrome dan FF29 terbaru

Salvador Dali
sumber
1
Bisakah Anda membuat kelas, mendeklarasikan variabel dan menetapkan nilainya di dalam kelas. Kemudian, buat GETTER untuk variabel itu; dan tidak menerapkan penyetel. Ini harus menerapkan konstanta ...
Andrew
8
@Andrew terima kasih, tapi saya tidak bertanya bagaimana saya bisa melakukan ini. Saya ingin tahu mengapa kata kunci const berperilaku seperti ini.
Salvador Dali

Jawaban:

174

Dokumentasi menyatakan:

... konstanta tidak dapat diubah melalui penugasan ulang
... konstanta tidak dapat dideklarasikan kembali

Saat Anda menambahkan ke larik atau objek yang tidak Anda tetapkan ulang atau deklarasikan ulang konstanta, itu sudah dideklarasikan dan ditetapkan, Anda hanya menambahkan ke "daftar" yang ditunjuk oleh konstanta.

Jadi ini berfungsi dengan baik:

const x = {};

x.foo = 'bar';

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

x.foo = 'bar2';

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

dan ini:

const y = [];

y.push('foo');

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

y.unshift("foo2");

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

y.pop();

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

tapi tidak satu pun dari ini:

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
adeneo
sumber
4
jadi maksud Anda ini bukan bug, tetapi seharusnya berfungsi seperti ini? Karena saya pikir gagasan tentang konstanta itu tidak bisa diubah. Pada dasarnya seorang programmer percaya bahwa apa pun yang akan terjadi, tidak ada yang dapat mengubah nilai di dalam konstanta saya.
Salvador Dali
2
Menurut saya tidak begitu mudah, dalam hal ini nilai konstanta adalah array dari elemen tertentu. Mengubah apa pun berarti Anda mengubah nilainya .
veritas
6
Ya, itu seharusnya bekerja dengan cara ini, Anda tidak menetapkan ulang konstanta, itu masih referensi yang sama, Anda hanya menambahkan ke array referensi konstan, dan array dan objek seperti "daftar", mengubahnya tidak tidak mengubah referensi atau mendeklarasikan ulang konstanta.
adeneo
27
@SalvadorDali: konstan dan hanya-baca adalah dua hal yang berbeda. Variabel Anda konstan , tetapi larik yang ditunjuknya bukan hanya-baca
Matt Burland
46

Ini terjadi karena konstanta Anda sebenarnya menyimpan referensi ke array. Ketika Anda menggabungkan sesuatu ke dalam array Anda, Anda tidak mengubah nilai konstanta Anda, tetapi array yang ditunjuknya. Hal yang sama akan terjadi jika Anda menetapkan objek ke konstanta dan mencoba mengubah properti apa pun darinya.

Jika Anda ingin membekukan larik atau objek agar tidak dapat dimodifikasi, Anda dapat menggunakan Object.freezemetode yang sudah menjadi bagian dari ECMAScript 5.

const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]
Guilherme Sehn
sumber
1
Dengan logika yang sama, fivehimpunan konstan ke 5 sebenarnya tidak memiliki nilai 5, itu hanya referensi ke bilangan 5. Jadi jika saya melakukannya, five++saya tidak mengubah konstanta, hanya angka yang ditunjukkannya.
Anthony
3
@Anthony referensi hal hanya berfungsi untuk array dan objek, bukan nilai primitif
Guilherme Sehn
1
@Anthony Dalam contoh Anda, Anda mengubah angka yang dituju variabel five(variabel yang fivedulunya adalah label untuk angka 5, sekarang menunjuk ke angka yang berbeda: 6). Dalam contoh di pertanyaan (dan jawaban ini), xselalu menunjuk ke daftar yang sama; if xis const Anda tidak dapat membuatnya menunjuk ke daftar yang berbeda. Satu-satunya perbedaan adalah bahwa daftar yang sama dapat bertambah atau berkurang; ini adalah sesuatu yang hanya mungkin untuk array dan objek dan bukan untuk primitif.
ShreevatsaR
9

Ini adalah perilaku yang konsisten dengan setiap bahasa pemrograman yang dapat saya pikirkan.

Pertimbangkan C - array hanyalah petunjuk yang dimuliakan. Array konstan hanya berarti bahwa nilai penunjuk tidak akan berubah - tetapi pada kenyataannya data yang terkandung di alamat itu bebas.

Dalam javascript, Anda diizinkan untuk memanggil metode objek konstan (tentu saja - jika objek konstan tidak akan melayani banyak tujuan!) Metode ini mungkin memiliki efek samping memodifikasi objek. Karena array dalam javascript adalah objek, perilaku ini juga berlaku untuk mereka.

Anda hanya yakin bahwa konstanta akan selalu menunjuk ke objek yang sama. Properti dari objek itu sendiri bebas berubah.

hari Kamis
sumber
4

Deklarasi const membuat referensi hanya-baca ke suatu nilai. Ini tidak berarti nilai yang dimilikinya tidak dapat diubah, hanya saja pengidentifikasi variabel tidak dapat ditetapkan kembali. Misalnya, dalam kasus di mana konten adalah objek, ini berarti konten objek (misalnya, parameternya) dapat diubah.

Selain itu, catatan penting juga:

Konstanta global tidak menjadi properti objek jendela ...

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

Benjamin West
sumber
3

Saya pikir ini akan memberi Anda kejelasan lebih lanjut tentang masalah ini: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0 .

Pada dasarnya intinya adalah constselalu menunjuk ke alamat yang sama dalam memori. Anda dapat mengubah nilai yang disimpan di alamat itu tetapi tidak dapat mengubah alamat yang dituju constjuga.

Definisi yang constAnda sebutkan akan berlaku saat constmenunjuk ke alamat yang memiliki nilai primitif. Ini karena Anda tidak dapat menetapkan nilai ke ini consttanpa mengubah alamatnya (karena begitulah cara kerja menetapkan nilai primitif) dan mengubah alamat a consttidak diperbolehkan.

Dimana seolah-olah constmenunjuk ke nilai non-primitif, dimungkinkan untuk mengedit nilai alamat.

Zyxmn
sumber
2

Baca artikel ini sambil mencari alasan mengapa saya bisa memperbarui Object bahkan setelah mendefinisikannya sebagai const. Jadi intinya di sini adalah bahwa bukan Objek secara langsung tetapi atribut yang dikandungnya yang dapat diperbarui.

Misalnya, Objek saya terlihat seperti:

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

Jawaban di atas dengan benar menunjukkan bahwa itu adalah Object yang const dan bukan atributnya. Karenanya, saya akan dapat memperbarui id atau nama dengan melakukan:

number.name = 'John';

Tapi, saya tidak akan bisa memperbarui Object itu sendiri seperti:

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

TypeError: Assignment to constant variable.
Atul O Holic
sumber
1
contoh Anda adalah deskripsi yang praktis dan benar
Ebrahim
0

Karena dalam const Anda dapat mengubah nilai suatu objek, sehingga objek tersebut tidak benar-benar menyimpan data tugas, tetapi justru menunjuk ke sana. jadi ada perbedaan antara primitif dan objek di Javascript.


sumber