Để mở rộng câu trả lời của @ loganfsmyth:
Dữ liệu thực sự riêng tư duy nhất trong JavaScript vẫn là các biến có phạm vi. Bạn không thể có các thuộc tính riêng theo nghĩa các thuộc tính được truy cập bên trong giống như các thuộc tính công cộng, nhưng bạn có thể sử dụng các biến có phạm vi để lưu trữ dữ liệu riêng tư.
Biến phạm vi
Cách tiếp cận ở đây là sử dụng phạm vi của hàm xây dựng, là riêng tư, để lưu trữ dữ liệu riêng tư. Để các phương thức có quyền truy cập vào dữ liệu riêng tư này, chúng cũng phải được tạo trong hàm tạo, nghĩa là bạn đang tạo lại chúng với mọi trường hợp. Đây là một hình phạt hiệu suất và bộ nhớ, nhưng một số người tin rằng hình phạt là chấp nhận được. Có thể tránh bị phạt đối với các phương thức không cần truy cập vào dữ liệu riêng tư bằng cách thêm chúng vào nguyên mẫu như bình thường.
Thí dụ:
function Person(name) {
let age = 20; // this is private
this.name = name; // this is public
this.greet = function () {
// here we can access both name and age
console.log(`name: ${this.name}, age: ${age}`);
};
}
let joe = new Person('Joe');
joe.greet();
// here we can access name but not age
WeakMap phạm vi
WeakMap có thể được sử dụng để tránh hiệu suất và hình phạt bộ nhớ của phương pháp tiếp cận trước đó. WeakMaps liên kết dữ liệu với các Đối tượng (ở đây, ví dụ) theo cách mà nó chỉ có thể được truy cập bằng WeakMap đó. Vì vậy, chúng tôi sử dụng phương thức biến phạm vi để tạo WeakMap riêng tư, sau đó sử dụng WeakMap đó để truy xuất dữ liệu riêng tư được liên kết với this
. Phương pháp này nhanh hơn phương thức biến trong phạm vi bởi vì tất cả các phiên bản của bạn có thể chia sẻ một WeakMap duy nhất, vì vậy bạn không cần phải tạo lại các phương thức chỉ để chúng truy cập vào WeakMaps của riêng chúng.
Thí dụ:
let Person = (function () {
let privateProps = new WeakMap();
class Person {
constructor(name) {
this.name = name; // this is public
privateProps.set(this, {age: 20}); // this is private
}
greet() {
// Here we can access both name and age
console.log(`name: ${this.name}, age: ${privateProps.get(this).age}`);
}
}
return Person;
})();
let joe = new Person('Joe');
joe.greet();
// here we can access joe's name but not age
Ví dụ này sử dụng một Object để sử dụng một WeakMap cho nhiều thuộc tính riêng tư; bạn cũng có thể sử dụng nhiều WeakMaps và sử dụng chúng như age.set(this, 20)
, hoặc viết một trình bao bọc nhỏ và sử dụng nó theo cách khác, như thế nào privateProps.set(this, 'age', 0)
.
Sự riêng tư của phương pháp này về mặt lý thuyết có thể bị phá vỡ bằng cách giả mạo WeakMap
đối tượng toàn cầu . Điều đó nói rằng, tất cả JavaScript có thể bị phá vỡ bởi toàn cầu. Mã của chúng tôi đã được xây dựng dựa trên giả định rằng điều này không xảy ra.
(Phương pháp này cũng có thể được thực hiện với Map
, nhưng WeakMap
tốt hơn vì Map
sẽ tạo ra rò rỉ bộ nhớ trừ khi bạn rất cẩn thận và vì mục đích này, hai phương thức này không khác nhau.)
Nửa câu trả lời: Biểu tượng có phạm vi
Biểu tượng là một loại giá trị nguyên thủy có thể dùng làm tên thuộc tính. Bạn có thể sử dụng phương pháp biến phạm vi để tạo Biểu tượng riêng, sau đó lưu trữ dữ liệu riêng tư tại this[mySymbol]
.
Quyền riêng tư của phương pháp này có thể bị vi phạm bằng cách sử dụng Object.getOwnPropertySymbols
, nhưng hơi khó thực hiện.
Thí dụ:
let Person = (function () {
let ageKey = Symbol();
class Person {
constructor(name) {
this.name = name; // this is public
this[ageKey] = 20; // this is intended to be private
}
greet() {
// Here we can access both name and age
console.log(`name: ${this.name}, age: ${this[ageKey]}`);
}
}
return Person;
})();
let joe = new Person('Joe');
joe.greet();
// Here we can access joe's name and, with a little effort, age. ageKey is
// not in scope, but we can obtain it by listing all Symbol properties on
// joe with `Object.getOwnPropertySymbols(joe)`.
Nửa câu trả lời: Dấu gạch dưới
Mặc định cũ, chỉ sử dụng một tài sản công cộng có tiền tố gạch dưới. Mặc dù không phải là một tài sản riêng dưới bất kỳ hình thức nào, nhưng quy ước này đủ phổ biến để thực hiện tốt công việc truyền thông rằng độc giả nên coi tài sản là riêng tư, thường hoàn thành công việc. Để đổi lấy sự sai sót này, chúng ta có một cách tiếp cận dễ đọc hơn, dễ gõ hơn và nhanh hơn.
Thí dụ:
class Person {
constructor(name) {
this.name = name; // this is public
this._age = 20; // this is intended to be private
}
greet() {
// Here we can access both name and age
console.log(`name: ${this.name}, age: ${this._age}`);
}
}
let joe = new Person('Joe');
joe.greet();
// Here we can access both joe's name and age. But we know we aren't
// supposed to access his age, which just might stop us.
Phần kết luận
Kể từ ES2017, vẫn không có cách hoàn hảo để làm tài sản riêng. Phương pháp khác nhau có ưu và nhược điểm. Các biến phạm vi là thực sự riêng tư; WeakMaps có phạm vi rất riêng tư và thực tế hơn các biến có phạm vi; Biểu tượng phạm vi là hợp lý riêng tư và thực tế hợp lý; dấu gạch dưới thường đủ riêng tư và rất thực tế.