Các tính năng bổ sung của lớp trong JavaScript

Các tính năng bổ sung của lớp trong JavaScript

Trong bài viết này, chúng tôi sẽ giải thích các tính năng bổ sung của lớp trong JavaScript.

YouTube Video

Các tính năng bổ sung của lớp trong JavaScript

Thuộc tính riêng tư trong JavaScript

Trong JavaScript, các thuộc tính riêng tư là các thuộc tính chỉ có thể truy cập được trong đối tượng hoặc lớp. Điều này cung cấp thiết kế mã bảo mật và mạnh mẽ hơn bằng cách cung cấp đóng gói, để việc thay đổi trực tiếp hoặc tham chiếu từ mã bên ngoài không thể thực hiện được.

Được giới thiệu trong ECMAScript 2020 (ES11) vào năm 2020, việc sử dụng dấu # (hash) để định nghĩa các trường riêng tư trong một lớp được ra mắt. Điều này cung cấp một cách rõ ràng hơn, thay thế các quy ước riêng tư truyền thống của JavaScript (như tên biến bắt đầu bằng dấu gạch dưới).

Lợi ích của các thuộc tính riêng tư

Sau đây là những lợi ích của các thuộc tính riêng tư.

  • Đóng gói: Ẩn trạng thái nội bộ khỏi bên ngoài và duy trì tính nhất quán của dữ liệu.
  • Bảo mật: Ngăn chặn các thuộc tính bị thay đổi không mong muốn bởi mã bên ngoài.
  • Tăng khả năng bảo trì: Ẩn việc triển khai của các đối tượng hoặc lớp và làm rõ giao diện được hiển thị ra bên ngoài.

Cách sử dụng các thuộc tính riêng tư

Định nghĩa các thuộc tính riêng tư trong lớp

Các trường riêng tư được định nghĩa bằng cách sử dụng một tên bắt đầu bằng #. Trường này không thể được truy cập trực tiếp từ các đối tượng của lớp hoặc từ các lớp con của nó.

 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

Trong mã trên, #name là một thuộc tính riêng tư không thể truy cập trực tiếp từ bên ngoài lớp Person. Bạn chỉ có thể truy cập hoặc thay đổi tên thông qua các phương thức getNamesetName.

Định nghĩa các phương thức riêng tư

Giống như các thuộc tính riêng tư, các phương thức riêng tư cũng được định nghĩa bằng cách sử dụng một tên bắt đầu bằng #. Các phương thức riêng tư chỉ có thể được gọi từ bên trong lớp.

 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

Ở đây, #logCount được định nghĩa là một phương thức riêng tư và không thể truy cập từ bên ngoài lớp. Phương thức này chỉ được sử dụng bên trong lớp.

Lợi ích và các điểm cần cân nhắc về các thuộc tính riêng tư

Lợi thế

  • Bởi vì không thể truy cập trực tiếp từ bên ngoài lớp, các thay đổi hoặc hoạt động không mong muốn được ngăn chặn.
  • Bởi vì các phần không hiển thị từ bên ngoài có thể được ẩn tốt, bạn có thể quản lý rõ ràng các phần bạn công khai như một API.

Ghi chú

  • Bởi vì các trường riêng tư hoàn toàn bị ẩn từ bên ngoài lớp, việc kiểm tra và gỡ lỗi có thể trở nên khó khăn. Do đó, điều quan trọng là phải cung cấp một API có thể được kiểm tra kỹ lưỡng ở giai đoạn thiết kế.
  • Các trường riêng tư hoạt động khác biệt với các phần khác của JavaScript với đặc tính dựa trên nguyên mẫu vì chúng là duy nhất cho mỗi thể hiện.

Triển khai truyền thống dưới dạng biệt danh cho các thuộc tính riêng tư

Trước khi giới thiệu các trường riêng tư sử dụng #, JavaScript không có cú pháp chính thức cho các thuộc tính riêng tư. Vì vậy, trong quá khứ, các thuộc tính giả riêng tư đã được triển khai theo các cách sau.

Quy ước sử dụng dấu gạch dưới

Các nhà phát triển thường quy định 'riêng tư' bằng cách thêm dấu gạch dưới vào trước tên biến.

 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)

Phương pháp này chỉ là một 'quy ước', và trên thực tế, các thuộc tính vẫn có thể được truy cập từ bên ngoài.

Triển khai các thuộc tính riêng tư bằng cách sử dụng closures

Cũng có thể đạt được thuộc tính riêng tư bằng cách sử dụng closures với phạm vi hàm.

 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

Với phương pháp này, biến _name được bao bọc trong phạm vi hàm và không thể truy cập trực tiếp từ bên ngoài.

Tóm tắt

Các thuộc tính riêng tư trong JavaScript rất hiệu quả trong việc cung cấp khả năng đóng gói trong thiết kế lớp và đối tượng, giúp bảo vệ dữ liệu an toàn. Ký hiệu # cho các trường riêng tư được giới thiệu trong ES2020 cung cấp phương pháp quản lý quyền riêng tư rõ ràng và an toàn hơn so với các quy ước truyền thống và closures.

Chuỗi tùy chọn trong JavaScript

Chuỗi tùy chọn là một cú pháp rất hữu ích trong JavaScript để truy cập các thuộc tính của các đối tượng lồng ghép sâu. Nó tăng cường khả năng đọc và duy trì mã bằng cách cho phép truy cập an toàn mà không cần phải kiểm tra riêng lẻ sự tồn tại của các thuộc tính cụ thể.

Cú pháp cơ bản của Chuỗi tùy chọn

Chuỗi tùy chọn có thể được sử dụng bằng cách đặt ? trước dấu chấm (.) hoặc ký hiệu dấu ngoặc được sử dụng để truy cập thuộc tính. Ký hiệu này trả về undefined khi một thuộc tính được duyệt là null hoặc undefined, cho phép chương trình tiếp tục xử lý an toàn mà không ném lỗi.

Ví dụ:

 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

Trong ví dụ này, chúng tôi đang truy cập thuộc tính address và thuộc tính city của đối tượng user. Nếu không sử dụng chuỗi lựa chọn (optional chaining), bạn sẽ cần thực hiện nhiều lần kiểm tra sự tồn tại, nhưng với chuỗi lựa chọn, bạn có thể truy cập an toàn vào thuộc tính chỉ bằng một câu lệnh duy nhất.

Sử dụng chuỗi lựa chọn với mảng và hàm

Chuỗi lựa chọn có thể được áp dụng không chỉ cho thuộc tính của đối tượng mà còn cho các phần tử của mảng và các lời gọi hàm.

Ví dụ với mảng:

1const users = [{ name: 'Alice' }, { name: 'Bob' }];
2
3// Accessing the non-existent third element
4const thirdUser = users[2]?.name;
5console.log(thirdUser);  // undefined

Ví dụ với hàm:

 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

Kết hợp chuỗi lựa chọn với các giá trị mặc định

Khi sử dụng chuỗi lựa chọn, việc sử dụng toán tử OR logic (||) hoặc toán tử hợp lệ nullish (??) để chỉ định các giá trị mặc định nếu một thuộc tính không tồn tại là rất phổ biến.

Ví dụ:

 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

Toán tử || coi false, 0, '', v.v., là sai, trong khi toán tử ?? chỉ sử dụng giá trị mặc định nếu toán hạng là null hoặc undefined.

Lợi ích của chuỗi lựa chọn

  • Truy cập an toàn vào các đối tượng lồng nhau: Sử dụng chuỗi lựa chọn, bạn không cần kiểm tra sự tồn tại rõ ràng, làm cho mã ngắn gọn hơn.
  • Tránh lỗi: Nó có thể ngăn ngừa lỗi trong quá trình chạy ngay cả khi một thuộc tính là null hoặc undefined.
  • Cải thiện khả năng đọc và bảo trì: Đặc biệt khi xử lý nhiều đối tượng lồng nhau, khả năng đọc mã được cải thiện đáng kể.

Lưu ý khi sử dụng chuỗi lựa chọn

  • Việc sử dụng chuỗi lựa chọn quá thường xuyên có thể là dấu hiệu cho thấy thiết kế cấu trúc dữ liệu quá phức tạp. Bạn nên cố gắng thiết kế một mô hình dữ liệu đơn giản.
  • Do một số trình duyệt cũ hơn và các trình thông dịch JavaScript không hỗ trợ, bạn có thể cần sử dụng polyfills hoặc transpilers.

Kết luận

Chuỗi lựa chọn là một tính năng mạnh mẽ giúp đơn giản hóa việc truy cập an toàn vào các thuộc tính và hàm của đối tượng lồng nhau trong JavaScript. Nó đặc biệt hiệu quả khi truy cập vào các cấu trúc dữ liệu lồng nhau phức tạp, góp phần ngăn ngừa lỗi và cải thiện khả năng đọc mã.

Bạn có thể làm theo bài viết trên bằng cách sử dụng Visual Studio Code trên kênh YouTube của chúng tôi. Vui lòng ghé thăm kênh YouTube.

YouTube Video