คุณสมบัติเพิ่มเติมของคลาสใน JavaScript
ในบทความนี้ เราจะอธิบายคุณสมบัติเพิ่มเติมของคลาสใน JavaScript
YouTube Video
คุณสมบัติเพิ่มเติมของคลาสใน JavaScript
คุณสมบัติส่วนตัวใน JavaScript
ใน JavaScript คุณสมบัติส่วนตัวคือคุณสมบัติที่เข้าถึงได้เฉพาะภายในออบเจ็กต์หรือคลาสเท่านั้น สิ่งนี้ช่วยให้การออกแบบโค้ดมีความปลอดภัยและแข็งแกร่งยิ่งขึ้นด้วยการใช้ encapsulation ทำให้การเปลี่ยนแปลงหรือเข้าถึงโดยตรงจากโค้ดภายนอกเป็นไปไม่ได้
ใน ECMAScript 2020 (ES11) ซึ่งเปิดตัวในปี 2020 ได้แนะนำการใช้ #
(เครื่องหมายแฮช) เพื่อกำหนดฟิลด์ส่วนตัวภายในคลาส สิ่งนี้ช่วยมอบวิธีที่ชัดเจนกว่าในการแทนที่ธรรมเนียมการทำคุณสมบัติส่วนตัวแบบดั้งเดิมใน JavaScript (เช่นการตั้งชื่อตัวแปรโดยเริ่มด้วยเครื่องหมายขีดล่าง)
ข้อดีของคุณสมบัติส่วนตัว
ต่อไปนี้คือข้อดีของคุณสมบัติแบบส่วนตัว (private properties)
- การห่อหุ้ม (Encapsulation): ซ่อนสถานะภายในจากภายนอกและรักษาความสอดคล้องของข้อมูล
- Security: ป้องกันไม่ให้คุณสมบัติถูกเปลี่ยนแปลงโดยไม่ได้ตั้งใจจากโค้ดภายนอก
- การดูแลรักษาที่ดีขึ้น: ซ่อนการทำงานภายในของวัตถุหรือคลาส และทำให้ส่วนต่อประสานที่เปิดเผยต่อภายนอกชัดเจนยิ่งขึ้น
วิธีการใช้คุณสมบัติส่วนตัว
การกำหนดคุณสมบัติส่วนตัวในคลาส
ฟิลด์ส่วนตัวถูกกำหนดด้วยชื่อที่เริ่มต้นด้วย #
ฟิลด์นี้ไม่สามารถเข้าถึงได้โดยตรงจากอินสแตนซ์ของคลาสหรือคลาสย่อย
1class Person {
2 // Define private property
3 #name;
4
5 constructor(name) {
6 this.#name = name;
7 }
8
9 // Method to access the private property
10 getName() {
11 return this.#name;
12 }
13
14 // Method to change the private property
15 setName(newName) {
16 this.#name = newName;
17 }
18}
19
20const john = new Person("John");
21console.log(john.getName()); // John
22
23// Cannot access private property directly
24console.log(john.#name); // SyntaxError: Private field '#name' must be declared in an enclosing class
ในโค้ดด้านบน #name
เป็นคุณสมบัติส่วนตัวที่ไม่สามารถเข้าถึงได้โดยตรงจากภายนอกคลาส Person
คุณสามารถเข้าถึงหรือเปลี่ยนแปลงชื่อได้ผ่านเมธอด getName
และ setName
เท่านั้น
การกำหนดเมธอดส่วนตัว
เช่นเดียวกับคุณสมบัติส่วนตัว เมธอดส่วนตัวก็ถูกกำหนดด้วยชื่อที่เริ่มต้นด้วย #
เมธอดส่วนตัวสามารถเรียกใช้ได้ภายในคลาสเท่านั้น
1class Counter {
2 #count = 0;
3
4 increment() {
5 this.#count++;
6 this.#logCount(); // Calling private method
7 }
8
9 // Private method
10 #logCount() {
11 console.log(`Current count: ${this.#count}`);
12 }
13}
14
15const counter = new Counter();
16counter.increment(); // Current count: 1
17
18// Cannot access private method directly
19counter.#logCount(); // SyntaxError: Private field '#logCount' must be declared in an enclosing class
ในที่นี้ #logCount
ถูกกำหนดให้เป็นเมธอดส่วนตัวและไม่สามารถเข้าถึงได้จากภายนอกคลาส เมธอดนี้ถูกใช้เฉพาะภายในคลาสเท่านั้น
ข้อดีและข้อพิจารณาของคุณสมบัติส่วนตัว
ข้อได้เปรียบ
- เนื่องจากไม่สามารถเข้าถึงได้โดยตรงจากภายนอกคลาส การเปลี่ยนแปลงหรือกระบวนการที่ไม่ตั้งใจจึงถูกป้องกัน
- เนื่องจากส่วนที่มองไม่เห็นจากภายนอกสามารถถูกซ่อนไว้ได้ดี คุณจึงสามารถจัดการส่วนที่เปิดเผยเป็น API ได้อย่างชัดเจน
หมายเหตุ
- เนื่องจากฟิลด์ส่วนตัวถูกซ่อนไว้อย่างสมบูรณ์จากภายนอกคลาส การทดสอบและการแก้ไขข้อผิดพลาดอาจทำได้ยาก ดังนั้นจึงเป็นสิ่งสำคัญที่จะต้องจัดหา API ที่สามารถทดสอบได้อย่างละเอียดในขั้นตอนการออกแบบ
- ฟิลด์ส่วนตัวมีพฤติกรรมที่แตกต่างจากส่วนอื่นของ JavaScript ที่มีลักษณะเชิงต้นแบบ เพราะฟิลด์เหล่านี้มีความเป็นเอกลักษณ์เฉพาะตัวในแต่ละอินสแตนซ์
การใช้สมบัติส่วนตัวแบบนามแฝงในลักษณะดั้งเดิม
ก่อนการเปิดตัวฟิลด์ส่วนตัวที่ใช้ #
JavaScript ยังไม่มีไวยากรณ์อย่างเป็นทางการสำหรับสมบัติส่วนตัว ดังนั้น ในอดีต สมบัติส่วนตัวแบบสมมุติจึงถูกนำมาใช้ในรูปแบบดังต่อไปนี้
ธรรมเนียมการใช้ขีดล่าง (underscore)
นักพัฒนาโดยทั่วไปจะแสดงถึง 'ส่วนตัว' โดยการใส่ขีดล่างหน้าชื่อของตัวแปร
1class Car {
2 constructor(brand) {
3 this._brand = brand; // Using an underscore to indicate private
4 }
5
6 getBrand() {
7 return this._brand;
8 }
9}
10
11const car = new Car("Toyota");
12console.log(car.getBrand()); // Toyota
13console.log(car._brand); // Toyota (Accessible from outside)
วิธีนี้เป็นเพียง 'ธรรมเนียมปฏิบัติ' เท่านั้น และในทางปฏิบัติ สมบัติยังสามารถถูกเข้าถึงจากภายนอกได้
การใช้สมบัติส่วนตัวด้วยการใช้ closure
ยังเป็นไปได้ที่จะสร้างสมบัติส่วนตัวด้วยการใช้ closure ในขอบเขตของฟังก์ชัน
1function createPerson(name) {
2 let _name = name; // Private variable within function scope
3
4 return {
5 getName: function() {
6 return _name;
7 },
8 setName: function(newName) {
9 _name = newName;
10 }
11 };
12}
13
14const person = createPerson("Alice");
15console.log(person.getName()); // Alice
16person.setName("Bob");
17console.log(person.getName()); // Bob
18
19// Cannot access directly from outside
20console.log(person._name); // undefined
ด้วยวิธีนี้ ตัวแปร _name
จะถูกเก็บไว้ภายในขอบเขตของฟังก์ชันและไม่สามารถเข้าถึงโดยตรงจากภายนอกได้
สรุป
สมบัติส่วนตัวใน JavaScript มีประสิทธิภาพมากในการจัดให้อยู่ในขอบเขตที่เหมาะสมในคลาสและการออกแบบออบเจ็กต์ ซึ่งช่วยปกป้องข้อมูลอย่างปลอดภัย สัญลักษณ์ #
สำหรับฟิลด์ส่วนตัวที่เปิดตัวใน ES2020 นำเสนอวิธีการจัดการความเป็นส่วนตัวที่ชัดเจนและปลอดภัยกว่าที่ใช้ในธรรมเนียมปฏิบัติและ closure แบบดั้งเดิม
การใช้ Optional Chaining ใน JavaScript
Optional Chaining เป็นไวยากรณ์ที่มีประโยชน์มากใน JavaScript สำหรับการเข้าถึงสมบัติของออบเจ็กต์ที่ซ้อนกันอยู่ลึก มันช่วยเพิ่มความอ่านง่ายและความสามารถในการบำรุงรักษาโค้ด โดยอนุญาตให้เข้าถึงได้อย่างปลอดภัยโดยไม่ต้องตรวจสอบการมีอยู่ของสมบัติเฉพาะแบบทีละรายการ
ไวยากรณ์พื้นฐานของ Optional Chaining
Optional Chaining สามารถใช้งานได้โดยวาง ?
ไว้หน้าจุด (.
) หรือเครื่องหมายวงเล็บที่ใช้สำหรับเข้าถึงสมบัติ ไวยากรณ์นี้จะคืนค่า undefined
เมื่อสมบัติที่กำลังเรียกดูมีค่าเป็น null
หรือ undefined
ช่วยให้โปรแกรมดำเนินการต่อได้อย่างปลอดภัยโดยไม่เกิดข้อผิดพลาด
ตัวอย่าง:
1const user = {
2 name: 'John',
3 address: {
4 street: '123 Main St',
5 city: 'New York'
6 }
7};
8
9// Without using optional chaining
10const city = user && user.address && user.address.city;
11console.log(city); // New York
12
13// Using optional chaining
14const cityWithOptionalChaining = user?.address?.city;
15console.log(cityWithOptionalChaining); // New York
ในตัวอย่างนี้ เรากำลังเข้าถึง address
และสมบัติ city
ของออบเจ็กต์ user
หากไม่ใช้ optional chaining คุณจะต้องตรวจสอบการมีอยู่หลายครั้ง แต่ด้วย optional chaining คุณสามารถเข้าถึง property ได้อย่างปลอดภัยด้วยคำสั่งเดียว
การใช้ Optional Chaining กับอาร์เรย์และฟังก์ชัน
Optional chaining สามารถใช้งานได้ไม่เพียงแค่ property ของอ็อบเจ็กต์ แต่ยังใช้กับองค์ประกอบของอาร์เรย์และการเรียกฟังก์ชันด้วย
ตัวอย่างกับอาร์เรย์:
1const users = [{ name: 'Alice' }, { name: 'Bob' }];
2
3// Accessing the non-existent third element
4const thirdUser = users[2]?.name;
5console.log(thirdUser); // undefined
ตัวอย่างกับฟังก์ชัน:
1const user = {
2 greet: function() {
3 return 'Hello!';
4 }
5};
6
7// Call the function only if greet exists
8const greeting = user.greet?.();
9console.log(greeting); // Hello!
10
11// Return undefined if greet does not exist
12const nonExistentGreeting = user.nonExistentMethod?.();
13console.log(nonExistentGreeting); // undefined
การผสมผสาน Optional Chaining กับค่าดีฟอลต์
เมื่อใช้ optional chaining มักจะใช้ logical OR (||
) หรือ nullish coalescing operator (??
) เพื่อระบุดีฟอลต์ค่าเมื่อ property ไม่ปรากฏ
ตัวอย่าง:
1const user = {
2 name: 'John',
3 address: {
4 city: 'New York'
5 }
6};
7
8// Set a default value for a non-existent property
9const state = user?.address?.state || 'Unknown';
10console.log(state); // Unknown
11
12// Example using the nullish coalescing operator
13const zipCode = user?.address?.zipCode ?? '00000';
14console.log(zipCode); // 00000
ตัวดำเนินการ ||
ถือว่า false
, 0
, ''
ฯลฯ เป็นค่า falsy ในขณะที่ ??
จะใช้ค่าดีฟอลต์เฉพาะกรณี operand เป็น null
หรือ undefined
ประโยชน์ของ Optional Chaining
- การเข้าถึงอ็อบเจ็กต์ที่ซ้อนกันอย่างปลอดภัย: ด้วยการใช้ optional chaining คุณไม่จำเป็นต้องตรวจสอบการมีอยู่อย่างชัดแจ้ง ทำให้โค้ดกระชับขึ้น
- การป้องกันข้อผิดพลาด: ช่วยหลีกเลี่ยงข้อผิดพลาด runtime แม้ว่า property จะเป็น
null
หรือundefined
- การเพิ่มความเข้าใจและการดูแลรักษาโค้ด: โดยเฉพาะอย่างยิ่งเมื่อทำงานกับอ็อบเจ็กต์ที่ซ้อนซับหลายชั้น ความสามารถในการอ่านโค้ดจะเพิ่มขึ้นอย่างมาก
ข้อควรระวังกับ Optional Chaining
- การใช้ optional chaining บ่อยครั้งอาจเป็นสัญญาณว่าโครงสร้างข้อมูลนั้นมีการออกแบบที่ซับซ้อนเกินไป คุณควรพยายามออกแบบโมเดลข้อมูลให้ง่าย
- เนื่องจากเบราว์เซอร์เก่าและเอนจิน JavaScript บางตัวไม่รองรับ คุณอาจต้องใช้ polyfills หรือ transpilers
สรุป
Optional chaining เป็นฟีเจอร์ที่ทรงพลังซึ่งช่วยให้การเข้าถึง property และฟังก์ชันของอ็อบเจ็กต์ที่ซ้อนกันใน JavaScript ง่ายและปลอดภัยยิ่งขึ้น มันมีประสิทธิภาพอย่างมากเมื่อเข้าถึงโครงสร้างข้อมูลที่ซ้อนกันลึก ช่วยป้องกันข้อผิดพลาดและเพิ่มความสามารถในการอ่านโค้ด
คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย