13

本回内容介绍

上一回聊到JS中模拟接口,装饰者模式,掺元类,分析了backbone的继承源码,感觉还好吧!

介一回,偶们来聊一下在JS单例模式(singleton),单例模式其实运用很广泛,比如:jquery,AngularJS,underscore吖虾米的都是单例模式,来吧,直接开始咯:

1. 单例模式

保证一个类只有一个实例,从全局命名空间里提供一个唯一的访问点来访问该对象。其实之前写过的对象字面量也是一种简单单例,如下:

    var Singleton = {
        name: "飞狐",
        method: function () {
            return 'hello world';
        }
    };
    alert(Singleton.method());    // 返回hello world

这就是一个简单单例了,应该很多盆友已经看出来了,没有作用域,如果要扩展私有属性和方法的话,那么就可以靠闭包来实现。

2. 闭包单例模式

顾名思义要用到闭包,作为返回实例对象,如下:

    var Singleton = (function(){
        var name = '飞狐';    // 私有属性
        var nickname = '帅狐';
        var showNickname = function(){    // 私有方法
            return nickname;
        }
        return {    // 返回一个对象
            name:name,    // 将私有属性公开
            nickName: function(){    // 在公开的方法中返回私有方法
                return showNickname();
            }
        }
    })();
    alert(Singleton.name);    // 飞狐 
    alert(Singleton.nickName());    // 帅狐 

这里我们接着上边儿简单单例的例子来,稍微的改一下,改成闭包之后,就数据保证了不受外界干扰了。

3. 惰性单例模式

惰性单例就是只有在使用的时候才初始化,如下:

    var Singleton = (function(){
        var uniq;    // 私有变量,用来存放返回实例化对象的容器
        function init(){    // 初始化方法    
            var buildeList = function(){    // 私有方法
                // 下面这一堆就是创建一个有序列表,含有5个li
                var root = document.createElement('ol');
                document.body.appendChild(root);
                for(var i=0;i<5;i++){
                    var a = document.createElement('a');
                    a.innerHTML = '<a>帅狐</a>';
                    var li = document.createElement('li');
                    li.appendChild(a);
                    root.appendChild(li);
                }
            }
            
            return {    // 一样的闭包,暴露共有方法
                method:function(){
                    return buildeList();
                }
            };
        }
        
        return {
            // 这里就是实例化对象了
            getInstance:function(){
                // 这里的uniq为true的时候,或者可以写成 typeof uniq==='undefined'
                if(!uniq){
                    // 创建单例实例
                    uniq = init();
                }
                return uniq;
            }
        };
    })();
    
    Singleton.getInstance().method();    // 返回1.帅狐2.帅狐3.帅狐4.帅狐5.帅狐

这个例子就是惰性单例了,也就是说只有在用的时候才会去初始化方法,这样可以更省资源。

4. 分支单例模式

分支单例就很简单了,就是做程序分支的判断,利用分支来返回相应的实例,经常用于浏览器检测,直接看代码吧,如下:

    var ua  = window.navigator.userAgent.toLocaleLowerCase();
    var matchedRE = /iphone|android|symbianos|windows\sphone/g;
    var Singleton = (function() {
          var webUrl = 'web端url';
          var mobileUrl = '移动端url';
          return (matchedRE.test(ua))?mobileUrl:webUrl;
    })();
    // 如果是pc端返回就是web端url,如果是移动端就返回移动端url
    alert(Singleton); 

这个例子就是分支单例了,比较简单,这个例子也是模拟京东目前判断访问设备的代码。

装逼图
装个逼再说。刚看到一新闻,韩雪发微博称,因为自己修改的本月套餐,上月流量就清零了,并称:“我改这个月的和上个月有什么关系吗?我付了钱的,多余的流量凭什么你说清零就清零呢?这不是霸王条款吗?”,女神都忍受不了了,哈哈~~

这一回讲的内容不多,就一个单例模式,
下面的内容更简单,一道题。

5. 笔试题:判断字符串中出现次数最多的字母,返回该字母及其出现次数

    function calculate(str){
        //命名一个变量放置字母出现的最高次数并初始化为0
        var maxLength = 0;
        //命名一个变量放置结果输入 
        var result = '';
        //循环迭代开始,并判断字符串是否为空
        while(str != '' ){
            //将原始的字符串变量赋值给新变量
            var oldStr = str;
            //用字符串的substr的方法得到第一个字符(首字母)
            var getStr = str.substr(0,1);
            //执行一次全局替换
            eval("str = str.replace(/"+getStr+"/g,'')");
            //判断原始的字符串的长度减去替代后字符串长度是否大于之前出现的最大的字符串长度
            if(oldStr.length-str.length > maxLength ) {
                //两字符串长度相减得到最大的字符串长度
                maxLength = oldStr.length-str.length;
                //返回最大的字符串结果(字母、出现次数)
                result = "出现最多的字母是:" + getStr + "------出现了" + maxLength + " 次。";
            }
        }
        return result;
    }
    var str ="adadfdfseffserfefsefseeffffftsdg";
    alert(calculate(str)); 

这个题基本上我都写了注释,难度适中,当娱乐消遣。

这一回,主要聊了单例模式,应该很好理解,难度不大。
下一回,咱主要聊一聊工厂模式。

话说,看完文章觉得ok,客观点个赞呗,好东西多推荐推荐,让大家都知道,嘿嘿,好像有点那啥卖瓜了...


注:此系飞狐原创,转载请注明出处


飞狐
2.4k 声望1.4k 粉丝

专注AI量化,技术界最懂金融的CFA金融分析师