zoukankan      html  css  js  c++  java
  • 深入理解模块模式

            这里主要引用《JavaScript语言精粹》里面有关函数的理解,结合《JavaScript高级程序设计-第2版》对块级作用域的理解,联想到自己所做的项目,对模块模式作以汇总并评价。

      1 /**
      2  * 首先需要知道块级作用域的概念——
      3  *     1>JavaScript当中没有真正意义上的块级作用域,我们使用匿名函数进行模拟实现。
      4  *     2>在块级作用域中定义的任何变量,都会在执行结束时被销毁(闭包另当别论),源于没有指向该匿名函数的引用。
      5  *     3>当里面应用了闭包时,该块级作用域里的代码执行结束时,销毁的是它的作用域链,但是其活动对象仍然保存在内存中。
      6  *     3>作用:
      7  *         a>提高性能(相对而言):对于临时需要的变量,用完立即销毁
      8  *         b>防止向全局作用域中添加变量和函数。
      9  *         c>减少闭包占用的内存问题
     10  *     4>引入模块模式...
     11  */
     12 (function($){
     13        /**
     14         * 模块模式
     15         *     1>组成
     16         *         a>外层是一个立即执行的函数表达式
     17         *         b>模块中定义私有变量(当然也有私有函数)
     18         *         c>利用闭包创建可以访问私有变量和函数的特权函数。
     19         *         d>返回这个特权函数
     20         *    2>作用
     21         *        a>摒弃全局变量
     22         *        b>封装功能或者程序,毫无疑问,更具维护性,更具重用性
     23         *    3>优势:只暴露了公有方法,隐藏里面的私有属性
     24         */
     25        //举个例子
     26        //输入区域键盘处理
     27        dom.find('div.ldj-chat-in input, div.ldj-chat-input textarea').bind('keydown keyup change',function(dom){
     28            //这3个变量是专属于这个模块的私有变量
     29            var curr = 0;
     30            /**
     31              * 这里的history是一个数组,用于保存历史记录,很显然,这里的history需要静态的保存历史数据,而不是每一次触发事件的时候,再重新赋值所有历史记录值,
     32              * 可能如果是新手的话,可能会把这里的history保存为一个全局变量,以便于操作,保存记录。但是,由于全局变量是共享的,所以如果无意中改变了它的值,
     33              * 后果将是很严重的。这也就是我们通常说的,"全局变量是魔鬼"。我们利用了模块模式(一个立即执行的函数表达式),摒弃了全局变量的应用。
     34              * 当然我们可以利用传入的参数值来保存对应变量的状态。接着我们要实现我们的功能就是,让history具有全局变量的效果。当然也就想到应用闭包了。
     35              * 当这个函数调用完成后,由于这个函数里面存在一个匿名函数,并且里面的匿名函数调用了这里的history变量,
     36              * 而且,这个匿名函数赋值给了一个jQuery对象的一个事件,导致这里的history变量一直存在于内存当中。
     37              * 当然,这里的curr和now变量也都被引用了,那么这两个变量也将在内存里面。(这里,哪些变量需要放置在这儿,需要依照应用来定)。
     38              */
     39            var history;  
     40                
     41            var now;
     42            
     43            /**
     44             * 返回的是一个函数(闭包),这个函数能够访问到以上3个私有属性变量,拿《JavaScript语言精粹》的话来讲,就是特权函数了,
     45             * 因为只有它才能访问当这个模块里的私有变量,走出了这个模块,谁也访问不到了。
     46             */
     47            return function(e){
     48                /**
     49                 * 以下声明的这3个变量,是属于这个匿名函数的动态作用域里面的变量,也就是说,每触发一次事件,这里的值都会重新赋值,
     50                 * 当然这里的变量赋值也需要依应用而定。就像这里的text变量取的是每进行一次键盘的敲击,
     51                 * 都需要重新记录文本框里面所有敲击的内容,当然就应该是动态变量的赋值了。
     52                 */
     53                var l = $(this).data('len') || 0;
     54                var text = $(this).val();
     55                var n = text.length;
     56                history = history || dom.data('history');
     57                    
     58                if ($.browser.opera || (e.type === 'keyup')) {
     59                    //回车
     60                    if (e.keyCode === 13) {
     61                        curr = 0;
     62                        //如果消息为空,则不发送
     63                        if (text.trim() === '') {
     64                            $(this).val('').focus();
     65                            return;
     66                        }
     67                        $(this).trigger('send');
     68                        return false;
     69                    }
     70                    //
     71                    if (e.which === 38 && curr < history.length) {
     72                        now === undefined && (now = $(this).val());
     73                        var prev = history[curr];
     74                        if ($(this).is('textarea')) {
     75                            $(this).val(/^#c[0-9a-fA-F]{6}/.test(prev) ? prev.substring(8) : prev);
     76                        }
     77                        else {
     78                            $(this).val(prev);
     79                        }
     80                        $(this).data('len', prev.length);
     81                        curr++;
     82                    }
     83                    //下...
     84                }
     85            }  
     86        }(dom));  //执行完这个函数的时候,该函数的作用域链会立即销毁,但是它的活动对象一直存在于内存当中。需要强调这里传入的参数的应用理解,
     87                  //它往往传入的是需要保存状态的参数。另一个在性能的优化上理解的话,就是查询该元素更加快速,很显然,减少了一层闭包的变量查询。
     88        /**
     89         * 虽然,history变量一直在内存里面,但是在上面的块级作用域的外面是根本访问不到的。访问不到的原因是,
     90         * 上一个模块的最外层是由立即执行的函数表达式构成,导致这个匿名函数在执行完成后,
     91         * 它的作用域链会被销毁,当然里面的动态局部变量也是被销毁的,如果有闭包的存在,那么它的活动对象依旧在内存中。
     92         * 深入理解了这一点,才能对JavaScript代码的调优作以深入分析。
     93         */
     94             
     95        (function(){
     96            //第二个模块
     97            //...
     98        })();  //当然可以在这里传入必要的全局参数
     99        
    100        (function(){
    101            //第三个模块
    102            //...
    103        })();
    104        
    105        /**
    106         * 如此这样模块化去写JavaScript代码,是不是感觉代码的封装性更好了呢?答案是肯定的。
    107         * 同样的,模块模式的应用提供了一种JavaScript代码的优化思想。
    108         */
    109    
    110    })(jQuery);  //最外层同样也是模块模式,同样的,有效摒弃全局变量;起到了块级作用域的效果。
    111    
    112    /**
    113     * 1.模块模式的另外一个应用便是功能的有效独立扩展,汤姆大叔的博客解释的清晰明了
    114     *   http://www.cnblogs.com/TomXu/archive/2011/12/30/2288372.html
    115     * 2.会发现,在最外层的代码(function($){...})(jQuery),同样也是模块模式的应用,可以知道,
    116     *   模块模式的应用不仅可以应用在程序的局部,同样也能应用在程序的全局。它的好处已经解释过了,在此略过。
    117     */

            注意,不要仅仅用模块模式去优化我们的JavaScript代码,由于里面有闭包的存在,对于内存的的消耗还是有些大的。当然,我们需要变相的去看待这里的闭包,如果一个变量,我们持续需要检索,我们当然要选择让这种类型的变量一直置于内存中,以提高查询检索速度;不要忘了闭包的存在让这个变量实现静态存储(实现静态存储是有条件的,这里就不再解释了),什么时候需要应用这种方式,不仅要从性能上去考虑,还要从功能需求上考虑。

  • 相关阅读:
    set-rebgin
    HTML5开发学习:本地存储Web Sql Database
    Sublime text 入门学习资源篇及其基本使用方法
    web前端不可错过的开发工具–Adobe Brackets
    关于WEB前端开发的工具
    WebStorm使用技巧
    五大浏览器兼容性
    IT解惑真经
    win7下一劳永逸地解决触控板禁用的问题
    PHP+Mysql学习笔记
  • 原文地址:https://www.cnblogs.com/jinguangguo/p/2632683.html
Copyright © 2011-2022 走看看