предисловие
Читая «Введение в ECMAScript 6», я увидел разбросанную реализацию приватных переменных, поэтому резюмирую статью здесь.
1. Соглашение
выполнить
class Example {
constructor() {
this._private = 'private';
}
getName() {
return this._private
}
}
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex._private); // private
преимущество
- Просто написать
- Легко отлаживать
- хорошая совместимость
недостаток
- Доступный извне и модифицируемый
- В языке нет механизма взаимодействия, например, оператор for in будет перечислять все атрибуты.
- конфликт имен
2. Закрытие
реализовать один
/**
* 实现一
*/
class Example {
constructor() {
var _private = '';
_private = 'private';
this.getName = function() {return _private}
}
}
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex._private); // undefined
преимущество
- Нет конфликтов имен
- Внешняя недоступность и модификация
недостаток
- Логика конструктора усложняется. Конструктор должен делать только инициализацию объекта, а вот для реализации приватных переменных нужно включать реализацию некоторых методов, да и организация кода немного неясна.
- Методы существуют в экземпляре, а не в прототипе, и подклассы не могут использовать super для их вызова.
- Сборка добавляет немного накладных расходов
реализация два
/**
* 实现二
*/
const Example = (function() {
var _private = '';
class Example {
constructor() {
_private = 'private';
}
getName() {
return _private;
}
}
return Example;
})();
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex._private); // undefined
преимущество
- Нет конфликтов имен
- Внешняя недоступность и модификация
недостаток
- Писать немного сложно
- Сборка добавляет немного накладных расходов
3. Symbol
выполнить
const Example = (function() {
var _private = Symbol('private');
class Example {
constructor() {
this[_private] = 'private';
}
getName() {
return this[_private];
}
}
return Example;
})();
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex.name); // undefined
преимущество
- Нет конфликтов имен
- Внешняя недоступность и модификация
- Нет штрафа за производительность
недостаток
- немного сложнее
- Совместимость тоже хорошая
4. WeakMap
выполнить
/**
* 实现一
*/
const _private = new WeakMap();
class Example {
constructor() {
_private.set(this, 'private');
}
getName() {
return _private.get(this);
}
}
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex.name); // undefined
Если вы напишите так, вам может показаться, что инкапсуляции недостаточно, вы также можете написать это так:
/**
* 实现二
*/
const Example = (function() {
var _private = new WeakMap(); // 私有成员存储容器
class Example {
constructor() {
_private.set(this, 'private');
}
getName() {
return _private.get(this);
}
}
return Example;
})();
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex.name); // undefined
преимущество
- Нет конфликтов имен
- Внешняя недоступность и модификация
недостаток
- Сложнее писать
- Совместимость немного проблематична
- Существует определенная стоимость производительности
5. Последние предложения
class Point {
#x;
#y;
constructor(x, y) {
this.#x = x;
this.#y = y;
}
equals(point) {
return this.#x === point.#x && this.#y === point.#y;
}
}
Так почему бы просто не использовать приватные поля напрямую? Например это:
class Foo {
private value;
equals(foo) {
return this.value === foo.value;
}
}
Проще говоря, это слишком хлопотно, и, конечно, есть соображения производительности...
Например, если вместо # использовать ключевое слово private:
class Foo {
private value = '1';
equals(foo) {
return this.value === foo.value;
}
}
var foo1 = new Foo();
var foo2 = new Foo();
console.log(foo1.equals(foo2));
Здесь мы создаем два новых экземпляра, а затем передаем foo2 в качестве параметра методу экземпляра foo1.
Итак, можем ли мы получить значение foo2.value? если мы напрямуюfoo2.value
Должно быть невозможно получить значение, в конце концов, это приватная переменная, но equals — это метод класса Foo, так можно ли его получить?
Ответ положительный.
На самом деле то же самое и в других языках, таких как Java и C++.Функции-члены класса могут обращаться к закрытым переменным экземпляра того же типа., это потому, что приватный предназначен для сокрытия "внешней" информации. Внутри самого класса нет необходимости запрещать доступ к приватным переменным. Вы также можете понять, что ограничение приватных переменных основано на классе, а не на объекте. Кроме того, это также может принести удобство пользователю.
Поскольку получить значение можно, напечатанный результат должен быть истинным, но что, если значение, которое мы передаем, является не экземпляром Foo, а другим объектом?
var foo1 = new Foo();
console.log(foo1.equals({
value: 2
}));
Конечно, код здесь также может работать нормально, но для компилятора это немного хлопотно, потому что компилятор не знает, является ли значение обычным атрибутом foo или приватным атрибутом, поэтому компилятору необходимо принять решение. , сначала оцените, не является ли foo экземпляром Foo, а затем перейдите к получению значения.
Это также означает, что такое суждение должно быть сделано для каждого доступа к атрибуту, и механизм был сильно оптимизирован для доступа к атрибуту, который слишком ленив для изменения, а также снижает скорость.
Но в дополнение к этой работе, есть некоторые другие вещи, которые следует учитывать, такие как:
- Вы должны закодировать закрытый ключ в каждую лексическую среду.
- Может для перебора этих свойств?
- Если частный атрибут имеет то же имя, что и обычный атрибут, кто кого заблокирует?
- Как предотвратить обнаружение имен частных свойств.
Более подробное обсуждение использования # вместо private может относиться к этомуIssue.
Конечно, эти проблемы можно решить, но это немного хлопотно.
И если вы выберете #, реализация вообще не будет иметь ничего общего со свойствами объекта JavaScript и будет использоватьprivate slots
Короче говоря, используя новый синтаксис поиска слотов, это будет намного проще, чем приватная реализация.
Ссылаться на
- «Как развиваются языки программирования — на примере JS Private» Хэ Шицзюнь
- Exploring ES6
- Новый синтаксис JS: частные свойства
серия ES6
Адрес каталога серии ES6:GitHub.com/ в настоящее время имеет бриз…
Ожидается, что в серии ES6 будет написано около 20 статей, направленных на углубление понимания некоторых точек знаний ES6, с акцентом на область действия на уровне блоков, шаблоны меток, функции стрелок, реализацию моделирования символов, наборов, карт и обещаний, схему загрузки модулей, асинхронность. обработка и т.п. содержание.
Если есть какие-либо ошибки или неточности, пожалуйста, поправьте меня, большое спасибо. Если вам нравится или у вас есть вдохновение, добро пожаловать в звезду, что также является поощрением для автора.