模块化的理解

模块化方式

什么是模块化
所谓的模块化开发就是封装细节,提供使用接口,彼此之间互不影响,每个模块都是实现某一特定的功能。模块化开发的基础就是函数

  • 函数封装

    • "污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。
  • 对象方式

    var module1 = {
         _count : 0,
        m1 : function (){
          //...
        },
        m2 : function (){
          //...
        }
    }
    // 这样的写法会暴露所有模块成员,内部状态可以被外部改写。比如,外部代码可以直接改变内部计数器的值。module1._count = 1;
    
  • IIFE

    var module1 = (function(){
        var _count = 0;
        var m1 = function(){
          //...
        };
        var m2 = function(){
          //...
        };
        return {
          m1 : m1,
          m2 : m2
        };
      })();
    
  • 放大模式

    • 如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)。在原有的基础上扩展更多的方法
    var module1 = (function (mod){
        mod.m3 = function () {
          //...
        };
        return mod;
      })(module1);
    
    // 上面的代码为module1模块添加了一个新方法m3(),然后返回新的module1模块,方便方法连续调用。如何防止module1为null或underfined的情况了?
    
  • 宽放大模式

    • 在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上面的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"。
    var module1 = (function (mod){
    
            return mod;
      })(window.module1 || {}); // 确保对象不为空
    
    // 与"放大模式"相比,"宽放大模式"就是"立即执行函数"的参数可以是空对象,解决了非空问题。
    
  • 输入全局变量

    • 独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。为了在模块内部调用全局变量,必须显式地将其他变量输入模块。
    var module1 = (function ($, YAHOO) {
        //...
      })(jQuery, YAHOO);
    

COMMONJS 服务器端同步加载

  1. 再来说说 module.exports 和 exports,用法其实是相似的,但是不能对 exports直接赋值,不会有任何效果。
  2. 对于 CommonJS 和 ES6 中的模块化的两者区别是:
    • 前者支持动态导入,也就是 require(${path}/xx.js),后者目前不支持,但是已有提案
    • 前者是同步导入,因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大。而后者是异步导入,因为用于浏览器,需要下载文件,如果也采用导入会对渲染有很大影响
    • 前者在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想更新值,必须重新导入一次。但是后者采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化
    • 后者会编译成 require/exports 来执行的

AMD (Asynchronous Module Definition)

"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

require([module], callback);

requirejs的使用

  1. 为什么要使用requirejs

    • 加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;

    • 由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面)

    • 依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。

    • requirejs 特性

      1. 实现js文件的异步加载,避免网页失去响应;
      2. 管理模块之间的依赖性,便于代码的编写和维护。
  2. requireJs的加载

    <script src="js/require.js" data-main="js/main"></script>
    
    1. data-main属性的作用是,指定网页程序的主模块。
    2. 在上例中,就是js目录下面的main.js,这个文件会第一个被require.js加载。
    3. 由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。
    
  3. 主模块的写法

    主模块",意思是整个网页的入口代码。它有点像C语言的main()函数,所有代码都从这儿开始运行。下面就来看,怎么写main.js。

    require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
        // some code here
            // require.js会先加载jQuery、underscore和backbone,然后再运行回调函数。主模块的代码就写在回调函数中。
      });
    /*
    require()函数接受两个参数。
        第一个参数是一个数组,表示所依赖的模块,上例就是['moduleA', 'moduleB', 'moduleC'],即主模块依赖这三个模块;
        第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。
    */
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容