搜索
javascript - js单例模式
黄舟
黄舟 2017-04-10 15:45:25
[JavaScript讨论组]
            window.onload = function() {
                var Createp=function(html){
                    this.html=html;
                    this.init();
                }
                Createp.prototype.init=function(){
                    var p=document.createElement("p");
                    p.innerHTML=this.html;
                    document.body.appendChild(p);
                }
                
                //这个代理类为什么要用匿名函数自执行,写成普通函数为什么却没用?
                var ProxySingletonCreatep=(function(){
                    var instance;
                    return function(html){
                        if(!instance){
                            instance=new Createp(html);
                        }
                        return instance;
                    }
                })();
               
                var a=new ProxySingletonCreatep("sven1");
                var b=new ProxySingletonCreatep("sven2");
                alert(a===b);
            }
黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

全部回复(5)
迷茫

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

ringa_lee

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

大家讲道理

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

var ProxySingletonCreatep=(function(){
    var instance;
    return function(html){
        if(!instance){
            instance=new Createp(html);
        }
        return instance;
    }
})();
   
var a=new ProxySingletonCreatep("sven1");
var b=new ProxySingletonCreatep("sven2");
alert(a===b); //这里输出false

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

var ProxySingletonCreatep=(function(){
var instance;
return function(html){
    if(!instance){
        instance=new Createp(html);
    }
    return instance;
}
})();
var Createp = new ProxySingletonCreatep();   
var a= Createp ("sven1");
var b= Createp ("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 ProxySingletonCreatep=(function(){
    var instance;
    return function(html){
        if(!instance){
            instance=new Createp(html);
        }
        return instance;
    }
})();

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

function(html){
    if(!instance){
        instance=new Createp(html);
    }
    return instance;
}
即
var instance;
var ProxySingletonCreatep = function(html){
    if(!instance){
        instance=new Createp(html);
    }
    return instance;
}

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

以上

大家讲道理

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

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

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

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

window.onload = function(){
      window.onload = null;
      // initial code
};
伊谢尔伦

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

其实prototype应该也算是单实例

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号