Используя синтаксис #, теперь мы можем создавать частные свойства в классах ES6 следующим образом:
class Person {
#name;
constructor(name) {
this.#name = name;
}
getName() { return this.#name; }
}
let ron = new Person('ron')
ron.#name // undefined
ron.getName(); // ron
Ранее, в ES5, частные свойства вряд ли можно было «подделать» следующим образом:
function Person(name) {
var name = name;
this.getName = function() {
return name;
}
}
(new Person('ron')).name // undefined
(new Person('ron')).getName() // ron
В приведенной выше версии используется тот факт, что «var» не будет принадлежать «this» экземпляров Person. Таким образом, используя силу «замыкания», getName получает доступ к «имени». Однако проблема в том, что this.getName() не является частью цепочки прототипов, поэтому, чтобы добавить getName в прототип, нам нужно будет сделать:
Person.prototype.getName = function() { return this.getName(); }
Что сбивает с толку и довольно плохо пахнет.
Другой вариант: (используя символы ES6 и все еще не используя классы)
function Person(name) {
const nameSymbol = Symbol();
this[nameSymbol] = name;
this.getName = function() {
return this[nameSymbol];
}
}
Но все еще не решает проблему, что getName не является частью прототипа. Другая проблема заключается в том, что с помощью Object.getOwnPropertySymbols этот «поддельный» частный член доступен.
Другой вариант es5 будет заключаться в использовании «шаблона модуля Revleaing» и предоставлении публичного API следующим образом:
const myEs5Module = (function () {
var _name = 'yos';
function getName() {
return _name;
}
const publicAPI = { getname };
return publicAPI;
})();
Но это не класс или функция-конструктор, это больше похоже на модуль.
Поэтому я хотел бы понять, является ли синтаксис '#' для частных свойств в классах ES6 синтаксическим сахаром и может ли он быть каким-то образом полифиллен для таких любителей функций, как я.
Кстати: я читал сообщения вроде следующего: Частные свойства в классах JavaScript ES6 и до сих пор чувствую себя неудовлетворенным. также ПРИМЕЧАНИЕ. Я не ищу модули ES6 / решение Babel.
Частные свойства являются полифидируемыми, но дело в том, что если вы зарегистрируете экземпляр класса в отладчике, вы можете увидеть даже его частные свойства.
@andymccullough - Раньше это было правдой, до частных свойств и методов, но теперь это не так.
@andymccullough Являются ли классы ES6 просто синтаксическим сахаром для прототипа шаблона в Javascript?
Являются ли частные свойства класса ES6 просто синтаксическим сахаром?
Нет. Они являются фундаментальным дополнением к тому, как объекты работают на внутреннем уровне. Частные поля (как они называются) хранятся в новых слотах в объекте, которых не было до предложения, и недоступны другими способами.
Поэтому я хотел бы понять, является ли синтаксис '#' для частных свойств в классах ES6 синтаксическим сахаром и может ли он быть каким-то образом полифиллен для таких любителей функций, как я.
Вы не можете использовать частные свойства без синтаксиса class. (Будущие предложения могут изменить это.) Вместо этого вам придется продолжать делать то, что вы делаете (решение закрытия), или использовать WeakMap только ваши функции имеют доступ к объекту, к которому относятся свойства.
Вы сделали свои собственные примеры закрытия, так что вот ваш класс Person, использующий подход WeakMap вместо частных свойств:
const Person = (() => {
const names = new WeakMap();
function Person(name) {
names.set(this, name);
}
Person.prototype.getName = function getName() {
return names.get(this);
};
return Person;
})();
let ron = new Person("ron")
console.info(ron.name); // undefined
console.info(ron.getName()); // "ron"
FWIW, я подробно рассматриваю частные поля (и некоторые другие class функции, которые, вероятно, перейдут на этап 4 ["завершенные"} в этом году) в моей недавней книге JavaScript: The New Toys в главе 18. Ссылки в моем профиле если вы заинтересованы.
Это очень полезный ответ и фантастический бонус к моему пониманию. Большое спасибо.
Я чувствую необходимость еще кое-что прояснить. Я вижу, вы использовали WeakMap с ключом this и значением name. так что каждый экземпляр будет иметь свое собственное «имя» по мере необходимости. Но как насчет: const Person = (() => { let _name = null; function Person(name) { _name = name; } Person.prototype.getName = function getName() { return _name; }; return Person; }) ; const PersonFactory = function(name) { const PersonMaker = Person(); вернуть новый PersonMaker (имя); }
Я предложил не IIFE, а просто функциональное выражение. Извините или форматирование кода, которое могло вас запутать. Я протестировал его, и он создает разных Мэри и Джо.
@EvaCohen - Извините, прочитал слишком быстро. Но это намного сложнее, чем вам нужно, и каждый раз, когда вы создаете экземпляр, создается совершенно новый Person (и Person.prototype), ничего не используя повторно. Вам лучше просто использовать функцию Person из второго блока кода в вашем вопросе и напрямую закрыть параметр.
Все, что связано с классами в JS, — это «синтаксический сахар»