Понадобился нам в нашем js-сценарии, допустим, Singleton. Ну, мы берём и делаем, как все взрослые дяди:
/** * @class MyClass * @property {String} x * @property {String} y */ function MyClass() { this.x = "x"; this.y = "y"; } MyClass.prototype = {/* ... */}; /** * Get instance of singleton * * @static * @return {MyClass} */ MyClass.getInstance = function () { if (!this.instance) { this.instance = new this(); } return this.instance; }; var instance1 = MyClass.getInstance(), instance2 = MyClass.getInstance(); instance1 == instance2; // true |
Но, ведь, JavaScript идеальный язык для того, чтобы сделать какое-нибудь извращение. Грех такой шанс упустить.
Что происходит при выполнении new MyClass()
? Создаётся пустой объект, ему в прототипы назначается MyClass.prototype
, в его контексте вызывается MyClass()
и после всего этого он же возвращается в качестве результата выражения. Всем известные факты.
Однако, если конструктор возвращает через return любой объект, то именно он, а не this
будет результатом new
. Воспользуемся этим:
function MyClass() { var callee = arguments.callee; if (!callee.instance) { callee.instance = { 'x': "x", 'y': "y" }; } return callee.instance; } var instance1 = new MyClass(), instance2 = new MyClass(); instance1 == instance2; // true |
Теперь не нужно никаких getInstance()
. Просто создаём объекты через new
и каждый раз получаем одно и то же.
Заодно избавились от проблемы первого варианта: можно было создать объект напрямую в обход getInstance()
(конструктор то в JavaScript не сделать private
).
Особые параноики видят ещё одну проблему: ручная замена MyClass.instance
. Но и здесь у извращенцев есть ответ:
var MyClass = (function () { var instance; return (function () { if (!instance) { instance = { 'x': "x", 'y': "y" }; } return instance; }); }()); |
Как и всегда, JavaScript позволяет нам делать стандартные вещи с одной стороны намного проще, а с другой так, что никто из читающих этот код, нихрена не поймёт.
это все прекрасно пока не возникнет желания посмотреть инстанс
var myObj = new MyClass();
console.log(myObj instanceof MyClass); // false
CTAPbIu_MABP, 25.02.2013, 9:05
CTAPbIu_MABP, тогда чуть иначе:
vasa_c, 25.02.2013, 11:20
Здравствуйте, arguments.callee — устаревшее свойство, используйте
var MyClass = function() {
if (MyClass.prototype._singletonInstance) {
return MyClass.prototype._singletonInstance;
}
MyClass.prototype._singletonInstance = this;
};
Александр, 11.12.2013, 18:49
Да, Александр, спасибо.
Но зачем прототип замусоривать?
vasa_c, 11.12.2013, 21:57