คุณสมบัติเพิ่มเติมของคลาสใน JavaScript

คุณสมบัติเพิ่มเติมของคลาสใน 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 ด้วย

YouTube Video