js单例模式



 window.onload = function() {
                var CreateDiv=function(html){
                    this.html=html;
                    this.init();
                }
                CreateDiv.prototype.init=function(){
                    var div=document.createElement("div");
                    div.innerHTML=this.html;
                    document.body.appendChild(div);
                }

                //这个代理类为什么要用匿名函数自执行,写成普通函数为什么却没用?
                var ProxySingletonCreateDiv=(function(){
                    var instance;
                    return function(html){
                        if(!instance){
                            instance=new CreateDiv(html);
                        }
                        return instance;
                    }
                })();

                var a=new ProxySingletonCreateDiv("sven1");
                var b=new ProxySingletonCreateDiv("sven2");
                alert(a===b);
            }

jquer javascript闭包 JavaScript javascript面向对象

喵喵D狗狗 9 years, 3 months ago

返回的函数里面的instance始终指向内部的那个变量==

其实prototype应该也算是单实例

不撸是傻子 answered 9 years, 3 months ago

代理是单例模式,,作用是只创建一次节点,避免多次创建节点。如 a b 跳过用户代理,就会创建出两个 DIV。

可以达到同样效果的办法是:

  1. 不用代理:把单例直接写在 onload 回调里,但题主之代码其实还有单一职责之意

  2. 不用单例: onload 里将其重新设为 null ,也能避免重复创建的可能性。如下:


 window.onload = function(){
      window.onload = null;
      // initial code
};

sh003 answered 9 years, 3 months ago

首先按照LZ说的把自执行去掉改成普通Function的闭包


 var ProxySingletonCreateDiv=(function(){
    var instance;
    return function(html){
        if(!instance){
            instance=new CreateDiv(html);
        }
        return instance;
    }
})();

var a=new ProxySingletonCreateDiv("sven1");
var b=new ProxySingletonCreateDiv("sven2");
alert(a===b); //这里输出false

好,false显然不能满足单例的要求,我们要把代码改成如下才能实现单例


 var ProxySingletonCreateDiv=(function(){
var instance;
return function(html){
    if(!instance){
        instance=new CreateDiv(html);
    }
    return instance;
}
})();
var CreateDiv = new ProxySingletonCreateDiv();   
var a= CreateDiv ("sven1");
var b= CreateDiv ("sven2");
alert(a===b); //这回输出了true 实现了单例

所以这里就有个问题,不使用自执行的方式实现单例就显得不够优雅。再解释区别之前,我们先来说说,用new来初始化一个function和直接调用一个function的区别。来看看下面的例子。


 function A(){
    this.user = {"name":"helloA"};
    return this.user.name;
}
function B(){
    this.user = {"name":"helloB"};
    return this.user;
}
function C(){
    this.user = {"name":"helloC"};;
    return function(){
        return this.user;
    };
}

var a = new A();
console.log(a); //打印出完整的a对象,由于return是个字符串,被直接无视了
var a1 = A();
console.log(a1); //打印出helloA,这个很正常
var b = new B();
console.log(b); //打印出user对象{"name","helloB"},return的值因为是个对象,没有被无视,这点和function A不同
var c = new C();
console.log(c); //打印出return的 anonymous function,也没有被无视,和function A 不同

通过上面的例子我们可以看出,使用new关键字初始化的function会返回this对象,而无视return的值,除非 return的是一个对象,或者function 。 而直接使用Function()方式则直接返回return的值。
好了,讲到这里一些朋友可能已经看出题主的问题关键之所在了,他不是在问闭包的问题,而是new关键字的问题。


 var ProxySingletonCreateDiv=(function(){
    var instance;
    return function(html){
        if(!instance){
            instance=new CreateDiv(html);
        }
        return instance;
    }
})();

当我们使用自执行方式的时候其实 var ProxySingletonCreateDiv这个变量已经指向了这个自执行匿名函数的return值,也就是另外一个匿名函数


 function(html){
    if(!instance){
        instance=new CreateDiv(html);
    }
    return instance;
}
即
var instance;
var ProxySingletonCreateDiv = function(html){
    if(!instance){
        instance=new CreateDiv(html);
    }
    return instance;
}

所以,再后面的2次new关键字的使用,其实你new的是上面这个return的匿名函数,由于这个匿名函数本身是return的是一个实例,所以你使用了new关键字也不会影响到它的返回(参见上面的function C()例子 )。因为instance这个变量是闭包的,可以保证自己的状态而不被回收,闭包这个就不用我多解释了,大家都懂得。

以上

我是魔法师 answered 9 years, 3 months ago

其实清楚了闭包的特性就会明白为什么了。
当一个函数返回它内部定义的一个函数时,就产生了一个闭包, 闭包包括了被返回的函数以及这个函数的定义环境
题主例子中的 匿名函数 自执行后, ProxySingletonCreateDiv 匿名函数 内的局部变量 instance 就是一个闭包,相当于 instance 并没有随着 匿名函数 自执行后而释放。
在还没有调用 ProxySingletonCreateDiv 时,变量 instance undefined
当第一次调用 ProxySingletonCreateDiv 时,由于 if 语句为 true ,变量 instance 被赋值为了 CreateDiv 的一个对象。
当第二次调用 ProxySingletonCreateDiv 时,由于 if 语句为 false ,变量 instance 不会再被赋值,还是第一次调用后的值。

tq00x08 answered 9 years, 3 months ago

这个匿名函数形成了一个闭包,单例对象instance会保存在这个闭包中,防止它不会被回收掉

白色的卡妙 answered 9 years, 3 months ago

Your Answer