Ответ 1
У меня появился следующий шаблон для решения этой проблемы, по крайней мере, пока. То, что мне было нужно, - это привилегированный сеттер, так что частная переменная может быть изменена изнутри определенных функций прототипа, но не из другого места:
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 экземпляров объекта в цикле (обратите внимание, что объект, используемый для бенчмаркинга, более сложный, чем тот, который был выше, что было просто для упрощения):
ХРОМ:
Только закрытие - 2172 мс
Прототипирование (выше) - 822ms
Прототипирование (std way) - 751 мс
FIREFOX:
Только закрытие - 1528 мс
Прототипирование (выше) - 971 мс
Прототипирование (std way) - 752ms
Как вы можете видеть, этот метод почти такой же быстрый, как и обычное прототипирование, и, безусловно, быстрее, чем просто обычное закрытие, которое копирует функции вместе с экземпляром.