美文网首页
AMD CMD CommonJS ES6 Module

AMD CMD CommonJS ES6 Module

作者: 张Piers | 来源:发表于2020-11-17 14:25 被阅读0次

    前言

    作为一个接口API测试工程师,你是否曾经有过疑惑,有些项目在模仿(fu zhi zhan tie)原有的代码时,有时候是通过export 将模块暴露出去,有时候是通过export default,有些包可以通过import引用,有些是require,那么,来总结一下这些区别

    首先了解一些基本的概念

    AMD(RequireJS)

    1. AMD一开始是CommonJS规范中的一个草案,全称是Asynchronous Module Definition,即异步模块加载机制。后来由该草案的作者以RequireJS实现了AMD规范,所以一般说AMD也是指RequireJS。
    2. 特点:
      • 对于依赖的模块,AMD推崇依赖前置,提前执行。也就是说,在define方法里传入的依赖模块(数组),会在一开始就下载并执行。
      • 模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
    3. 使用:通过define来定义一个模块,使用require可以导入定义的模块。
    // a.js
    /*
    * define(id?, dependencies?, factory);
    * id:可选参数,用来定义模块的标识,如果没有提供该参数,脚本文件名(去掉拓展名)
    * dependencies:是一个当前模块依赖的模块名称数组
    * factory:工厂方法,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值 在页面上使用require函数加载模块
    */
    define(function(){
        return 1;
    })
    
    // b.js
    /*
    *数组中声明需要加载的模块,可以是模块名、js文件路径
    * require([dependencies], callback); 
    * [dependencies]: 是一个数组,表示所依赖的模块
    * callback: 是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块
    */
    require(['a'], function(a){
       console.log(a);// 1
    });
    

    CMD

    1. CMD是SeaJS在推广过程中生产的对模块定义的规范,在Web浏览器端的模块加载器中,SeaJS与RequireJS并称,SeaJS作者为阿里的玉伯。
    2. 特点:对于依赖的模块,CMD推崇依赖就近,延迟执行。也就是说,只有到require时依赖模块才执行。
    3. 使用:
    // a.js
    /*
    * define 接受 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串
    * define(id?, deps?, factory)
    *  id 表示模块标识
    * 数组 deps 是模块依赖
    * factory 为对象、字符串时,表示模块的接口就是该对象、字符串。
    */
    define(function(require, exports, module) {
      var $ = require('jquery');
      exports.setColor = function() {
        $('body').css('color','#333');
      };
    });
    
    //b.js
    //数组中声明需要加载的模块,可以是模块名、js文件路径
    seajs.use(['a'], function(a) {
      $('#el').click(a.setColor);
    });
    

    CommonJS

    1. CommonJS规范为CommonJS小组所提出,目的是弥补JavaScript在服务器端缺少模块化机制,NodeJS、webpack都是基于该规范来实现的。
      在 ES6 之前,ECMAScript 并没有提供代码组织的方式,那时候通常是基于 IIFE 来实现“模块化”,随着 JavaScript 在前端大规模的应用,以及服务端 Javascript 的推动,原先浏览器端的模块规范不利于大规模应用。于是早期便有了 CommonJS 规范,其目标是为了定义模块,提供通用的模块组织方式。
    2. 特点:
      • 所有代码都运行在模块作用域,不会污染全局作用域;
      • 模块是同步加载的,即只有加载完成,才能执行后面的操作;
      • 模块在首次执行后就会缓存,再次加载只返回缓存结果,如果想要再次执行,可清除缓存;
      • require返回的值是被输出的值的拷贝,模块内部的变化也不会影响这个值。
    3. 使用:
    //a.js
    module.exports = function () {
      console.log("hello world")
    }
    
    //b.js
    var a = require('./a');
    
    a();//"hello world"
    
    //或者
    
    //a2.js
    exports.num = 1;
    exports.obj = {xx: 2};
    
    //b2.js
    var a2 = require('./a2');
    
    console.log(a2);//{ num: 1, obj: { xx: 2 } }
    

    ES6 Module

    1. ES6 Module是ES6中规定的模块体系,相比上面提到的规范, ES6 Module有更多的优势,有望成为浏览器和服务器通用的模块解决方案。
    2. 特点(对比CommonJS):
      • CommonJS模块是运行时加载,ES6 Module是编译时输出接口;
      • CommonJS加载的是整个模块,将所有的接口全部加载进来,ES6 Module可以单独加载其中的某个接口;
      • CommonJS输出是值的拷贝,ES6 Module输出的是值的引用,被输出模块的内部的改变会影响引用的改变;
      • CommonJS this指向当前模块,ES6 Module this指向undefined;
      • 目前浏览器对ES6 Module兼容还不太好,我们平时在webpack中使用的export/import,会经过babel转换为CommonJS规范。
    3. 使用:
    //a.js
    var name = 'lin';
    var age = 13;
    var job = 'ninja';
    
    export { name, age, job};
    
    //b.js
    import { name, age, job} from './a.js';
    console.log(name, age, job);// lin 13 ninja
    
    //或者
    
    //a2.js
    export default function () {
      console.log('default ');
    }
    
    //b2.js
    import customName from './a2.js';
    customName(); // 'default'
    

    Node.js模块里exports与module.exports的区别

    其实require导出的内容是module.exports的指向的内存块内容,并不是exports的。 简而言之,区分他们之间的区别就是 exports 只是 module.exports的引用,辅助后者添加内容用的。
    为了避免糊涂,尽量都用 module.exports 导出,然后用require导入。

    var module = {
        exports:{
            name:"我是module的exports属性"
        }
    };
    var exports = module.exports;  //exports是对module.exports的引用,也就是exports现在指向的内存地址和module.exports指向的内存地址是一样的
    console.log(module.exports);    //  { name: '我是module的exports属性' }
    console.log(exports);   //  { name: '我是module的exports属性' }
    exports.name = "我想改一下名字";console.log(module.exports);    //  { name: '我想改一下名字' }
    console.log(exports);   //  { name: '我想改一下名字' }
    //看到没,引用的结果就是a和b都操作同一内存地址下的数据
    
    
    //这个时候我在某个文件定义了一个想导出的模块
    var Circle = {
        name:"我是一个圆",
        func:function(x){
            return x*x*3.14;
        }
    };
    exports = Circle;  //   看清楚了,Circle这个Object在内存中指向了新的地址,所以exports也指向了这个新的地址,和原来的地址没有半毛钱关系了
    console.log(module.exports);    //  { name: '我想改一下名字' }
    console.log(exports);   // { name: '我是一个圆', func: [Function] }
    

    ES中的模块重的export 和 export default的区别

    • export与export default均可用于导出常量、函数、文件、模块等
    • 在一个文件或模块中,export、import可以有多个,export default仅有一个
    • 通过export方式导出,在导入时要加{ },export default则不需要
    • export能直接导出变量表达式,export default不行。

    相关文章

      网友评论

          本文标题:AMD CMD CommonJS ES6 Module

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