อีนัมในจาวาสคริปต์กับ ES6
ฉันกำลังสร้างโปรเจกต์ Java เก่าใหม่ใน Javascript และตระหนักว่าไม่มีวิธีที่ดีในการทำ enums ใน JS
สิ่งที่ดีที่สุดที่ฉันสามารถคิดได้คือ:
const Colors = {
RED: Symbol("red"),
BLUE: Symbol("blue"),
GREEN: Symbol("green")
};
Object.freeze(Colors);
const ทำให้ Colors ไม่สามารถถูกกำหนดค่าใหม่ได้ และการทำให้คงที่ช่วยป้องกันการเปลี่ยนแปลงคีย์และค่าของมัน ผมกำลังใช้ Symbols เพื่อให้ Colors.RED ไม่เท่ากับ 0 หรือสิ่งอื่นใดนอกจากตัวมันเอง
มีปัญหากับสูตรนี้หรือไม่? มีวิธีที่ดีกว่านี้หรือเปล่า?
(ฉันรู้ว่าคำถามนี้ซ้ำเล็กน้อย แต่คำถาม/คำตอบก่อนหน้านี้ค่อนข้างเก่า และ ES6 มอบความสามารถใหม่ๆ ให้กับเรา)
แก้ไข:
อีกวิธีแก้ปัญหา ซึ่งเกี่ยวข้องกับปัญหาการทำลำดับ แต่ผมเชื่อว่ายังคงมีปัญหาเรื่องขอบเขต:
const enumValue = (name) => Object.freeze({toString: () => name});
const Colors = Object.freeze({
RED: enumValue("Colors.RED"),
BLUE: enumValue("Colors.BLUE"),
GREEN: enumValue("Colors.GREEN")
});
โดยการใช้การอ้างอิงวัตถุเป็นค่า คุณจะได้รับการหลีกเลี่ยงความขัดแย้งเหมือนกับสัญลักษณ์
คำตอบ #1
มีปัญหากับการจัดสูตรนี้ไหม?
ฉันไม่เห็นเลย
มีวิธีที่ดีกว่านี้ไหม?
ฉันจะรวมสองประโยคให้เป็นประโยคเดียว:
const Colors = Object.freeze({
RED: Symbol("red"),
BLUE: Symbol("blue"),
GREEN: Symbol("green")
});
ถ้าคุณไม่ชอบโค้ดซ้ำๆ เช่น การเรียกใช้ Symbol ซ้ำๆ คุณก็สามารถสร้างฟังก์ชันช่วย makeEnum ที่สร้างสิ่งเดียวกันจากรายการชื่อได้เช่นกัน
คำตอบ #2
แม้ว่าการใช้ Symbol เป็นค่าของ enum จะทำงานได้ดีสำหรับกรณีการใช้งานง่าย ๆ แต่การให้คุณสมบัติต่าง ๆ กับ enum ก็สามารถเป็นประโยชน์ได้ ซึ่งสามารถทำได้โดยการใช้ Object เป็นค่าของ enum ที่มีคุณสมบัติเหล่านั้น
ตัวอย่างเช่น เราสามารถให้แต่ละ Colors มีชื่อและค่าเฮ็กซ์ได้:
/**
* Enum for common colors.
* @readonly
* @enum {{name: string, hex: string}}
*/
const Colors = Object.freeze({
RED: { name: "red", hex: "#f00" },
BLUE: { name: "blue", hex: "#00f" },
GREEN: { name: "green", hex: "#0f0" }
});
การรวมคุณสมบัติใน enum จะช่วยหลีกเลี่ยงการต้องเขียนคำสั่ง switch (และอาจลืมกรณีใหม่ๆ ในคำสั่ง switch เมื่อมีการขยาย enum) ตัวอย่างนี้ยังแสดงคุณสมบัติและประเภทของ enum ที่ถูกจัดทำเอกสารด้วยคำอธิบายประกอบ JSDoc ของ enum ด้วย
ความเท่าเทียมทำงานตามที่คาดไว้โดย Colors.RED === Colors.RED เป็น true และ Colors.RED === Colors.BLUE เป็น false.
คำตอบ #3
อัปเดต 11.05.2020:
แก้ไขเพื่อรวมฟิลด์และเมธอดสแตติกเพื่อให้ใกล้เคียงกับพฤติกรรมของ enum 'จริง'
ถ้าคุณวางแผนที่จะอัปเดต ผมแนะนำให้ลองใช้สิ่งที่ผมเรียกว่า "Enum Class" (เว้นแต่จะมีข้อจำกัดของเบราว์เซอร์หรือสภาพแวดล้อมรันไทม์ที่คุณไม่สามารถยอมรับได้) มันเป็นคลาสที่ ง่ายมาก และสะอาดตาโดยใช้ฟิลด์แบบส่วนตัวและตัวเข้าถึงที่จำกัดเพื่อจำลองพฤติกรรมของ enum นี่คือสิ่งที่ผมบางครั้งทำใน C# เมื่อผมต้องการสร้างฟังก์ชันเพิ่มเติมให้กับ enum
ฉันตระหนักว่าฟิลด์คลาสส่วนตัวยังอยู่ในช่วงทดลองในตอนนี้ แต่ดูเหมือนว่าจะใช้ได้สำหรับการสร้างคลาสที่มีฟิลด์/คุณสมบัติที่ไม่สามารถเปลี่ยนแปลงได้ การสนับสนุนเบราว์เซรก็พอใช้ได้ เบราว์เซอร์ "หลัก" เพียงตัวเดียวที่ยังไม่รองรับคือ Firefox (ซึ่งฉันมั่นใจว่าพวกเขาจะรองรับในเร็วๆ นี้) และ IE (ไม่สำคัญ)
ข้อจำกัดความรับผิดชอบ:
ผมไม่ใช่นักพัฒนา ผมเพียงแค่รวบรวมสิ่งนี้ขึ้นมาเพื่อแก้ไขข้อจำกัดของการไม่มี enums ใน JS เมื่อผมทำงานในโครงการส่วนตัว
ตัวอย่างชั้นเรียน :
class Colors {
// Private Fields
static #_RED = 0;
static #_GREEN = 1;
static #_BLUE = 2;
// Accessors for "get" functions only (no "set" functions)
static get RED() { return this.#_RED; }
static get GREEN() { return this.#_GREEN; }
static get BLUE() { return this.#_BLUE; }
}
ตอนนี้คุณควรจะสามารถเรียกใช้เอนัมของคุณโดยตรงได้แล้ว
Colors.RED; // 0
Colors.GREEN; // 1
Colors.BLUE; // 2
การรวมกันของการใช้ฟิลด์ส่วนตัวและตัวเข้าถึงที่จำกัดหมายความว่าค่าของ enum ที่มีอยู่ได้รับการป้องกันอย่างดี (พวกมันโดยหลักแล้วเป็นค่าคงที่ในตอนนี้)
Colors.RED = 10 // Colors.RED is still 0
Colors._RED = 10 // Colors.RED is still 0
Colors.#_RED = 10 // Colors.RED is still 0
คำตอบ #4
ดังที่กล่าวไว้ด้านบน คุณยังสามารถเขียนฟังก์ชันช่วยเหลือ makeEnum() ได้อีกด้วย:
function makeEnum(arr){
let obj = Object.create(null);
for (let val of arr){
obj[val] = Symbol(val);
}
return Object.freeze(obj);
}
ใช้มันแบบนี้:
const Colors = makeEnum(["red","green","blue"]);
let startColor = Colors.red;
console.log(startColor); // Symbol(red)
if(startColor == Colors.red){
console.log("Do red things");
}else{
console.log("Do non-red things");
}
คำตอบ #5
นี่คือวิธีการส่วนตัวของฉัน
class ColorType {
static get RED () {
return "red";
}
static get GREEN () {
return "green";
}
static get BLUE () {
return "blue";
}
}
// Use case.
const color = Color.create(ColorType.RED);
