เหตุใดฉันจึงสามารถเปลี่ยนค่าของค่าคงที่ในจาวาสคริปต์


104

ฉันรู้ว่า 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;

ฉันเป็นบั๊กหรือฉันพลาดอะไรไป? ฉันลองใช้ใน chrome และ FF29 ล่าสุด


1
คุณสามารถสร้างคลาสประกาศตัวแปรและกำหนดค่าภายในคลาสได้ไหม จากนั้นสร้าง GETTER สำหรับตัวแปรนั้น และอย่าใช้ setter ควรใช้ค่าคงที่ ...
แอนดรูว์

8
@ แอนดรูขอบคุณ แต่ฉันไม่ได้ถามว่าฉันจะทำสิ่งนี้ได้อย่างไร ฉันอยากรู้ว่าทำไมคำหลัก const ถึงทำงานในลักษณะนี้
Salvador Dali

คำตอบ:


177

เอกสารระบุ:

... ค่าคงที่ไม่สามารถเปลี่ยนแปลงผ่านการกำหนดซ้ำ
... ค่าคงที่ไม่สามารถประกาศซ้ำได้

เมื่อคุณเพิ่มลงในอาร์เรย์หรือออบเจ็กต์ที่คุณไม่ได้กำหนดใหม่หรือประกาศค่าคงที่อีกครั้งแสดงว่ามีการประกาศและกำหนดแล้วคุณเพียงแค่เพิ่มลงใน "รายการ" ที่ค่าคงที่ชี้ไป

ดังนั้นจึงใช้งานได้ดี:

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
คุณหมายความว่านี่ไม่ใช่ข้อผิดพลาด แต่ควรใช้วิธีนี้หรือไม่ เพราะฉันคิดว่าความคิดของค่าคงที่คือมันไม่สามารถเปลี่ยนแปลงได้ โดยทั่วไปโปรแกรมเมอร์มีความเชื่อมั่นว่าไม่ว่าอะไรจะเกิดขึ้นไม่มีอะไรสามารถเปลี่ยนแปลงค่าภายในค่าคงที่ของฉันได้
Salvador Dali

2
ฉันคิดว่ามันไม่ใช่เรื่องง่ายในกรณีนี้ค่าของค่าคงที่คืออาร์เรย์ขององค์ประกอบเฉพาะ เปลี่ยนอะไรหมายความว่าคุณเปลี่ยนค่า
veritas

7
ใช่มันควรจะทำงานในลักษณะนี้คุณไม่ได้กำหนดค่าคงที่ซ้ำมันยังคงเป็นข้อมูลอ้างอิงเหมือนเดิมคุณเพียงแค่เพิ่มการอ้างอิงคงที่ลงในอาร์เรย์เท่านั้นอาร์เรย์และวัตถุก็เหมือนกับ "รายการ" การแก้ไขก็ทำได้ ไม่เปลี่ยนการอ้างอิงหรือประกาศค่าคงที่อีกครั้ง
adeneo

28
@SalvadorDali: ค่าคงที่และอ่านอย่างเดียวเป็นสองสิ่งที่แตกต่างกัน ตัวแปรของคุณคงที่แต่อาร์เรย์ที่ชี้ไปไม่ใช่แบบอ่านอย่างเดียว
Matt Burland

46

สิ่งนี้เกิดขึ้นเนื่องจากค่าคงที่ของคุณกำลังจัดเก็บข้อมูลอ้างอิงไปยังอาร์เรย์ เมื่อคุณรวมบางอย่างเข้ากับอาร์เรย์ของคุณคุณจะไม่ได้แก้ไขค่าคงที่ของคุณ แต่อาร์เรย์นั้นชี้ไป สิ่งเดียวกันนี้จะเกิดขึ้นถ้าคุณกำหนดให้วัตถุเป็นค่าคงที่และพยายามแก้ไขคุณสมบัติใด ๆ ของมัน

หากคุณต้องการตรึงอาร์เรย์หรือวัตถุเพื่อไม่ให้แก้ไขได้คุณสามารถใช้Object.freezeวิธีนี้ซึ่งเป็นส่วนหนึ่งของ ECMAScript 5 อยู่แล้ว

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

1
ด้วยตรรกะเดียวกันนั้นค่าคงที่ที่fiveกำหนดเป็น 5 ไม่ได้มีค่าเป็น 5 มันเป็นเพียงการอ้างอิงถึงจำนวน 5 ดังนั้นถ้าfive++ฉันไม่เปลี่ยนค่าคงที่ก็แค่จำนวนที่มันชี้ไป
Anthony

3
@ แอนโธนีสิ่งอ้างอิงใช้ได้กับอาร์เรย์และวัตถุเท่านั้นไม่ใช่ค่าดั้งเดิม
Guilherme Sehn

1
@Anthony ในตัวอย่างของคุณคุณกำลังเปลี่ยนตัวเลขที่ตัวแปรfiveชี้ไป (ตัวแปรที่fiveใช้เป็นป้ายกำกับสำหรับหมายเลข 5 ตอนนี้มันชี้ไปที่ตัวเลขอื่น: 6) ในตัวอย่างของคำถาม (และคำตอบนี้) xชี้ไปที่รายการเดียวกันเสมอ ถ้าxเป็น const คุณไม่สามารถทำให้ชี้ไปที่รายการอื่นได้ ข้อแตกต่างเพียงอย่างเดียวคือรายการเดียวกันสามารถขยายหรือลดขนาดได้ นี่เป็นสิ่งที่เป็นไปได้สำหรับอาร์เรย์และวัตถุเท่านั้นไม่ใช่สำหรับวัตถุดั้งเดิม
ShreevatsaR

9

นี่เป็นพฤติกรรมที่สอดคล้องกับทุกภาษาโปรแกรมที่ฉันคิดได้

พิจารณา C - อาร์เรย์เป็นเพียงตัวชี้ที่ได้รับการยกย่อง อาร์เรย์คงที่หมายความว่าค่าของตัวชี้จะไม่เปลี่ยนแปลง แต่ในความเป็นจริงข้อมูลที่อยู่ในที่อยู่นั้นเป็นอิสระ

ในจาวาสคริปต์คุณได้รับอนุญาตให้เรียกใช้เมธอดของวัตถุคงที่ (แน่นอน - มิฉะนั้นวัตถุคงที่จะไม่ตอบสนองวัตถุประสงค์มากนัก!) วิธีการเหล่านี้อาจมีผลข้างเคียงจากการแก้ไขวัตถุ เนื่องจากอาร์เรย์ในจาวาสคริปต์เป็นอ็อบเจ็กต์ลักษณะการทำงานนี้จึงใช้ได้กับอาร์เรย์เช่นกัน

สิ่งที่คุณมั่นใจได้ก็คือค่าคงที่จะชี้ไปที่วัตถุเดียวกันเสมอ คุณสมบัติของวัตถุนั้นมีอิสระที่จะเปลี่ยนแปลง


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 https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0

โดยทั่วไปจะเดือดลงไปที่constชี้ไปยังที่อยู่เดียวกันในหน่วยความจำเสมอ คุณสามารถเปลี่ยนค่าที่เก็บไว้ในที่อยู่นั้นได้ แต่ไม่สามารถเปลี่ยนที่อยู่ของconstชี้ได้เช่นกัน

คำจำกัดความของconstคุณที่กล่าวถึงจะเป็นจริงเมื่อconstชี้ไปยังที่อยู่ที่มีค่าดั้งเดิม เนื่องจากคุณไม่สามารถกำหนดค่านี้ได้constโดยไม่ต้องเปลี่ยนที่อยู่ (เพราะนี่คือวิธีการกำหนดค่าดั้งเดิมทำงาน) และเปลี่ยนที่อยู่ของconstไม่อนุญาตให้

ในกรณีที่หากค่าconstนี้ชี้ไปที่ค่าที่ไม่ใช่พื้นฐานคุณสามารถแก้ไขค่าของแอดเดรสได้


2

อ่านบทความนี้ในขณะที่ค้นหาว่าเหตุใดฉันจึงสามารถอัปเดต Object ได้แม้ว่าจะกำหนดเป็น const . ดังนั้นประเด็นคือมันไม่ใช่ Object โดยตรง แต่เป็นแอตทริบิวต์ที่มีซึ่งสามารถอัปเดตได้

ตัวอย่างเช่นวัตถุของฉันดูเหมือนว่า:

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

คำตอบข้างต้นชี้ให้เห็นอย่างถูกต้องว่าเป็น Object ที่เป็น const ไม่ใช่แอตทริบิวต์ ดังนั้นฉันจะสามารถอัปเดตรหัสหรือชื่อได้โดยทำ:

number.name = 'John';

แต่ฉันจะไม่สามารถอัปเดต Object ได้เช่น:

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

TypeError: Assignment to constant variable.

1
ตัวอย่างของคุณเป็นคำอธิบายที่ใช้ได้จริงและถูกต้อง
Ebrahim

0

เนื่องจากใน const คุณสามารถเปลี่ยนค่าของอ็อบเจ็กต์ได้ดังนั้นอ็อบเจ็กต์จึงไม่เก็บข้อมูลการกำหนด แต่จะชี้ไปที่อ็อบเจ็กต์แทน ดังนั้นจึงมีความแตกต่างระหว่างวัตถุดั้งเดิมและวัตถุใน Javascript

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.