JavaScript模块化

随着JavaScript代码复杂度的提高,从无模块化到现在的ES6模块化,有很大的变化,发展阶段如下:无模块化->CommonJS规范->AMD规范->CMD规范->ES6模块化

  1. 无模块化

    ​ JavaScript最初只需要实现简单的验证和提交表单,以及一些简单的JS交互效果,直接在HTML中通过script标签引入js文件或直接在script标签中添加相应JavaScript代码即可。

    ​ 随着代码负责度的增加,需要引入多个JavaScript文件,特殊情况下还需要注意顺序,比如使用jQuery实现功能之前,必须先引入jQuery,顺序错误会导致报错。

    优点

    • 有模块化的思想雏形,代码可读性相对于单JavaScript文件和直接在script标签中写JavaScript代码较好

    缺点

    • 污染全局变量
    • 依赖关系不明显,容易出错
  2. CommonJS规范

    • node应用由模块组成,采用CommonJS规范

    • 每个文件就是一个模块,有自己的作用域,每个文件里的变量、函数、类都是私有的,对其他文件不可见。

    • 通过exports属性导出模块,通过require加载模块

      //导出
      var x = 5;
      var addX = function (value) {
        return value + x;
      };
      module.exports.x = x;
      module.exports.addX = addX;
      
      //导入
      var example = require('./example.js');
      console.log(example.x); // 5
      console.log(example.addX(1)); // 6
      
    • 提问1:exports和module.exports的区别?

      exports只是module.exports的引用,辅助后者添加内容,最终require引入的内容,始终是module.exports的,如果exports指向没有被改变,exports和module.exports指向的内容是一样的。建议使用commonJS规范时,统一使用module.exports导出,require导入

    缺点

    • CommonJS规范时同步加载模块的,只有加载完成了,才会执行后面的操作,用于服务器编程不存在速度慢的问题,可是浏览器环境是从服务器加载模块,需要使用非同步加载模块,CommonJS规范不符合要求。

    优点

    • 不污染全局变量
    • 模块可以多次加载,但只会在第一次加载时运行一次,然后运行结果缓存,以后加载,直接读取缓存结果,要想模块再次运行,必须清除缓存
  3. AMD规范

    ​ AMD规范的出现,解决了非同步加载模块的问题,允许使用回调函数,require.js采用的就是AMD规范。

    • 定义模块

      define(id,[depends],callback);
      
    • 加载模块

      require([module],callback);
      
    • 兼容CommonJS规范

      define(function (require, exports, module){
        var someModule = require("someModule");
        var anotherModule = require("anotherModule");
      
        someModule.doTehAwesome();
        anotherModule.doMoarAwesome();
      
        exports.asplode = function (){
          someModule.doTehAwesome();
          anotherModule.doMoarAwesome();
        };
      });
      

    ​ 注意:使用require.js时,必须提前加载该模块的所有依赖,才能使用,不能按需加载

    缺点

    解决了浏览器环境异步加载的问题,可同步加载多个模块

    优点

    不能按需加载依赖模块,必须提前加载

  4. CMD规范

    CMD规范的出现解决了,上述问题中按需加载的问题,sea.js使用的就是CMD规范,它和require.js相比,最大的区别就是可按需加载模块,即模块的加载可以延迟执行。

    // AMD
    define(['./a', './b'], function(a, b) {  // 依赖必须一开始就写好  
       a.doSomething()    
       // 此处略去 100 行    
       b.doSomething()    
       ...
    });
    // CMD
    define(function(require, exports, module) {
       var a = require('./a')   
       a.doSomething()   
       // 此处略去 100 行   
       var b = require('./b') 
       // 依赖可以就近书写   
       b.doSomething()
       // ... 
    });
    

    缺点

    同时解决了浏览器端异步加载和延迟加载模块的问题

    优点

    依赖SPM打包,模块的加载逻辑偏重

  5. ES6模块化

    ​ ES6的模块化规范才是真正的规范,import引入模块,export导出模块,和前几个方案相比,功能更加强大,但目前ES6无法在浏览器中执行,所以需要使用babel将import编译为广泛支持的require。在项目中应该统一使用import或require,import以后应该是主流方向,所以推荐使用import

    //导出示例
    export default a;
    export a;
    export {a,b};
    //function和class导出的正确写法
    //写法1
    function f(){}
    export {f};
    //写法2
    export function f() {};
    
    
    //导入示例
    import a from './xx.js';
    import {a} from './xx.js';
    import {a,b} from './xx.js';
    

    提问2:export default 和 export的区别?

    答:

    • export和export default均可导出常量、函数、文件、模块等

    • 在一个文件或模块中,export、import可以有多个,export default仅有一个

    • 通过export方式导出,在导入时要加{},export default不需要

    • export能直接导出变量表达式,export default不行

    提问3:import和require的区别?

    答:

    import/export是ES6新规范;require/exports是CommonJS的一部分

    区别:

    • import/export比较灵活
    • CommonJS和ES6 Module 输出都可以看成是一个具备多个属性或者方法的对象
    • default 是ES6 Module所独有的关键字,export default 输出默认的接口对象,import from 'fs’可直接导入这个对象;
    • ES6 Module中导入模块的属性或者方法是强绑定的,包括基础类型;而 CommonJS 则是普通的值传递或者引用传递。

你可能感兴趣的:(js基础,前端,模块化)