Привет!
За последние 10 лет(С днем рождения, prototype.js!) было написано очень много библиотек для эмуляции полноценного ООП в javascript.
Все они, так или иначе, решали задачу реализации приватных членов класса.
Копьев сломано много и в итоге разработчики разделились на 2 части:
Первая прячет приватные свойства в scope конструктора и отказывается от использования прототипов(создает методы для каждого экземпляра объекта заново), вторая просто использует соглашение в именах вроде "_privateProperty" и по сути никак не инкапсулирует данные.
Теория:
Ключевое слово new позволяет вызвать функцию таким образом что внутри нее this будет равен пустому объекту с методами прототипа. Таким образом, внутри конструктора можно сформировать объект который вернется из конструктора без явного указания return.
var Animal = function(name){
this._privateName = name;
};
Animal.prototype.getName = function(){
return this._privateName;
};
var a = new Animal('Cow');
a._privateName === a.getName(); /* true */
Но если функция вызванная с new явно возвращает любое значение отличное от примитивных типов(строки, числа, NaN и.т.д) то именно этот результат и вернется при том что внутри конструктора через this будет доступен все тот же пустой объект и методы из прототипа.
Практика:
Если принять то что все свойства this приватные а публичные мы возвращаем явно, то получается изящная эмуляция приватных свойств:
var Animal = function(name){
var self = this;
this._privateName = name;
return {
hello: Animal.prototype.hello.bind(this)
};
};
Animal.prototype.getName = function(){
return this._privateName;
};
Animal.prototype.hello = function(){
return 'hello ' + this.getName();
};
var a = new Animal('Cow');
a._privateName; /* undefined */
a.getName(); /* Exception */
a.hello(); /* hello Cow */
Для примера я написал простую функцию которая «оборачивает» конструктор и прячет приватные методы из прототипа:
github.com/poluyanov/privatize/blob/master/privatize.js
Плюсы:
- Основной плюс подобного подхода в том что на большом количестве объектов работа с прототипами и их методами изначально быстрее чем традиционное создание методов на каждый экземпляр объекта: jsperf.com/scopevsprototype
- Иногда может быть удобно динамически оверрайдить методы прототипа для ряда объектов.
- Внутри прототипа можно скрыть(По настоящему!) общие поля для множества объектов(Например счетчики).
Минусы:
- Поскольку функция конструктор возвращает простой объект, не работает instanceof;
- Такой подход для некоторых может казаться неявным и неочевидным.
Способ не претендует на новаторство и возможно вы в своей работе часто пользуетесь таким подходом. Буду рад вашим комментариям.
Автор: poluyanov