JavaScript常用设计模式

作者: oldSix_Zhu | 来源:发表于2017-03-18 11:12 被阅读238次

    设计模式有很多,不定时更新
    这只是在下的一点浅见,若有不妥,请多指教
    目录:
    1.沙箱模式(模块模式/Module模式)
    1.2 立即执行函数表达式(IIFE)
    2.监听者模式
    3.严格模式

    1.沙箱模式(模块模式/Module模式)

    什么是沙箱模式?
    做iOS开发的都知道,每一个app都有一个沙盒,保存的是这个app的数据,外界其他的app是访问不到的,这样就很安全,隐私.
    沙箱模式就是为了达到类似这样的目的产生的
    ----沙箱模式不会在外界暴露任何的全局变量,也就减少了全局变量重名的情况,不会造成全局变量污染
    ----沙箱中的所有数据,都是和外界完全隔离的,外界无法对其进行修改,达到安全的目的

    如何实现沙箱模式?
    利用函数可以构建作用域,其上级作用域不能直接访问下级作用域中的数据的特点
    具体是用立即执行函数表达式(IIFE: Immediately Invoked Function Expression)

    先看一个简单的例子:

    <script>
        //普通模式1
        var num1 = 0;
        for(var i = 1;i <= 100; i++)
        {
            num1 += i;
        }
        console.log(num1);//5050
    
        //普通模式2
        function test() {
            var num2 = 0;
            for(var i = 1;i <= 100; i++)
            {
                num2 += i;
            }
            console.log(num2);//5050
        }
        test();
    
        //沙箱模式
        (function () {
            var num3 = 0;
            for(var i = 1;i <= 100; i++)
            {
                num3 += i;
            }
            console.log(num3);//5050
        })();
    
        console.log(num1);//还可以打印5050
        console.log(num2);//爆红,num2 is not defined
        console.log(num3);//爆红,num3 is not defined
    </script>
    

    ----从这个例子可以看出沙箱模式的简单写法就是用一个IIFE把代码包起来即可
    ----相比于第一种写法,沙箱模式写法省了两个全局变量名( num1 与 i )和一个全局函数名( test )
    ----相比于第二种写法,功能是相同的,但省了一个全局函数名( test )

    沙箱模式一般用在哪里?
    1.我们自己可以书写功能独立的一些组件
    (例如自己封装的js函数,在一个.js文件中,按照沙箱模式用一个立即执行函数包起来即可)
    2.还可以应用在书写第三方框架,或者为第三方框架书写插件
    (例如把jQuery对象代替window传进去就可以)
    可以保证自己内部的成员变量不被外界修改

    jQuery中的沙箱模式

    1 2

    jQuery中的沙箱模式是这样实现的:

        //jQuery中的沙箱模式
        (function (w) {
            var Cat = {
                eat:function () {
                    console.log("吃");
                }
            }
            w.cat = w.$ = Cat;
        })(window)
    
        window.cat.eat();//吃
        window.$.eat();//吃
        cat.eat();//吃
        $.eat();//吃
    

    还有一种写法:

        //第二种写法
        (function () {
            var Cat = {
                eat:function () {
                    console.log("吃");
                }
            }
            window.cat = window.$ = Cat;
        })()
    
        window.cat.eat();//吃
        window.$.eat();//吃
        cat.eat();//吃
        $.eat();//吃
    

    这两种写法都是给window增加了一个cat和$的属性,并指向同一个对象Cat

    实际上第二种写法与第一种写法没有用法上的区别,只是逻辑上,概念上的区别,
    意思是我们没有直接用外界的window全局对象,而是使用自己的形参w,
    只不过在调用的时候把window作为实参传了进来,
    实现了沙箱模式逻辑上与外界隔绝

    在我们使用的时候,
    如果我们需要对外界暴露一些属性或者方法,
    就可以将这些属性或者方法添加到window全局对象上,
    但是这个全局对象不可直接引用,因为引用会破坏沙箱原则,
    所以我们用传参的形式把window对象传入沙箱内,
    此时沙箱内使用window对象的时候,不会再去全局搜索window对象,
    而是使用的沙箱内部定义的形参

    1.2 立即执行函数表达式(IIFE: Immediately Invoked Function Expression)

    稍微写一点IIFE
    立即执行函数表达式也叫自调用匿名函数
    特点是没有函数名,在页面加载完成时就执行一次,且内部的变量不会被外界访问到,正好符合沙箱模式

    (function(){})();
    (function(){}());
    是两种JavaScript立即执行函数的常见写法

        <script>
            
            (function (w) {
                console.log(w);
            })("哈哈哈");
            
            (function (w) {
                console.log(w);
            }("哈哈哈"));
            
            //不用括号()也可以
            //比如+ - ! 等等其他奇葩符号,不过没人会这么用吧...
            !function (w) {
                console.log(w);
            }("哈哈哈");
    
            //三者都是打印哈哈哈
        </script>
    

    不多写了,可以看看其他人的文章
    <a href="http://www.jianshu.com/p/05ab2eacd11b">js中(function(){…})()立即执行函数写法理解</a>
    <a href="http://www.jianshu.com/p/5b5de313015c">JavaScript IIFE</a>


    2.监听者模式

    和OC中的通知一样,类似于广播,通常用来处理一对多的关系

    主要实现方式为:
    设置一个监听者(对象),维护一个听众队列(对象数组),监听一个事件(函数)
    当事件发生时,告知所有的听众,听众各自做出反应,
    一个听众可以理解为是一个回调,告知听众即执行回调

    先看个基本的实现:

    <script>
        // 监听者
        var jianTingZhe = {
            // 听众列表
            listeners: [],
            // 此事件触发时,告知所有的听众执行方法
            sing: function() {
                this.listeners.forEach( function( listen ) {
                    listen();
                });
            }
        }
    
        jianTingZhe.listeners.push( function() {
            console.log( '你问~我爱~你有~多深~' );
        } );
        jianTingZhe.listeners.push( function() {
            console.log( '我爱~你有~几分~' );
        } );
        jianTingZhe.listeners.push( function() {
            console.log( '月亮代表我的心' );
        } );
        // 触发事件,开始唱歌
        jianTingZhe.sing();
    
        //打印
        //你问~我爱~你有~多深~
        //我爱~你有~几分~
        //月亮代表我的心
    </script>
    

    再看一个与沙箱模式结合的例子:

    <script>
        // 监听者
        var jianTingZhe = {
            // 听众列表
            listeners: {
                listener1: [],
                listener2: [],
                listener3: []
            },
    
            // sing1触发时,告知所有监听sing1的听众
            sing1: function() {
                this.listeners.listener1.forEach( function( listen ) {
                    listen();
                });
            },
    
            // sing2触发时,告知所有监听sing2的听众
            sing2: function() {
                this.listeners.listener2.forEach( function( listen ) {
                    listen();
                });
            },
    
            // sing3触发时,告知所有监听sing3的听众
            sing3: function() {
                this.listeners.listener3.forEach( function( listen ) {
                    listen();
                });
            }
        };
    
        // 这是一个模块,整体可以认为是一个听众监听三个事件
        (function( w ) {
            // sing1听众
            jianTingZhe.listeners.listener1.push( function() {
                console.log( '你问~我爱~你有~多深~' );
            } );
            jianTingZhe.listeners.listener1.push( function() {
                console.log( '我爱~你有~几分~' );
            } );
            jianTingZhe.listeners.listener1.push( function() {
                console.log( '月亮代表我的心~' );
            } );
    
            // sing2听众
            jianTingZhe.listeners.listener2.push( function() {
                console.log( '今夜还吹着风~想起你好温柔~' );
            });
            jianTingZhe.listeners.listener2.push( function() {
                console.log( '有你的日子分外~的轻松~' );
            });
    
            // sing3听众
            jianTingZhe.listeners.listener3.push( function() {
                console.log( '因为爱情~不会轻易悲伤~' );
            });
        }( window ));
    
        // 这是另一个模块,整体可以认为是一个听众
        (function( w ) {
            // sing3听众
            jianTingZhe.listeners.listener3.push( function() {
                console.log( '所以一切都是幸福的模样~' );
            });
        }( window ));
    
        jianTingZhe.sing1();
        jianTingZhe.sing2();
        jianTingZhe.sing3();
        
        //打印
        //你问~我爱~你有~多深~
        //我爱~你有~几分~
        //月亮代表我的心~
        //今夜还吹着风~想起你好温柔~
        //有你的日子分外~的轻松~
        //因为爱情~不会轻易悲伤~
        //所以一切都是幸福的模样~
    </script>
    

    3.严格模式

    我们都知道JS的语法是很松散的,怎么写都对😂,
    比如函数后面没有;也可以执行
    而严格模式是在ES5出现的,只要启用了严格模式,JS的语法就会变得规范,写得不规范会警告报错等

    严格模式可以消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
    消除代码运行的一些不安全之处,保证代码运行的安全;
    增加运行速度;

    用法:
    在.js文件中,若要使用严格模式,则写一行'use strict'
    就会告诉解析器下面的代码就必须规范了,要按照ES5以上来解析

    例如保留字:
    一旦出现Unexpected strict mode reserved word这样的错误说明你用保留字做了参数名了
    es6-->implements, interface, let, package, private, protected, public, static, yield
    es5-->class, enum, export, extends, import, super

    再例如.js中以下代码:

    'use strict'
    a=123;
    

    运行后会报错a没有被定义,而没有声明严格模式则不会报错


    其他设计模式

    比如工厂模式在我之前文章里写过了,就不再写了
    JS函数的4种调用模式
    还有很多不定时更新吧(∩_∩)

    相关文章

      网友评论

        本文标题:JavaScript常用设计模式

        本文链接:https://www.haomeiwen.com/subject/zspjnttx.html