深入学习javascript--Module模式

  Module模式体现了js的封装性,把内部细节对外部隐藏,暴露出公共接口给调用者去调用。分为两种方式–字面量表示法和module模式,module是字面量的高级表现形式。

  本文以module模式提出者的一篇文章 《A JavaScript Module Pattern》【我看不懂你们看着办】为蓝本,参考胖大叔版本的译文以及刘卿版本译文,对文内提及的各个方法进行更加细致的深入,每个例子均可运行在webkit内核的chrome中,其他浏览器未测。

对象字面量表示法

  一个模块等于一个花括号{}包含的对象集合,每个对象以冒号分隔属性值、逗号结尾,否则出现错误。单一属性直接以逗号结尾;多属性以花括号{}包裹,采用键值对形式书写。
  Error : Uncaught SyntaxError: Unexpected identifier

  •   个人理解:
   var  Module = {
        myProperty : "zjfirst",
        myConfig : {
            name : "552378416",
            password :"zxc456."
        },
        myMethod : function(){
            console.log("in love");
        }
    }
    console.log(Module.myProperty); 
    console.log(Module.myConfig);
    console.log(Module.myConfig.__proto__.__proto__ === null);
    console.log("name : "+Module.myConfig.name);
    console.log("password : "+ Module.myConfig.password);
    Module.myMethod();
  •   webkit截图

对象字面量表示法

Module模式

  Module模块化设计主要是通过闭包的方式,封装私有属性和方法,暴露一个公有api给外界去调用。如果这个模块需要暴露出去给其他人用作为一个工具库的话,最好使用 UMD 模式,也就是判断是否支持 AMD、CommonJS模块加载,UMD 做的事就是兼容!兼容!兼容!

  •   个人理解:
    var Module = (function(){
        var privatevar = 0 ;
        var privateMethod = function(foo){  
            console.log(foo);
        };
        return{
            publicvar : "U: i am hungry , want eat sb !",
            publicMethod : function(bar) {
                privateMethod(bar);
            },
            publicMethod2 : function(){
                console.log("I: U r very hungry !");            
            }  
        };
    }());
    Module.publicMethod("I: Who is hungry ?");
    Module.publicMethod2();
    console.log(Module.publicvar);
    console.log(Module.privatevar);
  •   加入UMD
(function(root, factory){
    if(typeof define === 'object' && define.amd) {
        define([], factory);
    } else if(typeof module === 'object' && module.exports) {
        module.exports = factory();
    } else {
        root.ModuleName = factory();
    }
}(this, function(){
    var module = {};
    module.publicMethod = ...;

    return module;
}));
  •   webkit截图

这里写图片描述

高级用法

  多人合作,一个模块分割成多个文件的故事。

  松耦合

  任意顺序加载多个Module,如果不存在Module模型,{}赋值给var Module,并向其中添加新的元素属性,返回值为新的Module。”强内聚,弱耦合”,开发追求的标准莫不过如此。

  •   代码结构:
var Module = (function (my) {
        my.abc = "abc";
        return my;
    } (Module || {}));
  •   个人理解:
    var Module = Module || {}; //解决多文件加载时候module如何定义问题,有定义增加一些方法;无定义那就白手起家
    var i, len, obj ,flag ;
    Module = (function (my) {
        my.add = function () {
            var reg =  /^(-?\d+)(\.\d+)?$/ ; //数字正则
            len = arguments.length;          //不定参数
            flag = 0;
            for(i = 0;i < len;i++){
                if(reg.test(arguments[i])){
                    flag += 1;

                }           
            }
            if(flag == len){
                obj = 0;
                for(i = 0;i < len;i+=1){
                    obj += arguments[i];
                }
            }else{
                obj = "";
                for(i = 0;i < len;i+=1){
                    obj += arguments[i];
                }
            }   
            console.log(obj);
        }
        return my;
    } (Module || {}));   
    Module.add(2, "aaaaa");
    Module.add(2, "aaaaa", 121);
    Module.add(2.2, 5.58.75.9);
  •   webkit截图

    松耦合上传图片

  紧耦合(未完待续)下班回家继续研究
  …
  …
  …
  22:00分 吃完饭洗完脸 坐在电脑前 折腾自己好久没开机的电脑 安装好常用的软件、插件之后 继续研究没研究完的东西….
  …
  …
  …

  紧耦合加强之间的模块之间联系,减少单独模块的复用性,获得的好处是有加载顺序,可以安全的重载方法。

  •   代码结构:
var MODULE = (function (my) {
        var old_moduleMethod = my.moduleMethod;

        my.moduleMethod = function () {
                // method override, has access to old through old_moduleMethod...
        };

        return my;
}(MODULE));
  •   个人理解:
    var Module = Module || {};

    Module = (function(my){
        my.addPhoto = function (foo) {
            console.log(foo);
        };
        return my;
    }(Module));

    Module = (function (my) {   
        var add = my.addPhoto;  //紧耦合的关键点
        my.addPhoto = function(){
            add("i am a sb !!");
            console.log("i love me !!");
        }
        return my;
    }(Module));
    Module.addPhoto();
  •   webkit截图

紧耦合上传图片

  克隆与继承(未完待续)夜深 程序员去挺尸了…
  …
  …
  …
  上班一小时,脑子活跃了,开始整理我的学习心得,公司前端大佬们在上演“人月神话”的故事。作为一只进击的小白,只好继续坚持(偷偷发育,我们能赢)的策略,等大佬争论结束后,默默给大佬打打杂。
  …
  …
  …
  关于这个知识点,我纠结再三还是将克隆与继承糅合在一起去介绍,可能代码有点绕,大家多花一丢丢时间就可以弄明白了。
  克隆这里介绍的是浅拷贝,理解这一小节需要掌握的知识包含:深度克隆、原型链、继承、for-in loops 以及上面的铺垫。所谓克隆就是复制原有模块方法为自己所用(js中方法的传递采用值传递的特殊方式–引用传递),加上重载的函数,感觉比以前要叼许多了。按照惯例,给大家上翻译过后的module关于clone与inheritance的结构:(刘卿的版本更有原汁原味)

  •   代码结构:

    var MODULE_TWO = (function (old) {
            var my = {},
                    key;

            for (key in old) {
                    if (old.hasOwnProperty(key)) {
                            my[key] = old[key];
                    }
            }

            var super_moduleMethod = old.moduleMethod;
            my.moduleMethod = function () {
                    // override method on the clone, access to super through super_moduleMethod
            };

            return my;
    }(MODULE));
  •   个人理解:

      偷个懒不画内存图了,关于克隆前后,方法addPhoto( )改变产生的微小差异,通过口语化的注释来帮助理解,个人觉得很生动了。

    var Module = Module || {};
    Module = {                              //字面量表示法
        publicStr : "i want to be a superman ...but ",
        addPhoto : function (foo) {       
            console.log(foo+Module.publicStr);
        }
    };
    Module2 = (function (old) {
            var my = {},key;
            //克隆
            for (key in old) {
                    if (old.hasOwnProperty(key)) { //不检索原型链
                            my[key] = old[key];
                    }
            }   
            return my;
    }(Module));

    Module2.addPhoto("i am isAre !! ");    //继承了Module方法
    console.log(Module2.publicStr);          
    Module.addPhoto = function(foo){
        console.log("foo : "+foo);
    }
    Module.publicStr = "16 years old you fucked the sky ";
    Module.addPhoto("i am isAre !!");    //Module方法修改注意是引用值发生改变,指向另一块内存堆区
    //可以理解为搬家了,对于他来说已经从江北搬到了江南,家的外貌地址全然发生改变
    Module2.addPhoto("i am isAre !!");   //Module2引用值仍是之前那个地址  所以console结果是:你16岁的那年对天放了一炮... 
    // 可以理解为旧友没有得知搬家消息,根据门牌号登门拜访,才发现家还是那个家,不曾改变过,但是里面住的人当然与现实有差距了
  •   webkit截图

clone上传图片

Tips:如何使方法修改过后两个模块同步?

  节约篇幅考虑,缩小代码量,直接修改上段代码11–15行为”my = old;”,console出现了两次结果:你16岁的那年对天放了一炮…

  跨文件访问私有对象

  交叉访问匿名函数中的私有属性,默默增加新的函数方法,都被允许,这里面蕴藏着数据结构里面的锁机制。所以需要掌握的知识点:锁机制、异步的概念。
  简单介绍一下锁机制吧:去做某些羞羞的事情,你来了,门锁上,你做事情,做完了,你出来;然后又来一位志同道合的人,他进去了,门锁上,他做事情,你又想做了,发现门是锁的,进不去。就这么简单的一回事~~反正我懂了…

  •   代码结构:
var blogModule = (function (my) {
    var _private = my._private = my._private || {},

        _seal = my._seal = my._seal || function () {
            delete my._private;
            delete my._seal;
            delete my._unseal;

        },

        _unseal = my._unseal = my._unseal || function () {
            my._private = _private;
            my._seal = _seal;
            my._unseal = _unseal;
        };

    return my;
} (blogModule || {}));
  •   个人理解:
var Module = (function (my) { 
    var _private = my._private = my._private || {},     //浅复制 实现交叉访问的大前提  通过删除 添加 my._private来进行模拟锁机制 进行数据访问操作等
    _seal = my._seal = my._seal || function () {
            delete my._private;
            delete my._seal;
            delete my._unseal;
        },
    _unseal = my._unseal = my._unseal || function () {
        my._private = _private;
        my._seal = _seal;
        my._unseal = _unseal;
    };

        _seal();               //锁门不许进
        _private.i = 10;       //准备工作
        if(_private.j){
            _private.j = 1000;
        }
    my.add = function(my){    //搞事情
        console.log(_private.i*_private.j);
    }    
        _unseal();            //开门下一位
return my;
}(Module || {}));


var Module = (function (my) {  //志同道合的路人甲到来
    var _private = my._private = my._private || {},
    _seal = my._seal = my._seal || function () {
        delete my._private;
        delete my._seal;
        delete my._unseal;
    },
    _unseal = my._unseal = my._unseal || function () {
        my._private = _private;
        my._seal = _seal;
        my._unseal = _unseal;
    };
    _seal();                  //关门
    _private.j = 100;         //准备工作
    if(_private.i){
        _private.i = 1700;
    }
    my.divide = function(my){  //搞事情    
        console.log(_private.i/_private.j);
    }
    _unseal();                //下一位
return my;
}(Module || {}));

var Module = (function (my) {  //不明事理的路人乙
    var _private = my._private = my._private || {},
    _seal = my._seal = my._seal || function () {
            delete my._private;
            delete my._seal;
            delete my._unseal;
        },
    _unseal = my._unseal = my._unseal || function () {
        my._private = _private;
        my._seal = _seal;
        my._unseal = _unseal;
    }; 
    _seal();                  //关门
    my.subtract = function(){ //不准备工作就搞事情
        console.log(_private.j-_private.i);
    }
    _unseal();                //很快就出来了...
    return my;
}(Module || {}));
Module.divide();
Module.add();                //add()就是乘法 大家发挥一下想象 
Module.subtract();
  •   webkit截图

私有属性访问上传图片

特别说明:假如,轻车熟路的路人乙第二次去干某事,这回准备了工作,那么最终输出结果,以路人乙为标准。请大家自行测试。

  子模块

  模块的儿子叫子模块,对模块的继承拓展有延伸作用,继承了爸爸的所有特色。有些时候,父亲老了,某些事情不能去做了,就生个儿子让儿子去做。只贴代码结构,大家有兴趣的可以自行对照着父模块的示例再敲一遍,加深印象~~~

  •   代码结构:
blogModule.CommentSubModule = (function () {
    var my = {};
    // ...

    return my;
} ());
CommentSubModule.subMethod();

结束语
  耗时三天的研究或许是不值得的,有这个时间我可以堆好多页面出来,研究好多小的知识点,但是困难的东西研究出来,心里还是挺哈皮的~~
  存在的知识盲区:umd模式。博文出现的小问题是浮点相加出现误差的问题,自行百度即可。
  由于能力问题、时间问题或多或少存在着一些不足,请大牛不吝指教。

参考链接:
  【原作者–我看不懂你们看着办】
  【汤姆大叔的传送门】
  【汤姆大叔翻译没他好的传送门】
  【猪大大的传送门】
特别感谢:
  segmentfault的shawncheung同学;zhihu的胡嵩。
  
  
  
  
  
  
  
  
【csdn博客管理员镇楼】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值