Вникаю в ООП JavaScript. Пытаюсь разобратся в создании обектов с приватными методами и свойствами.
В JavaScript можно создавать обьекты через new
function Constructor() {
var name = 'foo';
this.get_name = function() {
return name;
}
}
var foo = new Constructor();
А можно без
function ConstructorWithoutNew() {
var name = 'bar';
var that = {};
that.get_name = function() {
return name;
}
return that;
}
var bar = ConstructorWithoutNew();
Первый вопрос - есть ли принципиальная разница между этими подходами? При каких условиях стоит использовать тот или иной, или возможно есть третий, более универсальный/продуктивный/правильный?
Ответ
Разница этих подходов в том, что в первом случае активируются механизмы наследования в js, а во втором случае - используются механизмы утиной типизации.
При использовании второго способа не будет работать оператор instanceof - зато так можно "унаследоваться" от функции, чего нельзя нормально сделать с прототипами.
Но оба способа не являются идеальными - в каждом из них создается отдельный метод на каждый экземпляр объекта. При (ошибочной) попытке применить такой метод на "чужой" экземпляр объекта через call или apply возможны странные вещи, которые будут не сразу очевидны.
Поэтому самый современный способ создания приватный полей - через символы. Кратко: вызов Symbol("...") даст вам некоторый объект, который можно использовать в качестве имени поля, при этом повторный вызов функции Symbol даст уже новый объект. То есть, если "спрятать" символ - то и поле окажется приватным.
Вот пример, здесь символ "спрятан" при помощи паттерна "модуль":
var Constructor;
!function() {
var sName = Symbol("name")
Constructor = function Constructor() { }
Constructor.prototype[sName] = "foo"
Constructor.prototype.get_name = function() {
return this[sName];
}
}()
var foo = new Constructor();
Переменная sName не видна за пределами модуля - а потому и доступа к приватному полю name снаружи нет, хотя внутри модуля к нему обращаться довольно просто.
Поддерживаются символы на момент написания этого ответа, к сожалению, только Хромом и Огнелисом из основных браузеров. Но для других браузеров (IE) можно использовать полифил:
!function() {
if (typeof window.Symbol === "function") return;
var counter = 0;
window.Symbol = function (name) {
return "__" + name + "@" + ++counter;
}
}()
Такой символ не будет обладать большинством свойств "настоящих" символов - но для создания почти-приватных переменных вполне пойдет.
Комментариев нет:
Отправить комментарий