JS设计模式(一)-MODULE(模块模式)

JavaScript模块是用于保持代码块之间相互独立而普遍使用的设计模式。对于熟悉面向对象语言的人来说,模块是JavaScript的"类"。在JavaScript中Module模式模拟了类的概念,用闭包封装了"私有"状态和方法。

Module(模块)模式

通常能够帮助我们清晰地分离和组织项目中的代码单元

js中实现模块的方法

1》对象字面量表示法

2》Module模式

3》AMD模式

4》CommonJS模块

5》ECMAScript Harmony模块

Module模式某种程度上是基于对象的字面量

9.2.1对象字面量

在对象字面量表示法中,一个对象被描述为一组包含在大括号{}中、以逗号分隔的name/value对。对象内的名称可以是字符串或标识符,后面跟着一个冒号。对象中最后的一个name/value对的后面不用加逗号,如果加逗号将会导致出错。

Var myObjectLiteral={

variableKey:variableValue;

functionKey:function(){

//

}

};

对象字面量不需要使用new运算符进行实例化,但不能用在一个语句的开头,因为开始的可能被解读为一个块的开始。在对象的外部,新成员可以使用如下赋值语句添加在字面量上,如:

myModule.property="some Value";

使用对象字面量有助于封装和组织代码,Module模式仍然使用对象字面量,但只是作为一个作用域函数的返回值。

复制代码

   var myModule={
        myProperty:"somevalue",
        //对象字面量可以包含属性和方法
        //例如,可以声明模块的配置对象
        myConfig:{
            useCaching:true,
            language:"en"
        },
        //基本方法
        myMethod:function(){
            console.log("myMethod");
        },
        //根据当前配置输出信息
        myMethod2:function(){
            console.log("caching is:" + (this.myConfig.useCaching) ? "enabled":"disabled");
        },
        //重写当前配置
        myMethod3:function(newConfig){
            if(typeof newConfig==="object"){
                this.myConfig=newConfig;
                console.log(this.myConfig.language);
            }
        }
    };
    myModule.myMethod();
    myModule.myMethod2();//打印出来的是enabled,没有加上前面的字符串
    myModule.myMethod3({
        language:"fr",
        useCaching:false
    });

复制代码

9.2.2Module(模块)模式

Module模式最初被定义为一种在传统软件工程中为类提供私有和公有封装的方法。

在js中,Module模式用于进一步模拟类的概念,通过这种方式,能够使一个单独的对象用于公有/私有方法和变量,从而屏蔽来自全局作用域的特殊部分。产生的结果是:函数名与在页面上其他脚本定义的函数冲突的可能性降低。

模块模式的模板

复制代码

var myNamespace=(function(){
    //私有计数器变量
    var myPrivateVar=0;
    //记录所有参数的私有函数
    var myPrivateMethod=function(foo){
        console.log(foo);
    }
    return{
        //公有变量
        myPublicVar:"foo",
        //调用私有变量和方法的公有函数
        myPublicFunction:function(bar){
            //增加私有计数器值
            myPrivateVar++;
            //传入bar调用私有方法
            myPrivateMethod(bar);
        }
    };
})();

复制代码

9.2.2.1 私有

Module模式使用闭包封装“私有”状态和组织。它提供了一种包装混合公有/私有方法和变量的方式,防止其泄露至全局作用域,并与别的开发人员的接口发生冲突。通过该模式,只需返回一个公有API,而其他的一切则都维持在私有闭包里 。

这为我们提供了一个屏蔽处理底层时间逻辑的整洁解决方案,同时只暴露一个接口供应用程序的其他部分使用。该模式除了返回一个对象而并不是函数之外,非常类似于一个立即调用的函数表达式。

应该指出的是,在js中没有正真意义上的“私有”,因为js没有访问修饰符,因此我们使用函数作用域来模拟这个概念。在Module模式内:闭包声明的变量和方法只在该模式内部可用。但在返回对象上定义的变量和方法,则对外部使用者都是可用的。

复制代码

    var basketModule=(function(){
        //私有
        var basket=[];
        function doSomethingPrivate(){
            console.log("private");
        }
        function doSomethingElsePrivate(){
            //
        }
        //返回一个暴露出的公有对象
        return{
            //添加item到购物车
            addItem:function(values){
                basket.push(values);
            },
            //获取购物车里的item数
            getItemCount:function(){
                return basket.length;
            },
            //私有函数的公有形式别名,
            // doSomething:doSomethingPrivate自动调用doSomethingPrivate函数
            doSomething:doSomethingPrivate,
            //获取购物车里所有item的价格总值
            getTotal:function(){
                var itemCount=this.getItemCount(),total=0;
                while(itemCount--){
                    total+=basket[itemCount].price;
                }
                return total;
            }
        };
    })();

    //basketModule返回了一个拥有公用API的对象
    basketModule.addItem({
        item:"bread",
        price: 0.5
    });
    basketModule.addItem({
        item:"butter",
        price:0.3
    });
    console.log(basketModule.getItemCount());
    console.log(basketModule.getTotal());
    //会打印一个private和一个undefined,原因不明
    console.log(basketModule.doSomething());
    console.log(basketModule.basket);

复制代码

 

basket模块的优点:

 

1》只有模块自身才能享有拥有私有函数的自由,因为它只会暴露我们输出的API。

 

2》鉴于函数往往已声明并命名,在试图找到哪些函数抛出异常时,这将使得在调试器中显示调用堆栈变得更容易。(没感觉)

 

3》根据环境,还可以让我们返回不同 的函数

 

9.2.2.3 示例

复制代码

    /**
     * counter的存在被局限在模块的闭包内,唯一能访问其作用域的代码是return中的2个函数
     */
    var testModule=(function(){
        var counter=0;
        return{
            incrementCounter:function(){
                return ++counter;
            },
            resetCounter:function(){
                console.log("counter value prior to reset "+counter);
                counter=0;
            }
        };
    })();
    //增加计数器
    testModule.incrementCounter();
    //检查并重置计数器
    testModule.resetCounter();

复制代码

 

复制代码

//引入混入
    var myModule=(function(jQ,_){
        function privateMethod1(){
            jQ(".container").html("test");
        }
        return{
            publicMethod:function(){
                privateMethod1();
            }
        };
    //引入JQuery和Underscore
    })(jQuery,_);

复制代码

 

我们用立即执行函数(Immediately-Invoked-Function-Expressions (IIFE)) 创建私有空间,防止其泄露全局作用域。其样子如下:

var myGirlfriend = (function() {

  // 定义私有变量或方法
  var name = '小郑';

  var _kiss = function() {
    console.log('吻');
  }

  var _smile = function() {
    console.log('微笑');
  }

  return {
    // 暴露给公有的变量或方法
    simle: _smile,
    name: name
  }

})();

console.log(myGirlfriend.name); 
myGirlfriend.simle();

console.log(myGirlfriend._simle);
console.log(myGirlfriend._kiss);

/**
 * 结果:
 *     小美
 *     微笑
 *     undefined
 *     undefined
*/

在Module模式内,由于闭包的存在,声明的变量和方法只在模式内部可用,但在返回的对象上定义的变量和方法,在对外部也可用。如上面例子:其他人可以知道我的女朋友的名字,也可以看到我女朋友微笑,但不可以吻我女朋友。

Module模式的优缺点:

优点:

  • 实现代码的封装模块化
  • 实现私有化变量和方法

缺点:

  • 无法应用私有变量,造成无法对私有变量进行单元测试
  • 当我们想改可见性时,实际上要修改每一个曾经使用过该成员的地方。

这里只举例了一种简单Module的设计模式,从Module模式上还衍生出Revealing Module(揭示模块)模式、Singleton(单例)模式。这些模式都很有使用价值,不同当我们的系统中出现了它们,则表示我们能需要评估我们的设计,例如Singleton的存在往往表明系统中的模块要么是系统紧密耦合,要么是其逻辑过于分散在代码库的多个部分中。



作者:内孤
链接:https://www.jianshu.com/p/03c5b939e5d4
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

你可能感兴趣的:(前端设计模式)