new
. Мы привыкли, что он создаёт объект с помощью конструктора, передавая ему аргументы. Но на самом деле результат может быть и иным: если в функции, используемой в качестве конструктора, вернуть какой-либо другой объект, то он-то и станет результатом всего выражения с оператором new
. Посмотрим на пример:function X(){}
function Y(){ return new X; }
var y = new Y;
alert(y instanceof Y); // false
alert(y instanceof X); // true
Этот приём, например, можно очень удобно использовать для того, что бы заставить IE работать, как это должен делать любой нормальный браузер, с объектом XMLHttpRequest без всяких заморочек с его ActiveX`овскими конструкторами:// Provide the XMLHttpRequest class for IE 5.x-6.x:
if (typeof XMLHttpRequest == "undefined")
/** @constructor */
XMLHttpRequest = function() {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
throw new TypeError( "This browser does not support XMLHttpRequest." )
};
- после этого можно работать с этим конструктором практически так же, как во всех остальных браузерах - FireFox`е, Safari, Opera`е и Chrom`е. Этот приём описан в Wikipedia.Обычно для реализации Singleton`а применяются специальные конструкции на основе методов и прочего. Но в JavaScript представляется намного более простым использование этой возможности так, что бы внешний интерфейс создания экземпляра вообще не отличался от возврата уже созданного предыдущими вызовами экземпляра.
Так может быть реализован и pattern "Singleton" на JavaScript:
/**
* @constructor
* @singleton
*/
function SingletonClass() {
if (arguments.callee.instance)
return arguments.callee.instance;
//...
return arguments.callee.instance = this;
}
Update №1 (18.01.2010)
Мне пришла в голову мысль о том, что не очень хорошо делать так, как я предложил в примере выше. Дело в том, что поле instance открыто для редактирования и внесения изменений и этот механизм из-за этого можно сломать. Конечно, вряд ли кто-то станет намеренно так поступать, но лучше всё-таки не оставлять такой возможности.
Так что сейчас я оформляю Singleton`ы несколько подругому:
/**
* @constructor
* @singleton
*/
var SingletonConstructor;
(function() {
var /** @type {SingletonConstructor} */ instance;
SingletonConstructor = function() {
if (typeof instance !== 'undefined')
return instance;
//...
return instance = this;
};
})();
2 комментария:
А можно обойтись и без паразитных глобальных переменных:
function CEventController() {
var instance;
var actionCounter;
if (!instance)
instance = this;
this.stopActions = function() {
this.actionCounter++;
}
this.continueActions = function() {
this.actionCounter--;
}
this.isStopped = function() {
return this.actionCounter!=0 ? true : false;
}
this.getCounter = function() {
return this.actionCounter;
}
return instance;
}
И вызывать соответственно:
CEventController().stopActions();
alert(CEventController().getCounter());
Неправильно я написал. Там создаются куча клонов объекта. В идеале: http://bitari.blogspot.com/2006/07/js-singleton_22.html
Отправить комментарий