首先来看著名的 Brainjar.com 教程中的例子: function Browser() { var ua, s, i; this.isIE = false;
this.isNS = false;
this.version = null; ua = navigator.userAgent; s = "MSIE";
if ((i = ua.indexOf(s)) >= 0) {
this.isIE = true;
this.version = parseFloat(ua.substr(i + s.length));
return;
} s = "Netscape6/";
if ((i = ua.indexOf(s)) >= 0) {
this.isNS = true;
this.version = parseFloat(ua.substr(i + s.length));
return;
} // Treat any other "Gecko" browser as NS 6.1. s = "Gecko";
if ((i = ua.indexOf(s)) >= 0) {
this.isNS = true;
this.version = 6.1;
return;
}
}var browser = new Browser();
alert(browser.isIE); //如果是IE,弹出true
这段代码设计了一个Browser类,我们利用它的实例并调用其提供的一些属性来判断浏览器的类型和版本。这个设计有一个问题,那就是 Browser 可以用 new 操作符创建多个实例,但显然这是没有必要的。虽然多个Browser对象不会有什么损害,但有一些特殊情形下,我们也希望在js中实现 Singleton 模式。
解决方法很简单:
browser = new function () { var ua, s, i; this.isIE = false;
this.isNS = false;
this.version = null; ua = navigator.userAgent; s = "MSIE";
if ((i = ua.indexOf(s)) >= 0) {
this.isIE = true;
this.version = parseFloat(ua.substr(i + s.length));
return;
} s = "Netscape6/";
if ((i = ua.indexOf(s)) >= 0) {
this.isNS = true;
this.version = parseFloat(ua.substr(i + s.length));
return;
} // Treat any other "Gecko" browser as NS 6.1. s = "Gecko";
if ((i = ua.indexOf(s)) >= 0) {
this.isNS = true;
this.version = 6.1;
return;
}
};alert(browser.isIE); //如果是IE,弹出true
看到区别了吗,唯一的区别大概就是 new 操作符位置的变化。这其中的奥妙就是利用了 匿名构造器 函数。这得益于js: 构造器是一个函数,而函数也是一个对象 的特性。我们可以以下面的代码来理解:
Browser = function() {......};
var browser = new Browser();
window.Browser = void(0);
alert(browser.isIE);
也就是将构造器函数赋给一个临时变量,实例化一个对象后,再将构造器函数清除,这样也就无法再实例化一个Browser对象。
Singleton 对象在js中常用来实现一些工具类,类似于java中的由静态方法组成的类。Ajax类库中也有不少Singleton模式的应用,你可以在 Yahoo! User Interface Library 或者国内的 JSVM2 框架中找到很多类似的代码。
作为一个反例,大家也可以看看国内UML软件工程组织发表的文章:javascript设计模式交流(一) ——Singleton Pattern。文中对Singleton的实现很明显是模拟java的实现方式。我以为这样的实现是丑陋的。
我的真实目的,是想再次重申: javascript 是一门优秀的脚本语言,不要用Java的方式去编写javascript! 。很多时候这样的结果都是画蛇添足。