ฉันควรใช้ 'let' vs 'const' ใน ES6 มากแค่ไหน


214

ฉันเขียนรหัส ES6 จำนวนมากสำหรับ io.js เมื่อเร็ว ๆ นี้ มีโค้ดไม่มากนักในการเรียนรู้ดังนั้นฉันรู้สึกเหมือนว่าฉันกำหนดอนุสัญญาของตัวเองเมื่อฉันไป

คำถามของฉันเป็นเรื่องเกี่ยวกับเวลาที่จะใช้VSconstlet

constฉันได้รับการใช้กฎนี้ถ้าเป็นไปได้ใช้ ใช้เฉพาะletเมื่อคุณรู้ว่าค่าจำเป็นต้องเปลี่ยนแปลง (คุณสามารถย้อนกลับและเปลี่ยน a เป็นconsta letได้ในภายหลังหากคุณต้องการเปลี่ยนค่าของมันในภายหลัง)

เหตุผลหลักสำหรับกฎนี้คือมันง่ายที่จะใช้อย่างสม่ำเสมอ ไม่มีพื้นที่สีเทา

สิ่งที่เป็นเมื่อฉันใช้กฎนี้ในทางปฏิบัติ 95% constของการประกาศของฉัน และนี่ดูแปลกสำหรับฉัน ฉันแค่ใช้letสำหรับสิ่งต่าง ๆiในforวงหรือบางครั้งสำหรับสิ่งต่าง ๆ เช่นผลรวมสะสมฟีโบนักชี (ซึ่งไม่ได้เกิดขึ้นมากในชีวิตจริง) ฉันรู้สึกประหลาดใจกับสิ่งนี้ - ปรากฎ 95% ของ 'ตัวแปร' ในรหัส ES5 ของฉันจนถึงปัจจุบันเป็นค่าที่ไม่เปลี่ยนแปลง แต่การเห็นconstรหัสของฉันทั่วรู้สึกผิดอย่างใด

ดังนั้นคำถามของฉันคือ: ตกลงไหมที่จะใช้constสิ่งนี้มาก? ฉันควรจะทำสิ่งต่าง ๆ เช่นconst foo = function () {...};?

หรือฉันควรสำรองconstไว้สำหรับสถานการณ์แบบนั้นซึ่งคุณกำลังเขียนโค้ดที่ด้านบนของโมดูลอย่างหนัก - แบบที่คุณทำในรูปแบบเต็มแคปเช่นconst MARGIN_WIDTH = 410;?


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

15
function foo() {...}ดีกว่า<anything> foo = function() {...}
OrangeDog

12
@ OrangeDog ฉันอยากจะเห็นคำอธิบายของคุณสำหรับเรื่องนี้เนื่องจากฉันได้ข้อสรุปที่ตรงกันข้าม มีข้อแม้ที่function foo() {...}สามารถทำให้เกิดความสับสนเล็กน้อยเมื่อทำการดีบักเนื่องจากการยก นอกจากนี้การมีอยู่ของมันหมายความว่าเรามีสองโครงสร้างที่ทำสิ่งเดียวกัน แต่หนึ่งในนั้นทำงานในบริบทที่เฉพาะเจาะจงเท่านั้น (คุณสามารถใช้ฟังก์ชั่นการแสดงออกได้ทุกการแสดงออกสามารถอยู่ แต่คุณเท่านั้นที่สามารถใช้ฟังก์ชั่นการประกาศในระดับคำสั่ง.) functionหากคุณโปรดปรานกะทัดรัดปัญหาก็อาจเป็นไปได้ว่าไวยากรณ์นิพจน์ฟังก์ชั่นใช้ทั้งคำ
คม

11
การติดตามสแต็กมีชื่อของฟังก์ชันแทนที่จะเป็นอานนท์ การยกเป็นสิ่งที่ดีและให้คุณกำหนดฟังก์ชั่นตามลำดับอย่างเป็นธรรมชาติโดยไม่ต้องกังวลว่าจะไม่ได้กำหนด foo
OrangeDog

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

คำตอบ:


183

คำตอบของฉันที่นี่ไม่ใช่เฉพาะจาวาสคริปต์

เป็นกฎง่ายๆในภาษาใด ๆ ที่ให้ฉันทำในวิธีกึ่งง่ายฉันจะบอกว่าใช้ const / final / readonly / สิ่งที่มันถูกเรียกในภาษาของคุณทุกครั้งที่เป็นไปได้ เหตุผลนั้นง่ายมากมันง่ายกว่าที่จะให้เหตุผลเกี่ยวกับโค้ดเมื่อมันตายไปอย่างชัดเจนว่าอะไรที่สามารถเปลี่ยนแปลงได้และอะไรที่ไม่สามารถเปลี่ยนแปลงได้ และนอกจากนี้ในหลายภาษาคุณสามารถรับการสนับสนุนเครื่องมือที่บอกคุณว่าคุณกำลังทำอะไรผิดพลาดเมื่อคุณกำหนดตัวแปรที่คุณประกาศเป็น const โดยไม่ตั้งใจ

การย้อนกลับและเปลี่ยน const ให้เป็นปล่อยนั้นง่ายมาก และการควบคุมค่าเริ่มต้นจะทำให้คุณคิดสองครั้งก่อน และนี่เป็นสิ่งที่ดีในหลาย ๆ กรณี

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

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

และทุกอย่างเริ่มต้นด้วยการเป็นนักเสรีนิยมกับ const! ;) มันเป็นเพียงตัวละครอีกสองตัวที่จะเขียนเปรียบเทียบกับการปล่อยให้ดังนั้นไปข้างหน้าและconstทุกสิ่ง!


45
constเป็นตัวละครสองตัวมากกว่าlet...
OrangeDog

72
แต่ตัวละครน้อยกว่าที่เปลี่ยนไม่ได้ 5 ตัว
Cerad

7
ดูเหมือนว่าจะเป็นการใช้งานvalใน Scala (ซึ่งประกาศตัวแปรว่าไม่เปลี่ยนรูป) และใช้เฉพาะvarเมื่อ (เราไม่สามารถเปลี่ยนแปลงได้) เมื่อเราไม่สามารถใช้งานvalได้ กล่าวอีกนัยหนึ่งเราประกาศว่าตัวแปรไม่เปลี่ยนรูปโดยค่าเริ่มต้นและแนะนำความไม่แน่นอนเมื่อเราต้องการมันอย่างแน่นอน (ซึ่งอาจเป็นเพราะแนวทางที่ไม่แน่นอนนั้นสะอาดกว่า)
Kat

7
ฉันเห็นด้วยกับคำตอบนี้ แต่โปรดจำไว้ว่าสิ่งที่ไม่ชัดเจนดังนั้นเมื่อทำงานกับสิ่งต่าง ๆ เช่นวัตถุธรรมดาหรืออาร์เรย์เป็นคุณสมบัติของพวกเขาสามารถเปลี่ยนแปลงแม้ว่าพวกเขาจะถูกกำหนดด้วย 'const' ฉันคิดว่า 'const' ทำงานเหมือน object.freeze แต่นั่นไม่ใช่กรณี
backdesk

2
@Cerad คุณหมายถึง“ 4 ตัวอักษรน้อยกว่า” หรือว่าฉันคิดถึงเรื่องตลกบ้างที่นี่?
Mathias Bynens

57

ระวังเนื่องจากconstคีย์วัตถุนั้นไม่แน่นอน

จากที่นี่: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

ปุ่มวัตถุไม่ได้รับการป้องกัน

ลองพิจารณาตัวอย่างนี้:

const colors = {red: "#f00"}; 
console.log(colors); // { "red": "#f00" }

colors.red = "#00f";
colors.green = "#0f0";
console.log(colors); // { "red": "#00f", "green": "#0f0" }

สิ่งเดียวกันสำหรับอาร์เรย์:

const numbers = [1, 2, 3];
console.log(numbers); // [ 1, 2, 3 ]

numbers.push(4);
console.log(numbers); // [ 1, 2, 3, 4 ]

ฉันยังไม่ได้ตัดสินใจเองทั้งหมด แต่ฉันกำลังพิจารณาใช้constสำหรับอเรย์ที่ไม่ใช่อาเรย์ / ออบเจ็กต์ทั้งหมดและใช้letสำหรับออบเจ็กต์ / อาร์เรย์


34
จริง แต่คาดว่า IMO - constสิ่งที่เป็นค่าคงที่เป็นวัตถุอ้างอิงที่กำหนดให้กับคุณ colors = numbersจะไม่ทำงานอย่างที่คาดไว้ หากคุณต้องการปกป้องคุณสมบัติวัตถุของคุณคุณสามารถใช้Object.freeze() developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Josef Engelfrost

16
หลอกตา มันไม่เปลี่ยนแปลง แต่คุณสมบัติของวัตถุที่แท้จริงไม่ได้
Gaston Sanchez

1
+1 ใช่ข้อมูลอ้างอิงได้รับการคุ้มครอง แต่ในแง่ของคำถามมันค่อนข้างโง่ที่จะใช้ในกรณีเช่นconst moment = require('moment')เว้นแต่คุณเป็นคนประเภทที่กังวลว่าจะมีคนพยายามทำในmoment = dead.fish(() => pizza)ภายหลัง
MaxWell

5
บางทีอาจจะมีเหตุผลอื่น ๆ moment = Date.now()อีกมากมายที่จะต้องกังวลเกี่ยวกับ แต่ในกรณีใด ๆ หากรหัสถือว่าค่าคงที่ฉันเห็นอะไรผิดปกติกับการบังคับใช้มันเป็นไปได้
James M.

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

25

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

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

const immutableOject = Object.freeze({immutableProperty: 'foo'});

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


14
สังเกตว่าObject.freezeตื้น
Mathias Bynens

@MathiasBynens ฉันเจอความคิดเห็นนี้และฉันอยากรู้ว่าคุณหมายถึงอะไร คุณช่วยอธิบายรายละเอียดได้ไหม?
Cole Roberts

@ColeRoberts แนวคิดของการเปลี่ยนแปลงไม่ได้ตื้นคือเมื่อการอ้างอิงวัตถุตัวเองไม่เปลี่ยนรูป แต่คุณสมบัติยังคงสามารถเปลี่ยนแปลงได้ คีย์เวิร์ด const สร้างขึ้นเพื่อการเปลี่ยนรูปแบบตื้นเท่านั้นดังนั้นคุณต้องใช้ Object.freeze หากคุณสมบัติทั้งหมดควรเปลี่ยนรูปแบบไม่ได้
clean_coding

3
@ColeRoberts หมายความว่าค่าของวัตถุภายในวัตถุที่ถูกตรึง (เช่นวัตถุซ้อนกัน) ยังคงสามารถกลายพันธุ์ได้ ดูmathiasbynens.be/notes/es6-const#immutable-valuesสำหรับข้อมูลเพิ่มเติม
Mathias Bynens

19

ในES6constของฉันไม่ได้เกี่ยวกับการโพสต์เปลี่ยนแปลงไม่ได้ฉันอธิบายความconstหมายตามที่ระบุ

ตามข้อเท็จจริงวัตถุประสงค์เหล่านี้นี่คือความชอบส่วนตัวของฉัน:

[…] เหมาะสมที่จะใช้letและconstดังต่อไปนี้ในรหัส ES6 ของคุณ:

  • ใช้เป็นconstค่าเริ่มต้น
  • ใช้เฉพาะในletกรณีที่จำเป็นต้องทำการ rebinding (เช่นการกำหนดรูปแบบใด ๆ )
  • ( varไม่ควรใช้ใน ES6)

ส่วนตัวมันอาจเป็นความจริงที่ว่าสิ่งนี้ตรงกับเจตนาของสเป็คมากที่สุด

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

การใช้constเฉพาะค่าคงที่ก็เหมือนกับการใช้องค์ประกอบHTML<aside>สำหรับเนื้อหาแถบด้านข้างเท่านั้น


2
ทำไมคุณถึงตั้งชื่อบางอย่างconstถ้ามันไม่คงที่?
nu everest

3
@nueverest เพราะนั่นไม่ใช่สิ่งที่constมีไว้เพื่อ คุณได้อ่านข้างต้นหรือไม่
Mathias Bynens

2
@MathiasBynens ผมคิดว่า (เฉพาะ?) ปัญหาเกี่ยวกับการก็คือว่ามันเรียกว่าconst constมันเป็นชื่อโง่ (ใน javascript) ที่สร้างความสับสนให้กับนักพัฒนา (ทั้งหมด?) ในตอนแรก IMO ดีกว่าจะได้รับถ้าconsthad've ถูกเรียกว่าlet(โดยเฉพาะอย่างยิ่งเพราะletจะสั้น แต่constเป็นอย่างมากมายร่วมกันมากขึ้น) และletเรียกอย่างอื่น
MrN00b

@MathiasBynens ฉันได้รับมัน แต่ทำไมเรียกว่าอย่างนั้น? มันกำลังสร้างความสับสนอย่างมากเมื่อหน้านี้แสดงให้เห็น
jtr13

4

แนวทางส่วนบุคคลของฉันความคิดในการช่วยให้สามารถอ่านและเข้าใจโค้ดได้:


letใช้สำหรับตัวแปรอายุสั้นซึ่งกำหนดที่บรรทัดเดียวและไม่เปลี่ยนแปลงหลังจากนั้น โดยทั่วไปตัวแปรเหล่านั้นที่มีเพียงเพื่อลดจำนวนการพิมพ์ ตัวอย่างเช่น:

for (let key in something) {
  /* we could use `something[key]` for this entire block,
     but it would be too much letters and not good for the
     fingers or the eyes, so we use a radically temporary variable
  */
  let value = something[key]
  ...
}

constสำหรับชื่อทั้งหมดที่ทราบว่าเป็นค่าคงที่ตลอดทั้งโมดูล ไม่รวมค่าคงที่แบบโลคอล valueในตัวอย่างข้างต้นตัวอย่างเช่นเป็นค่าคงที่อยู่ในขอบเขตและอาจจะมีการประกาศด้วยconstแต่เนื่องจากมีการทำซ้ำจำนวนมากและแต่ละคนมีค่าเดียวกับชื่อ "ค่า" ที่อาจหลอกให้ผู้อ่านในความคิดvalueอยู่เสมอ เหมือน. โมดูลและฟังก์ชั่นเป็นตัวอย่างที่ดีที่สุดของconstตัวแปร:

const PouchDB = require('pouchdb')
const instantiateDB = function () {}
const codes = {
  23: 'atc',
  43: 'qwx',
  77: 'oxi'
}

varสำหรับทุกสิ่งที่อาจจะเปลี่ยนแปลงหรือไม่ก็ตาม รายชื่อที่อาจสร้างความสับสนให้คนที่อ่านรหัสที่แม้ว่าพวกเขาจะคงที่ในระดับท้องถิ่นและไม่เหมาะสำหรับการlet(กล่าวคือพวกเขาจะไม่แล้วเสร็จในประกาศโดยตรงง่าย) varใช้สำหรับการประกาศด้วย ตัวอย่างเช่น:

var output = '\n'
lines.forEach(line => {
  output += '  '
  output += line.trim()
  output += '\n'
})
output += '\n---'

for (let parent in parents) {
  var definitions = {}
  definitions.name = getName(parent)
  definitions.config = {}
  definitions.parent = parent
}

ความเห็นต่อไปและในอนาคตเป็นไปได้อัปเดตที่นี่


10
ข้อมูลโค้ดที่สองนั้นดูเหมือนปืน
Julian

1

JavaScript เป็นบิตพิเศษในตัวแปรที่สามารถใช้งานได้ แต่ควรพิจารณาใน C #, Java หรือภาษาสไตล์ C อื่นที่คล้ายคลึงกัน:

const public void DoSomething()

constเป็นเลขคี่และนั่นเป็นเพราะการประกาศวิธีการในภาษาเหล่านี้ไม่สามารถเปลี่ยนเมื่อพวกเขากำลังรวบรวมเป็นอย่างอื่นว่าเป็นสิ่งที่พวกเขาทำไม่ว่าสิ่งที่ (ไม่สนใจบาง hacks น่ากลัวที่อาจมีอยู่)

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

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