Encapsulation ในภาษา JavaScript
ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับคุณสมบัติการห่อหุ้ม (Encapsulation) ในภาษา JavaScript ซึ่งเป็นแนวคิดที่สำคัญในการเขียนโปรแกรมเชิงวัตถุที่ใช้สำหรับปกป้องข้อมูลภายในออบเจ็คจากการเข้าถึงโดยตรงจากภายนอกทำให้มันมีความปลอดภัยมากขึ้น นี่เป็นเนื้อหาในบทนี้
- Encapsulation คืออะไร
- Private properties
- Private methods
Encapsulation คืออะไร
Encapsulation หรือคุณสมบัติการห่อหุ้ม เป็นแนวคิดในการเขียนโปรแกรมเชิงวัตถุที่ข้อมูลในออบเจ็คจะถูกปกป้องหรือซ่อนเอาไว้ และในการดำเนินการกับข้อมูลดังกล่าวจะทำผ่านเมธอดแทน นี่ช่วยป้องกันการเข้าถึงข้อมูลในออบเจ็คโดยตรงและทำให้ข้อมูลมีความปลอดภัยมากขึ้น และในภาษา JavaScript เราสามารถกำหนดระดับการเข้าถึงของสมาชิกในออบเจ็คได้ด้วยสองรูปแบบได้แก่
- Public: เป็นสมาชิกที่สามารถเข้าถึงได้ทั้งจากภายในคลาสและนอกคลาส (นี่เป็นค่าเริ่มต้น)
- Private: เป็นสมาชิกที่สามารถเข้าถึงจากภายในคลาสเท่านั้น
ดังนั้นเพื่อปกป้องข้อมูลในออบเจ็ค เราจะกำหนดระดับการเข้าถึงของ Property หรือเมธอดของคลาสให้มีระดับการเข้าถึงเป็นแบบ Private และการดำเนินการกับข้อมูลเหล่านี้จะทำผ่านเมธอดที่เป็นแบบ Public แทน
Private properties
Private property คือสมาชิกของคลาสที่ถูกกำหนดระดับการเข้าถึงเป็นแบบ Private โดยเขียนเครื่องหมาย #
ที่หน้าชื่อของตัวแปร นี่จะทำให้ Property สามารถใช้งานได้จากเมธอดภายในคลาสเดียวกันเท่านั้น นี่เป็นตัวอย่างของคลาสเครื่องเล่นเพลงที่มีข้อมูลของระดับเสียงเป็น Property แบบ Private
class MusicPlayer {
#soundLevel = 0;
constructor(song) {
this.song = song;
}
setVolume(value) {
if (value < 0) {
this.#soundLevel = 0;
} else if (value > 30) {
this.#soundLevel = 30;
} else {
this.#soundLevel = value;
}
}
getVolume() {
return this.#soundLevel;
}
play() {
console.log(`Song starts playing...`);
}
stop() {
console.log(`Song has stopped playing.`);
}
}
let player = new MusicPlayer("Automatica - Nigel Standford");
player.setVolume(25);
player.play();
console.log(`Currently playing: '${player.song}'`);
console.log(`Volume was set to: ${player.getVolume()}`);
player.stop();
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
Song starts playing...
Currently playing: 'Automatica - Nigel Standford'
Volume was set to: 25
Song has stopped playing.
ในตัวอย่างนี้ เป็นโปรแกรมจำลองการทำงานของเครื่องเล่นเพลงที่มีสอง Property คือ song
สำหรับเก็บชื่อเพลงที่ต้องการเล่น และ #soundLevel
สำหรับเก็บระดับความดังของเครื่องเล่นเพลงโดย Property นี้มีระดับการเข้าถึงเป็นแบบ Private เนื่องจากเราต้องการปกปิดการเข้าถึงมันจากภายนอกออบเจ็ค
setVolume(value) {
if (value < 0) {
this.#soundLevel = 0;
} else if (value > 30) {
this.#soundLevel = 30;
} else {
this.#soundLevel = value;
}
}
getVolume() {
return this.#soundLevel;
}
และในการที่จะเข้าถึง Property นี้สำหรับอ่านค่าและกำหนดค่า เราจะต้องทำผ่าน Public เมธอดที่ทำหน้าที่เป็นตัวรับค่า (Getter) และกำหนดค่า (Setter) โดยที่ Public เมธอดนั้นสามารถเข้าถึงข้อมูลภายในคลาสที่มีระดับการเข้าถึงเป็นแบบ Private ได้เสมอ เนื่องจากมันเป็นสมาชิกจากคลาสเดียวกัน
player.setVolume(25);
...
console.log(`Volume was set to: ${player.getVolume()}`);
นั่นหมายความว่าในการกำหนดค่าและอ่านค่าจาก #soundLevel
จะต้องทำผ่านเมธอดที่มอบให้เท่านั้น นอกจากนี้ ภายในเมธอด setVolume
ยังได้ตรวจสอบระดับเสียงว่าจะต้องอยู่ในช่วงที่กำหนดเท่านั้นคือ 0-30 นี่จะทำให้ไม่มีใครสามารถเปลี่ยนแปลงค่าของ Property นี้โดยตรงได้ผ่านทางออบเจ็ค ยกตัวอย่างเช่น
// This will give an error
player.#soundLevel = 50;
คำสั่งนี้จะทำให้เกิดข้อผิดพลาดขึ้นเนื่องจากการเข้าถึง #soundLevel
เกิดขึ้นที่ภายนอกของออบเจ็คซึ่งเป็นสิ่งที่ไม่อนุญาติสำหรับ Private property และนี่เองเป็นวิธีการปกป้องข้อมูลในออบเจ็คให้ปลอดภัยจากการเข้าถึงภายนอก และอนุญาติให้ทำผ่านช่องทางที่กำหนดไว้เท่านั้น
console.log(`Currently playing: '${player.song}'`);
// or
player.song = "Gavity - Nigel Standford";
ในขณะที่ Property song
จะสามารถเข้าถึงจากภายนอกออบเจ็คหรือผ่านตัวแปรออบเจ็คเพื่ออ่านและกำหนดค่าโดยตรงได้ เนื่องจากมันมีระดับการเข้าถึงเป็นแบบ Public ซึ่งเป็นค่าเริ่มต้นของ Property และเมธอดในภาษา JavaScript
Private methods
นอกจาก Property แล้ว เมธอดก็ยังสามารถกำหนดการเข้าถึงเป็นแบบ Private ได้เช่นเดียวกันเพียงแค่ใส่เครื่องหมาย #
หน้าชื่อของเมธอด นี่จะทำให้มันสามารถเรียกใช้ได้จากเมธอดในคลาสเดียวกันเท่านั้น ต่อไปมาดูตัวอย่างการใช้งาน Private เมธอดในภาษา JavaScript
นี่เป็นตัวอย่างโปรแกรมจำลองการทำงานของรถยนต์ โดยการจำลองการทำงานพื้นฐานของรถยนต์ให้เป็นทั้งเมธอดที่เป็นแบบ Public และ Private ต่อไปมาดูตัวอย่างในการเขียนโปรแกรม
class Car {
#fuelLevel = 0;
constructor(name) {
this.name = name;
}
// Public methods
start() {
console.log(`${this.name} engine has started.`);
}
stop() {
console.log(`${this.name} engine has stopped.`);
}
fillUpFuel(amount) {
this.#fuelLevel += amount;
console.log(`${this.name}'s fuel has increased by ${amount}.`);
}
getFuelLevel() {
return this.#fuelLevel;
}
move(direction, speed) {
let fuelToUse = speed * 0.5;
if (this.#fuelAvailable(fuelToUse)) {
this.#consumeFuel(fuelToUse);
console.log(`${this.name} is moving ${direction} at ${speed} MPH.`);
} else {
console.log(`Fuel is not enoght for ${this.name} to move.`);
}
}
// Private methods
#consumeFuel(amount) {
this.#fuelLevel -= amount;
console.log(`${this.name} fuel has been consumed by ${amount}.`);
}
#fuelAvailable(fuelToUse) {
return this.#fuelLevel >= fuelToUse;
}
}
// Let's ride the car
let myCar = new Car("Tesla Model X");
myCar.start();
myCar.fillUpFuel(100);
myCar.move("forward", 56);
console.log(`How much fuel left for this car? ${myCar.getFuelLevel()}`);
myCar.move("backward", 20);
console.log(`How much fuel left for this car? ${myCar.getFuelLevel()}`);
myCar.move("forward", 200);
myCar.stop();
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม
ในตัวอย่างนี้ เราได้สร้างคลาส Car
ซึ่งเป็นคลาสของรถยนต์ที่มีสอง Property คือ name
ที่มีระดับการเข้าถึงแบบ Public และ #fuelLevel
ที่มีระดับการเข้าถึงเป็นแบบ Private จากนั้นภายในคลาสประกอบไปด้วยเมธอดทั้งแบบ Public และ Private ต่อไปมาดูว่าแต่ละเมธอดทำงานอะไร
start() {
console.log(`${this.name} engine has started.`);
}
stop() {
console.log(`${this.name} engine has stopped.`);
}
มาเริ่มจากสองเมธอดแรกคือเมธอด start
และ stop
ที่เป็น Public เมธอด มันใช้สำหรับเริ่มต้นและหยุดการทำงานของเครื่องยนต์ตามชื่อของมัน เมธอดเหล่านี้เพียงแค่แสดงข้อความเพื่อแจ้งสถานะการทำงานพร้อมกับชื่อของรถยนต์ที่กำลังทำงานอยู่เท่านั้น
fillUpFuel(amount) {
this.#fuelLevel += amount;
console.log(`${this.name}'s fuel has increased by ${amount}.`);
}
getFuelLevel() {
return this.#fuelLevel;
}
สองเมธอดต่อมาทำหน้าที่เป็น Getter และ Setter เมธอดสำหรับทำงานกับ Property #fuelLevel
ที่มีระดับการเข้าถึงเป็นแบบ Private เมธอดเหล่านี้ใช้สำหรับเติมเชื้อเพลิงให้กับรถยนต์ และรับเอาค่าของเชื้อเพลงปัจจุบันที่รถยนต์มีอยู่
#consumeFuel(amount) {
this.#fuelLevel -= amount;
console.log(`${this.name} fuel has been consumed by ${amount}.`);
}
#fuelAvailable(fuelToUse) {
return this.#fuelLevel >= fuelToUse;
}
ต่อมาเป็นเมธอดที่มีระดับการเข้าถึงเป็นแบบ Private เพราะว่าการทำงานเหล่านี้ไม่จำเป็นต้องใช้ภายนอกออบเจ็ค เมธอด #consumeFuel
ใช้สำหรับบริโภคเชื้อเพลิงจากปริมาณที่ระบุ ส่วนเมธอด #fuelAvailable
ใช้เพื่อตรวจสอบว่ารถยนต์มีเชื้อเพลิงเหลือตามปริมาณที่ต้องการหรือไม่
move(direction, speed) {
let fuelToUse = speed * 0.5;
if (this.#fuelAvailable(fuelToUse)) {
this.#consumeFuel(fuelToUse);
console.log(`${this.name} is moving ${direction} at ${speed} MPH.`);
} else {
console.log(`Fuel is not enoght for ${this.name} to move.`);
}
}
สุดท้ายเมธอด move
เป็นเมธอดที่ใช้สำหรับขับรถยนต์ไปยังทิศทางที่ระบุ พร้อมกับความเร็วที่ต้องการ ในการที่จะเคลื่อนที่รถยนต์ในตามความเร็วที่กำหนดได้นั้นจะมีการใช้งานเชื้อเพลิงเป็นจำนวน 50 เปอร์เซ็นต์ของความเร็ว เราได้คำนวณค่านี้และเก็บไว้ในตัวแปร fuelToUse
และในการที่รถยนต์จะเคลื่อนที่ได้ เชื้อเพลิงจะต้องเพียงพอต่อการใช้งาน เราใช้เมธอด #fuelAvailable
เพื่อตรวจสอบว่ามีเชื้อเพลิงเพียงพอหรือไม่ ในกรณีที่ใช่ เรียกใช้งานเมธอด #consumeFuel
เพื่อใช้งานเชื้อเพลิงตามจำนวนที่กำหนด ไม่เช่นนั้นแสดงข้อความว่าเชื้อเพลิงไม่พอ
ในตอนนี้คุณเห็นแล้วว่าทั้งเมธอด #fuelAvailable
และ #consumeFuel
เป็นการทำงานภายในของระบบรถยนต์อย่างชัดเจน นั่นทำให้เรากำหนดการเข้าถึงของมันเป็นแบบ Private เพื่อไม่ให้เปิดเผยกับภายนอกของออบเจ็ค
myCar.move("forward", 56);
นั่นหมายความว่าเมื่อคุณต้องการทำให้รถยนต์เคลื่อนที่ คุณไม่จำเป็นต้องทราบว่ามันทำงานอย่างไร ยกตัวอย่างเช่น เครื่องยนต์ทำงานอย่างไร หรือกลไกที่ทำให้ล้อหมุนเป็นอย่างไร นั่นเป็นเพราะว่าการทำงานเหล่านี้ไม่จำเป็นต่อผู้ใช้งาน ดังนั้นมันจึงถูกซ่อนจากมุมมองของผู้ใช้งาน
ในบทนี้ คุณได้เรียนรู้เกี่ยวกับุคุณสมบัติการห่อหุ้มหรือ Encapsulation ในภาษา JavaScript ที่เป็นคุณสมบัติในการเขียนโปรแกรมเชิงวัตถุที่ช่วยให้ข้อมูลมีความปลอดภัย และยังมีประโยชน์ทั้งในด้านโครงสร้างของโปรแกรมที่ดีและต่อการบำรุงรักษา