commonJS、AMD、CMD、UMD、ESM

commonJS

其代表为nodejs,在浏览器环境中无效,需通过babel转码支持
典型语法为require/exports ,随脚本执行同步动态加载模块,输出的是值的拷贝,模块内部非对象值的变化不会影响到这个值。

  • module.exports 和 exports
    module.exportsexports都是NodeJs中默认存在的{}默认指向同一块内存
    require引入的对象本质上是module.exports,因此如果直接对exports赋值,则会导致两者不全等。应通过exports.XXX=XXX进行赋值。
//utils.js
exports.a = 200;
console.log(module.exports) //{a : 200}
exports = {a:300}; //exports 指向其他内存区

//test.js
var utils = require('./utils');
console.log(utils.a) // 打印为 200

AMD(asynchronous module definition)

其代表为require.js,仅供前端使用
通过define函数定义模块,通过import引入模块。


CMD

其代表为Sea.js,仅供前端使用


UMD(Universal Module Definition)

一套兼容CommonJS、AMD、CMD的方案,既可以通过 创造出module,默认异步加载并在页面渲染完毕后执行,类似defer

  • module 具有局部作用域
  • module 默认处于严格模式
  • module中顶层的this指向undefined
  • import引入的内容类似const声明,不能重新赋值/定义
  • import {e1} from './webUtils.js';
    e1=234;//Uncaught TypeError: Assignment to constant variable.
    var e1=1;//Uncaught SyntaxError: Identifier 'e1' has already been declared
    
    • module引用时不支持 file:// 文件协议,只支持 HTTP 协议。因此即使本地打开也需要启本地服务器。
    • module是静态加载的,在代码静态解析阶段(而非脚本执行时)生成,因此import/export只能出现在模块的最外层(顶层)结构中且不能出现在判断等动态语句中。import/export是对模块的引用而非拷贝,模块中值的变化会动态体现到导出后的脚本中。

    import()函数
    • import()函数可实现动态加载,返回一个Promise对象
      import('./dialogBox.js')
      .then(dialogBox => {
        dialogBox.open();
      })
      .catch(error => {
        /* Error handling */
      })
    

    import/export 语法
    • 一个模块中只能有一个export default ,但可以有多个export
    • export default 向外暴露的成员,使用任意不带{}的变量来接收
    • export导出的成员,使用带{}的同名变量来接收
    //demo_export.js
    function hello() {}
    
    setTimeout(() => {
      num_to_change = 999;
    }, 1000);
    
    export var num_to_change = 0;
    export { hello as hello_1 };
    export default "hello world";
    
    
    
    • import...from会执行module并引入内容,而以下两句仅执行module而不引入内容
    
    
    

    babel将import/export转为require/exports
    • 导出和导入是分别编译的,因此可以用exports导出而用import导入,也可以用export导出而用require导入
    • 导出时,babel将所有输出都赋值给exports,并带上 __esModule 表明原本是import/export
    • 导入时,通过是否存在__esModule判断来源,决定导入的是整个模块还是其中某个属性
    //import/export
    export default 123;
    export const a = 123;
    const b = 3;
    const c = 4;
    export { b, c };
    
    //require/exports
    exports.default = 123;
    exports.a = 123;
    exports.b = 3;
    exports.c = 4;
    exports.__esModule = true;
    
    function _interopRequireDefault(obj) {
        return obj && obj.__esModule
            ? obj
            : { 'default': obj };
    }
    
    var _a = require('assert');
    var _a2 = _interopRequireDefault(_a);
    
    var a = _a2['default'];
    
    • babel5和babel6对export default的编译方式不同,因此通过require引入时会获得不同结果

    多次加载、循环加载

    阮一峰的说明

    • CommonJS 模块就是对象,只会在第一次加载时运行一次,以后再加载,就读取这个对象(返回第一次运行的结果)
      CommonJS 模块的重要特性是加载时执行,一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
      • 执行顺序 随脚本执行
        11.1=>1=>2.1=>6=>7(此时不会重新执行a,只会读取内存中a的拷贝,done为false) =>8=>9=>10=>2.2=>3=>4=>5=>11.2=>12=>13
    //a
    exports.done = false;//1
    var b = require('./b.js');//2
    console.log('在 a.js 之中,b.done = %j', b.done);//3
    exports.done = true;//4
    console.log('a.js 执行完毕');//5
    //b
    exports.done = false;//6
    var a = require('./a.js');//7
    console.log('在 b.js 之中,a.done = %j', a.done);//8
    exports.done = true;//9
    console.log('b.js 执行完毕');//10
    //main.js
    var a = require('./a.js');//11
    var b = require('./b.js');//12
    console.log('在 main.js 之中, a.done=%j, b.done=%j', a.done, b.done);//13
    
    $ node main.js
    
    在 b.js 之中,a.done = false
    b.js 执行完毕
    在 a.js 之中,b.done = true
    a.js 执行完毕
    在 main.js 之中, a.done=true, b.done=true
    
    • ESM 只会在第一次加载时运行一次,以后再加载,就通过引用再次去读取
      ES6模块不是对象,模块内部引用的变化,会反应在外部。
      • 执行顺序 在脚本之前执行
        a中变量/函数提升=>4+6=>7+11(此时获取到的a1未赋值,a2由于函数提升已经有值)=>8=>9=>1=>2=>3=>5=>10
    //a.mjs
    var a1 = 100; //1
    console.log("a1 in a", a1); //2
    function a2() {//3
      return 99;
    }
    import b from "./b.js"; //4
    console.log("b", b); //5
    export { a1, a2 }; //6
    
    //b.mjs
    import { a1,a2 } from "./a.js"; //7
    console.log("a1_before", a1); //8
    console.log("a2", a2()); //9
    setTimeout(() => {
      console.log("a1_after", a1); //10
    });
    export default 0; //11
    
    node --experimental-modules a.mjs
    a1_before undefined
    a2 99
    a1 in a 100
    b 0
    a1_after 100
    

    你可能感兴趣的:(commonJS、AMD、CMD、UMD、ESM)