zoukankan      html  css  js  c++  java
  • JS设计模式(一)-MODULE(模块模式)

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

    我们用立即执行函数(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的存在往往表明系统中的模块要么是系统紧密耦合,要么是其逻辑过于分散在代码库的多个部分中。

    ====================================
    ====================================

    模块是任何强大应用程序中不可或缺的一部分,它通常能帮助我们清晰地分离和组织项目中的代码单元。

    js中实现模块的方法:

    1. 对象字面量表示法
    2. Module模式
    3. AMD模块
    4. CommonJS模块
    5. ECMAScript Harmony 模块

    对象字面量

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

    var myModule = {
        myProperty:"someValue",
        myConfig:{
        useCaching:true,
        language:"en"
        },
        //基本方法
        myMethod:function(){
        //...
        },
        //根据当前配置输出信息
        myMethod2:function(){
            console.log("Caching is:"+(this.myConfing.useCaching) ? "enabled":"disabled");
        },
    
        //重写当前配置
        myMethod3:function(newConfig) {
        if(typeof newConfig ==="object"){
            this.myConfig = newConfig;
            console.log(this.myConfig.language);
            }
        },
    };
    myModule.myMethod3({
    language:"fr",
    usecaching:false
    })

    使用对象字面量有助于封装和组织代码。

    在javascript中,Module模式用于进一步模拟类的概念,通过这种方式,能够使一个单独的对象拥有公有/私有方法和变量,从而屏蔽来自全局作用域的特殊部分。

    module模式使用了闭包封装“私有”状态和组织。它提供了一种包装混合公有/私有方法和变量的方式,防止起泄露至全局作用域,并与别的开发人员的接口发生冲突。通过该模式,只需要返回一个公有的API,而其他的一切则都维持在私有闭包里。
    在module模式内,由于闭包的存在,声明变量和方法只在该模式内部可用,但在返回对象上定义的变量和方法,则对外部使用者都是可用的

    module模式的实现

    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();

    代码的其他部分是无法直接读取incrementCounter()和resetCounter()。counter变量实际上是完全与全局作用域隔离的,因此它表现的就像是一个私有变量,它的存在被局限于模块的闭包内,因为唯一能够访问其作用域的代码就是这两个函数。上述方法进行了有效的命名空间设置,所以在测试代码中,所有的调用都需要加上前缀。

    //包含命名空间、公有、和私有变量的Module模式
    var myNamspace = (function(){
        //私有计数器变量
        var myPrivateVar = 0;
    
        //记录素有参数的私有函数
        var myPrivateMethod = function(foo){
            console.log(foo);
        };
    
        return {
            //公有变量
            muPublicVar:"foo",
    
            //调用私有变量和方法的公有函数
            myPublicFunction:function(bar){
                myPrivateVar++;
                myPrivateMethod(bar);
            }
        }
    })();

    引用全局变量
    JavaScript有一个特性叫做隐式全局变量,不管一个变量有没有用过,JavaScript解释器反向遍历作用域链来查找整个变量的var声明,如果没有找到var,解释器则假定该变量是全局变量,如果该变量用于了赋值操作的话,之前如果不存在的话,解释器则会自动创建它,这就是说在匿名闭包里使用或创建全局变量非常容易,不过比较困难的是,代码比较难管理,尤其是阅读代码的人看着很多区分哪些变量是全局的,哪些是局部的。

    不过,好在在匿名函数里我们可以提供一个比较简单的替代方案,我们可以将全局变量当成一个参数传入到匿名函数然后使用,相比隐式全局变量,它又清晰又快,我们来看一个例子:

    //全局模块
    var myModule = (function(jQ,_){
    
        function privateMethod1(){
            jQ(".container").html(test);
        }
        return {
            publicMethod:function(){
                privateMethod1();
            }
        }
    })(jQuery,_);
    myModule.publicMethod();
    
    
    //全局模块
    var myModule = (function(){
    //模块对象
    var module = {};
    privateVariale = "Hello";
    
    function privateMethod(){
        //...
    }
    module.publicproperty = "Foobar";
    module.publiceMethod = function(){
    }   
    return module;
    })();

    声明全局变量,而不需要实现它们,并可以同样地支持全局引入的概念

    Module模式的还是存在一定的不足:
    1. 由于我们访问公有和私有成员的方式不同,当我们想改变可见性时,实际上我们必须修改每一个曾经使用过该成员的存在。
    2. 我们无法访问那些之后在方法里面添加的私有成员,
    3. 无法为私有成员创建自动化单元测试,bug需要修正补丁时会增加额外的复杂性。
    4. 开发人员无法轻易地扩展私有方法

    =======================================

  • 相关阅读:
    java面试系列<1>——java基础
    Netty 面试必备知识点
    Redis 面试必备知识点
    MySQL 面试必备知识点
    肝了一个半月的 Java 项目快速开发脚手架:Chewing
    线上BUG:MySQL死锁分析实战
    2021-07-01阅读小笔记:Spring ioc 之组件扫描
    2021-06-13:G1垃圾回收器
    Dubbo原理剖析 之 @DubboReference.version设置为*
    2021-04-09阅读小笔记:JDK8中的一等公民和Stream小概念
  • 原文地址:https://www.cnblogs.com/7qin/p/12670171.html
Copyright © 2011-2022 走看看