美文网首页让前端飞前端之美
理解CommonJs、AMD、CMD、ES6模块

理解CommonJs、AMD、CMD、ES6模块

作者: 聪明的汤姆 | 来源:发表于2018-08-24 12:04 被阅读17次

    模块化

    模块化就是把系统分离成独立功能的方法,这样我们需要什么功能,就加载什么功能

    • 每个模块都是独立的,良好设计的模块会尽量与外部的代码撇清关系,以便于独立对其进行改进和维护
    • 可以重复利用,而不用经常复制自己之前写过的代码

    模块化主要解决两个问题,"命名冲突"、"文件依赖"

    命名冲突

    // a.js
    var a = 1;
    
    // b.js
    var a = 2;
    

    文件依赖

    // b.js依赖a.js,标签的书写顺序必须是:
    <script src='a.js' type='text/javascript'></script>
    <script src='b.js' type='text/javascript'></script>
    

    这样在多人开发的时候很难协调啊,令人头疼的问题

    解决冲突、依赖(按需加载)

    使用命名空间
    这样的写法会暴露所有模块内的成员,内部状态可以被外部改写

    let module = {
      name: 'likang xie',
      sayName() {
        console.log(this.name);
      }
    }
    

    立即执行函数+闭包
    函数内部有自己独立的作用域,外部只能访问自己暴露的成员而不能读取内部的私有成员

    let module = (function () {
      let privateName = 'private'; // 私有变量
      let privateFn = function () {}; // 私有函数
      
      // 对外暴露的成员
      return {
        name: 'likang xie', // 公有属性
        sayName() { // 公有方法
          console.log(this.name);
        }
      }
    })();
    
    // 外部调用
    module.sayName(); // likang xie 
    

    使用立即执行函数+类
    同上

    const People = (function () {
    
      let privateName = 'private'; // 私有变量
      let fn = function () {}; // 私有方法
    
      return class People {
        constructor () {
          this.name = 'likang xie'; // 公有变量
        }
      
        // 公有方法
        sayName() {
          console.log(this.name);
        }
       }
    
    })()
    

    CommonJs(用于Node环境)

    根据CommonJs规范,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见,CommonJS规范加载模块是同步的,也就是说,加载完成才可以执行后面的操作,Node.js主要用于服务器编程,模块一般都是存在本地硬盘中,加载比较快,所以Node.js采用CommonJS规范。

    定义模块

    // module.js
    let name = 'liakng xie';
    let sayName = function () {
      console.log(name);
    };
    
    module.exports = { name, sayName }
    
    // 或者
    exports.sayName = sayName;
    

    加载模块

    // 通过 require 引入依赖
    let module = require('./module.js');
    module.sayName(); // likang xie
    

    module.export跟exports的区别

    1. module.exports 方法还可以单独返回一个数据类型(String、Number、Object...),而 exports 只能返回一个 Object 对象
    2. 所有的 exports 对象最终都是通过 module.exports 传递执行,因此可以更确切地说,exports 是给 module.exports 添加属性和方法
    exports.name = 'likang xie';
    exports.age = 21;
    console.log(module.exports); // 运行结果:{ name: 'likang xie', age: 21 }
    
    1. 同时用到module.export跟exports的时候
    // 情况1
    module.exports = { a: 1 }
    exports.b = 2;
     // { a:1 }
    console.log(module.exports);
    
    // 情况2
    module.exports.a =1;
    exports.b = 2;
     // { a:1, b:2 }
    console.log(module.exports);
    

    AMD(用于浏览器环境)

    AMD是"Asynchronous Module Definition"的简写,也就是异步模块定义。它采用异步方式加载模块。通过define方法去定义模块,require方法去加载模块。

    requireJs官方文档

    定义模块

    define(['module'], function() {
      let name = 'likang xie';
    
      function sayName() {
        console.log(name);
      }
      
      return { sayName }
    })
    

    使用模块

    // 通过 require 引入依赖
    require(['module'], function(mod) {
       mod.sayName(); // likang xie
    })
    

    CMD(用于浏览器环境)

    CMD与AMD用法很相似

    sea.js官方文档

    定义模块、使用模块

    define(function(require, exports, module) {
      // 通过 require 引入依赖
       var otherModule = require('./otherModule');
    
       // 通过 exports 对外提供接口
       exports.myModule = function () {};
    
       // 或者通过 module.exports 提供整个接口
       module.exports = function () {};
    })
    

    ES6模块(用于浏览器环境)

    模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

    定义模块、输出变量
    a.js

    export default { name: 'likang xie' }
    

    b.js

    // 输出多个变量
    export let name = 'likang xie';
    export let sayName = () => console.log(name);
    

    使用模块

    import people from 'a.js';
    console.log(people); // { name: 'likang xie' }
    
    // 将所有获取到的变量存到people里
    import * as people from 'b.js';
    console.log(people); // 一个module对象 { name: 'likang xie', sayName: .... }
    
    // 或者
    import { name, sayName } from 'b.js';
    

    浏览器原生支持ES6的模块?
    具体请参考在浏览器中使用javascript module(译)

    <script type="module">
      import * as fn from './b.js';
    </script>
    

    Webpack

    Webpack其实就是一个打包工具,他的思想就是一切皆模块,css是模块,js是模块,图片是模块。并且提供了一些列模块加载(各种-loader)来编译模块。官方推荐使用CommonJs规范,但是也支持CMD、AMD、ES6模块,所以基本通杀,准备写一篇入门Webpack的文章,所以这里就不过多说啦

    相关文章

      网友评论

        本文标题:理解CommonJs、AMD、CMD、ES6模块

        本文链接:https://www.haomeiwen.com/subject/jhepiftx.html