Щоб розгорнути відповідь на @ loganfsmyth:
Єдиними справді приватними даними у JavaScript все ще є змінні області. Ви не можете мати приватні властивості у розумінні властивостей, доступ до яких здійснюється внутрішньо так само, як до загальнодоступних ресурсів, але ви можете використовувати масштабовані змінні для зберігання приватних даних.
Обсяг змінних
Підхід тут полягає у використанні сфери функції конструктора, яка є приватною, для зберігання приватних даних. Щоб методи мали доступ до цих приватних даних, вони повинні бути створені і в конструкторі, тобто ви відтворюєте їх у кожному екземплярі. Це покарання за продуктивність та пам'ять, але деякі вважають, що покарання є прийнятним. Покарання можна уникнути за методи, які не потребують доступу до приватних даних, додавши їх до прототипу, як зазвичай.
Приклад:
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
Обсяг слабкої карти
Слабку карту можна використовувати, щоб уникнути продуктивності попереднього підходу та покарання пам’яті. WeakMaps пов'язує дані з Об'єктами (тут, екземпляри) таким чином, що до них можна отримати доступ лише за допомогою цього WeakMap. Отже, ми використовуємо метод масштабних змінних для створення приватного WeakMap, а потім використовуємо WeakMap для отримання приватних даних, пов’язаних із this
. Це швидше, ніж метод масштабних змінних, оскільки всі ваші екземпляри можуть спільно використовувати один WeakMap, тому вам не потрібно відтворювати методи лише для того, щоб вони отримували доступ до своїх власних слабких карт.
Приклад:
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
У цьому прикладі використовується Object для використання одного WeakMap для декількох приватних властивостей; ви також можете використовувати кілька слабких карт і використовувати їх на зразок age.set(this, 20)
, або написати невелику обгортку і використовувати її іншим способом, наприклад privateProps.set(this, 'age', 0)
.
Конфіденційність такого підходу теоретично може бути порушена підробкою глобальних WeakMap
об'єкта. При цьому, всі JavaScript можуть бути зламані гнучкими глобалами. Наш код вже побудований на припущенні, що цього не відбувається.
(Цей метод також можна виконати Map
, але WeakMap
краще, оскільки Map
він створить витоки пам'яті, якщо ви не дуже обережні, і для цього обидва не відрізняються.)
Напіввідповідь: Діапазон символів
Символ - це тип примітивного значення, яке може слугувати іменем властивості. Ви можете скористатися методом масштабної змінної для створення приватного символу, а потім зберегти приватні дані наthis[mySymbol]
.
Конфіденційність цього методу може бути порушена за допомогою Object.getOwnPropertySymbols
, але це зробити дещо незручно.
Приклад:
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)`.
Напіввідповідь: Підкреслення
Старий за замовчуванням, просто використовуйте загальнодоступну власність з префіксом підкреслення. Ця конвенція, хоч і не є приватною власністю, є достатньо розповсюдженою, тому вона робить хорошу роботу, повідомляючи, що читачі повинні ставитися до власності як до приватної, яка часто робить цю роботу. В обмін на цей проміжок часу ми отримуємо простіший для читання, простіший набір та швидший підхід.
Приклад:
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.
Висновок
Станом на ES2017, досі немає ідеального способу створення приватних об'єктів. У різних підходів є плюси і мінуси. Обчислені змінні дійсно є приватними; масштабні слабкі карти дуже приватні і практичніші, ніж масштабовані змінні; Символи в масштабі є досить приватними та досить практичними; Підкреслення часто є досить приватними та дуже практичними.