Getter and Setter Methods ใน JavaScript: ควบคุมการเข้าถึง Properties
ในบทเรียนที่แล้ว เราได้เรียนรู้เกี่ยวกับ static methods และ properties ซึ่งเป็นคุณสมบัติที่ผูกติดอยู่กับ class โดยตรง ในบทนี้ เราจะมาสำรวจ getter และ setter methods ซึ่งเป็นกลไกสำคัญในการควบคุมการเข้าถึงและแก้ไข properties ของ object ใน JavaScript
ทำไมต้องมี Getter และ Setter?
โดยปกติแล้ว การเข้าถึง properties ของ object ใน JavaScript นั้นทำได้โดยตรงผ่าน dot notation (object.property) หรือ bracket notation (object['property']) ซึ่งสะดวกและรวดเร็ว แต่ในบางสถานการณ์ เราอาจต้องการควบคุมการเข้าถึง properties เหล่านั้นอย่างละเอียดมากขึ้น เพื่อ:
- Validation: ตรวจสอบความถูกต้องของข้อมูลก่อนที่จะถูกกำหนดให้กับ property
- Transformation: แปลงรูปแบบข้อมูลก่อนที่จะถูกส่งคืนหรือจัดเก็บ
- Encapsulation: ซ่อนรายละเอียดการทำงานภายในของ object และเปิดเผยเฉพาะ interface ที่จำเป็น
- Read-only properties: สร้าง properties ที่สามารถอ่านได้อย่างเดียว (ไม่สามารถแก้ไขได้จากภายนอก)
- Computed properties: สร้าง properties ที่คำนวณค่าจาก properties อื่นๆ
Getter และ setter methods ช่วยให้เราสามารถบรรลุเป้าหมายเหล่านี้ได้
Getter Methods: การอ่าน Property อย่างมีเงื่อนไข
Getter method คือ function ที่ถูกเรียกเมื่อมีการเข้าถึง property ของ object โดยใช้ keyword get ตามด้วยชื่อ property ที่ต้องการควบคุม
class Circle {
constructor(radius) {
this._radius = radius; // convention: use _ to indicate private property
}
get radius() {
return this._radius;
}
get area() {
return Math.PI * this._radius * this._radius; // Computed property
}
}
const myCircle = new Circle(5);
console.log(myCircle.radius); // Output: 5 (เรียกใช้ getter radius())
console.log(myCircle.area); // Output: 78.53981633974483 (เรียกใช้ getter area())
ในตัวอย่างนี้:
_radiusเป็น property ที่เราต้องการควบคุมการเข้าถึง (ใช้ underscore_เป็น convention เพื่อบอกว่า property นี้ควรถูกมองว่าเป็น private)get radius()คือ getter method สำหรับ propertyradiusเมื่อเราเรียกmyCircle.radiusgetter method นี้จะถูกเรียกใช้และคืนค่าthis._radiusget area()คือ getter method สำหรับ propertyareaเมื่อเราเรียกmyCircle.areagetter method นี้จะคำนวณและคืนค่าพื้นที่ของวงกลม
ข้อดีของ getter:
- Clean code: ทำให้โค้ดอ่านง่ายขึ้น เพราะการเข้าถึง property ยังคงใช้ syntax เดิม (
myCircle.radius) แต่เบื้องหลังมีการทำงานที่ซับซ้อนกว่า - Encapsulation: ซ่อนรายละเอียดการจัดเก็บข้อมูลจริง (
_radius) จากภายนอก - Computed properties: สร้าง properties ที่มีค่าเปลี่ยนแปลงตาม properties อื่นๆ
Setter Methods: การกำหนดค่า Property อย่างมีเงื่อนไข
Setter method คือ function ที่ถูกเรียกเมื่อมีการกำหนดค่าให้กับ property ของ object โดยใช้ keyword set ตามด้วยชื่อ property ที่ต้องการควบคุม
class Temperature {
constructor(celsius) {
this._celsius = celsius;
}
get celsius() {
return this._celsius;
}
set celsius(value) {
if (value < -273.15) {
throw new Error("Temperature cannot be below absolute zero.");
}
this._celsius = value;
}
get fahrenheit() {
return this._celsius * 9/5 + 32;
}
set fahrenheit(value) {
this.celsius = (value - 32) * 5/9; // ใช้ setter celsius เพื่อ validation
}
}
const myTemperature = new Temperature(25);
console.log(myTemperature.celsius); // Output: 25
console.log(myTemperature.fahrenheit); // Output: 77
myTemperature.celsius = 30;
console.log(myTemperature.celsius); // Output: 30
myTemperature.fahrenheit = 86;
console.log(myTemperature.celsius); // Output: 30
try {
myTemperature.celsius = -300;
} catch (error) {
console.error(error.message); // Output: Temperature cannot be below absolute zero.
}
ในตัวอย่างนี้:
set celsius(value)คือ setter method สำหรับ propertycelsiusเมื่อเรากำหนดค่าให้กับmyTemperature.celsiussetter method นี้จะถูกเรียกใช้- ภายใน setter method เราทำการ validate ว่าค่าที่กำหนดไม่ต่ำกว่า absolute zero ถ้าต่ำกว่าจะ throw error
set fahrenheit(value)แสดงให้เห็นว่าเราสามารถใช้ setter อื่นๆ ภายใน setter เดียวกันได้ เพื่อให้แน่ใจว่าการ validation ยังคงถูกต้อง
ข้อดีของ setter:
- Data Validation: ตรวจสอบความถูกต้องของข้อมูลก่อนที่จะถูกจัดเก็บ ป้องกันข้อมูลที่ไม่ถูกต้องใน object
- Encapsulation: ควบคุมวิธีการที่ properties ถูกแก้ไขจากภายนอก
- Side effects: สามารถ trigger การทำงานอื่นๆ เมื่อ property ถูกแก้ไข เช่น การอัปเดต UI หรือการบันทึกข้อมูล
การ Validation Data ด้วย Getter และ Setter
การ validation data เป็น use case ที่สำคัญที่สุดอย่างหนึ่งของ getter และ setter มันช่วยให้เรามั่นใจได้ว่าข้อมูลที่อยู่ใน object ของเรานั้นถูกต้องและเป็นไปตามเงื่อนไขที่เรากำหนด
แนวทางการ Validation:
- Type checking: ตรวจสอบว่า data type ของค่าที่กำหนดถูกต้องหรือไม่ (เช่น เป็น number, string, array)
- Range checking: ตรวจสอบว่าค่าที่กำหนดอยู่ในช่วงที่กำหนดหรือไม่ (เช่น อายุต้องอยู่ระหว่าง 0 ถึง 120)
- Format checking: ตรวจสอบว่าค่าที่กำหนดเป็นไปตามรูปแบบที่กำหนดหรือไม่ (เช่น อีเมลต้องมีรูปแบบที่ถูกต้อง)
- Business rules: ตรวจสอบว่าค่าที่กำหนดเป็นไปตามกฎทางธุรกิจที่กำหนดหรือไม่ (เช่น จำนวนสินค้าในสต็อกต้องไม่เป็นลบ)
Trade-offs: การเพิ่ม validation เข้าไปใน getter และ setter อาจทำให้ประสิทธิภาพลดลงเล็กน้อย แต่โดยทั่วไปแล้วผลกระทบนั้นน้อยมากเมื่อเทียบกับประโยชน์ที่ได้รับจากการรักษาความถูกต้องของข้อมูล
แนวปฏิบัติที่ดีในการใช้ Getter และ Setter
- ใช้ underscore (
_) เป็น convention สำหรับ private properties: เพื่อบอกว่า property นี้ไม่ควรถูกเข้าถึงโดยตรงจากภายนอก - Getter ควรจะเร็วและไม่มี side effects: Getter ควรจะคืนค่า property โดยไม่มีการเปลี่ยนแปลงสถานะของ object
- Setter ควรจะระมัดระวังและ validate ข้อมูล: Setter ควรจะตรวจสอบความถูกต้องของข้อมูลก่อนที่จะจัดเก็บ และอาจ throw error หากข้อมูลไม่ถูกต้อง
- พิจารณาความซับซ้อนของ logic: หาก logic ใน getter หรือ setter ซับซ้อนเกินไป อาจพิจารณาย้าย logic นั้นไปอยู่ใน method อื่น
- อย่าใช้ getter/setter เพียงเพราะคิดว่า "ควรจะมี": ใช้เฉพาะเมื่อต้องการควบคุมการเข้าถึง property จริงๆ
สรุป
Getter และ setter methods เป็นเครื่องมือที่มีประโยชน์ในการควบคุมการเข้าถึงและแก้ไข properties ของ object ใน JavaScript มันช่วยให้เราสามารถ validate data, transform data, encapsulate data และสร้าง read-only หรือ computed properties ได้ การใช้งาน getter และ setter อย่างถูกต้องจะช่วยให้โค้ดของเรามีความน่าเชื่อถือและบำรุงรักษาได้ง่ายขึ้น
ในบทเรียนถัดไป เราจะมาเรียนรู้เกี่ยวกับ Spread Operator ซึ่งเป็น syntax ที่ช่วยให้เราสามารถขยาย (expand) array หรือ object ได้อย่างง่ายดาย