JavaScript的四种模块化规范

  1. <b>CommonJS规范</b>

    由于ES5没有模块化规范,所以产生了这三种规范。在ES6中又新增了一种公用模块化的方法。

    特点:同步

    CommonJS规范是通过module.exports定义的,在前端浏览器中并不支持此中规范

    浏览器不兼容Common的根本原因也就是缺少四个Node环境的变量

    • module
    • exports
    • require
    • global

    Node以及Webpack是采用CommonJS的形式来写的

    CommonJS定义的模块分为三种:模块引用(require);模块定义(exports);模块标识(module)

    require()用来引入外部模块,exports对象用于导出当前模块,或者当前的模块的方法和变量,module对象代表对象本身

    var foo = require('foo.js');
    var count =1;
    var plus = ()=>{
       foo.add(count);
    };
    module.exports= {
       count,
       plus
    }
    

    <b>特点</b>

    ​ 对于基本数据类型,和语言本身一样属于复制,即会被模块缓存,在另一个模块中可以对该模块输出的变量重新赋值。

    ​ 对于复杂数据类型,例如Array,Object,属于浅拷贝,即同时指向一个内存空间,因此对一个模块的值的改变可以影响另一个模块。详见javascript深拷贝与浅拷贝详解。

    当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。

    <b>循环加载</b>

    // a.js
    exports.done = false
    let b = require('./b.js')
    console.log('a.js-1', b.done)
    exports.done = true
    console.log('a.js-2', '执行完毕')
    
    // b.js
    exports.done = false
    let a = require('./a.js')
    console.log('b.js-1', a.done)
    exports.done = true
    console.log('b.js-2', '执行完毕')
    
    // c.js
    let a = require('./a.js')
    let b = require('./b.js')
    
    console.log('c.js-1', '执行完毕', a.done, b.done)
    
    

    运行node c.js

    usr:~ usr$  node c.js
    b.js-1 false
    b.js-2 执行完毕
    a.js-1 true
    a.js-2 执行完毕
    c.js-1 执行完毕 true true
    

    循环加载时,commonjs属于加载时执行,即脚本代码在require时候,就会全部执行。一旦出现某个模块被“循环加载”,只输出已经执行的部分,未执行的部分不输出。

    上述代码很明显的表现出了此类特点

    step1: node c.js

    step2: require(./a.js) //执行完a.js中的内容

    step2.1: export.done = flase; let b = require(./b.js); // 执行b中的代码

    step2.2: export.done = flase; let a= require(./a.js) //由于发生了循环加载,所以只执行a中的第一句,然后继续执行b.js 输出 <code>b.js-1 false b.js-2执行完毕</code>

    step2.3: 继续执行b中的代码 将b.done 赋值为true

    step 2.4 : 执行a的剩余部分 a.js-1 true; a.js-2 执行完毕

    step3:require(./b.js) 由于已经执行过了不会再执行b中的代码 所以直接输出b返回值

    step4: 输出c.js-1 执行完毕 true true


  2. <b>AMD规范</b>

    由于CommonJS的局限性 例如

    var math = require('math');
    
    math.add(2,3);
    

    第二行代码必须要在 require之后运行,如果math加载时间很长,就会陷入空等,整个过程是同步的。

    对于服务器这不是个问题,因为都存储在本地,但是对于客户端,如果由于网络原因,可能会陷入“假死”状态。

    所以客户端,不能采用同步加载,只能使用异步加载。

    AMD规范是require.js对模块化定义的一种规范化产出

    ​ 模块本身和模块之间的引用可以被异步加载

    ​ 先引入模块后使用模块的方法,称之为<b>依赖前置</b>

    优点

    ​ 1.包括异步调用和本身高扩展性

    ​ 2.解耦,模块在代码中也可以通过识别号进行查找

    define(['./package/lib.js'], function(lib) {
          function say(){
               lib.log('this is fn');
           }
           return {
               say:say
           }; 
    });
    

    Tips

    ​ lib.js是我们引入的方法,回调中lib参数表示的是引入的模块的所有方法及属性

    ​ 我们在当前模块定义了say方法,并且return say的执行结果

  3. <b>CMD规范</b>

    SeaJs

    CMD:同步模块定义

    依赖就近原则

    sayHello.js

    define(function(require,exports,module){
       //通过require引入依赖,并不是AMD的依赖前置,而是依赖就近,哪里用,哪里引
       //例如下列引入jquery
       var JQ = require('jquery');
       exports.sayHello = function(){
           $('#hello').toggle('slow')
       }
    })
    

    main.js

    define(function(require){
       var CMD = require('sayHello');
       var temp = new CMD();
       temp.sayHello();
    })
    
  4. <b>ES6模块化规范</b>

    ES6在语言标准上面实现了模块功能。设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入输出变量。CommonJS以及AMD都只能在运行时确定

    ES6的模块并不是对象,而是通过export显示指定输出的代码,再通过import命令导入

    //commonJs
    // CommonJS模块
    let { stat, exists, readFile } = require('fs');
    
    // 等同于
    let _fs = require('fs');
    let stat = _fs.stat;
    let exists = _fs.exists;
    let readfile = _fs.readfile;
    //创建了一个对象
    
    //ES6
    import { stat, exists, readFile } from 'fs';
    

    上面代码的实质是从fs模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。

    export输出的接口,是变量实时的值,与commonjs输出的是值的缓存不相同

    export与import要出现在模块顶层

    如果想要重新命名,需要使用as关键字

    也可以引入整个模块

    import * as bb from './xxx'

    也可以匿名导出 这样可以给导出的模块任意指定名字

    export default

    import anyname from 'xx.js'

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351