Чтобы расширить ответ @ 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
Scaped WeakMap
WeakMap может использоваться, чтобы избежать производительности предыдущего подхода и потери памяти. WeakMaps связывают данные с объектами (здесь, экземплярами) таким образом, что к ним можно получить доступ только с помощью этого WeakMap. Итак, мы используем метод переменных области видимости для создания приватного WeakMap, а затем используем этот WeakMap для извлечения приватных данных, связанных с this
. Это быстрее, чем метод переменных области видимости, потому что все ваши экземпляры могут совместно использовать один WeakMap, поэтому вам не нужно пересоздавать методы просто для того, чтобы они получили доступ к своим собственным WeakMaps.
Пример:
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
В этом примере объект используется для использования одного WeakMap для нескольких частных свойств; Вы также можете использовать несколько WeakMaps и использовать их как 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, до сих пор нет идеального способа сделать частную собственность. Различные подходы имеют свои плюсы и минусы. Переменные в области видимости являются действительно приватными; WeakMaps с областями видимости являются очень приватными и более практичными, чем переменные с областями видимости; Символы с определенной областью являются достаточно частными и достаточно практичными; подчеркивания часто бывают достаточно приватными и очень практичными.