Я разработал следующую схему для решения этой проблемы, по крайней мере, на данный момент. Мне нужен был привилегированный установщик, чтобы частная переменная могла быть изменена изнутри определенных функций прототипа, но не из других мест:
var Foo = (function() {
// the bulk of the objects behavior goes here and is created once
var functions = {
update: function(a) {
a['privateVar'] = "Private variable set from the prototype";
}
};
// the objects prototype, also created once
var proto = {
Update: function() {
this.caller('update');
}
};
// special function to get private vars into scope
var hoist = function(accessor) {
return function(key) {
return functions[key](accessor());
}
}
// the constructor itself
var foo = function foo() {
var state = {
privateVar: "Private variable set in constructor",
// put more private vars here
}
this.caller = hoist(function(){
return state;
});
}
// assign the prototype
foo.prototype = proto;
// return the constructor
return foo;
})();
В основном указатель на внутреннее состояние объекта поднимается до его прототипа через замыкание над простой функцией доступа () {return state; }. Использование функции 'caller' в любом данном экземпляре позволяет вам вызывать функции, которые создаются только один раз, но все же могут ссылаться на приватное состояние, которое хранится в этом экземпляре. Также важно отметить, что никакие функции за пределами прототипа никогда не смогут получить доступ к привилегированному средству доступа, так как «вызывающий» принимает только ключ, который ссылается на предопределенные функции, которые находятся в области видимости.
Вот некоторые тесты этого метода, чтобы увидеть, как он сравнивается с чистым прототипированием. На этих рисунках показано создание 80 000 экземпляров объекта в цикле (обратите внимание, что объект, используемый для сравнительного анализа, является более сложным, чем приведенный выше, который был только для упрощения):
CHROME:
Только закрытие - 2172 мс
Прототипирование (вышеуказанный способ) - 822мс
Прототипирование (стандартный способ) - 751мс
FIREFOX:
Только закрытие - 1528 мс
Прототипирование (над способом) - 971мс
Прототипирование (стандартный способ) - 752 мс
Как видите, метод почти такой же быстрый, как и обычное прототипирование, и определенно быстрее, чем просто использование обычного замыкания, которое копирует функции вместе с экземпляром.