• JS之AMD、CMD、CommonJS、ES6、UMD的使用笔记


    前言

    如下图:

    AMD与CMD的主要区别:

    • 1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
    • 2. CMD 推崇依赖就近,AMD 推崇依赖前置。看代码:
    // CMD
    define(function(require, exports, module) {
        var a = require('./a')
        a.doSomething()
        var b = require('./b')
        b.doSomething()
    })
    // AMD 默认推荐的是
    define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好  
        a.doSomething()
        b.doSomething()
    })

    AMD与CMD的其它区别可参考地址:https://www.zhihu.com/question/20351507

    AMD

    AMD规范可参考地址:https://github.com/amdjs/amdjs-api/wiki/AMD  

    AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。

    根据AMD规范,我们可以使用define定义模块,使用require调用模块,语法:

     define(id?, dependencies?, factory);
    • id: 定义中模块的名字;可选;如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字;
    • dependencies:依赖的模块;
    • factory:工厂方法,返回定义模块的输出值。

    总结一段话:声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行,依赖前置

    例子1:

     define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
           exports.verb = function() {
               return beta.verb();
               //Or:
               return require("beta").verb();
           }
       });

    例子2:

     define(["alpha"], function (alpha) {
           return {
             verb: function(){
               return alpha.verb() + 2;
             }
           };
       });

    例子3:

       define({
         add: function(x, y){
           return x + y;
         }
       });

    例子4:

    define(function (require, exports, module) {
         var a = require('a'),
             b = require('b');
    
         exports.action = function () {};
       });

    使用require函数加载模块:

    require([dependencies],function(){});
    • 第一个参数是一个数组,表示所依赖的模块
    • 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用.加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块

    require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题

    require(['alpha'],function(alpha){
        alpha.verb ();
    })

    CMD

    CMD规范参考地址:https://github.com/seajs/seajs/issues/242  CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。

    define Function

    define 是一个全局函数,用来定义模块。

    define define(factory)

    define 接受 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串。

    factory 为对象、字符串时,表示模块的接口就是该对象、字符串。比如可以如下定义一个 JSON 数据模块:

    define({ "foo": "bar" });

    也可以通过字符串定义模板模块:

    define('I am a template. My name is {{name}}.');

    factory 为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:requireexports 和 module

    define(function(require, exports, module) {
    
      // 模块代码
    
    });

    define define(id?, deps?, factory)

    define 也可以接受两个以上参数。字符串 id 表示模块标识,数组 deps 是模块依赖。比如:

    define('hello', ['jquery'], function(require, exports, module) {
    
      // 模块代码
    
    });

    id 和 deps 参数可以省略。省略时,可以通过构建工具自动生成。

    注意:带 id 和 deps 参数的 define 用法不属于 CMD 规范,而属于 Modules/Transport 规范。

    define.cmd Object

    一个空对象,可用来判定当前页面是否有 CMD 模块加载器:

    if (typeof define === "function" && define.cmd) {
      // 有 Sea.js 等 CMD 模块加载器存在
    }

     require Function

    require 是 factory 函数的第一个参数。

    require require(id)

    require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口。

    define(function(require, exports) {
    
      // 获取模块 a 的接口
      var a = require('./a');
    
      // 调用模块 a 的方法
      a.doSomething();
    
    });

    require.async require.async(id, callback?)

    require.async 方法用来在模块内部异步加载模块,并在加载完成后执行指定回调。callback 参数可选。

    define(function(require, exports, module) {
    
      // 异步加载一个模块,在加载完成时,执行回调
      require.async('./b', function(b) {
        b.doSomething();
      });
    
      // 异步加载多个模块,在加载完成时,执行回调
      require.async(['./c', './d'], function(c, d) {
        c.doSomething();
        d.doSomething();
      });
    
    });

    注意:require 是同步往下执行,require.async 则是异步回调执行。require.async 一般用来加载可延迟异步加载的模块。

    exports Object

    exports 是一个对象,用来向外提供模块接口。

    define(function(require, exports) {
    
      // 对外提供 foo 属性
      exports.foo = 'bar';
    
      // 对外提供 doSomething 方法
      exports.doSomething = function() {};
    
    });

    除了给 exports 对象增加成员,还可以使用 return 直接向外提供接口。

    define(function(require) {
    
      // 通过 return 直接提供接口
      return {
        foo: 'bar',
        doSomething: function() {}
      };
    
    });

    module Object

    module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。

    module.id String

    模块的唯一标识。

    define('id', [], function(require, exports, module) {
    
      // 模块代码
    
    });

    上面代码中,define 的第一个参数就是模块标识。

    module.exports Object

    当前模块对外提供的接口。

    传给 factory 构造方法的 exports 参数是 module.exports 对象的一个引用。只通过 exports 参数来提供接口,有时无法满足开发者的所有需求。 比如当模块的接口是某个类的实例时,需要通过 module.exports 来实现:

    define(function(require, exports, module) {
    
      // exports 是 module.exports 的一个引用
      console.log(module.exports === exports); // true
    
      // 重新给 module.exports 赋值
      module.exports = new SomeClass();
    
      // exports 不再等于 module.exports
      console.log(module.exports === exports); // false
    
    });

    CommonJS 

    CommonJS是服务器端模块的规范,Node.js采用了这个规范.Node.JS首先采用了js模块化的概念.
    CommonJS定义的模块分为:模块引用(require)/ 模块定义(exports)/模块标识(module)

    所有代码都运行在模块作用域,不会污染全局作用域。

    模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。

    模块加载的顺序,按照其在代码中出现的顺序。

    //common.js
    module.exports = function(a, b) {
    return a-b
    }
    
    let minus = require('./common.js')  //文件相对路径
    console.log(minus(5,4)) 
    // 结果: 1

    详细可以参考《阮一峰:CommonJS规范》

    ES6

    导出

    ES6两种导出方式:

    1. 命名导出
    2. 默认导出

    命名导出

    // 写法1
    export const name = 'calculator';
    export const add = function (a,b) {
        return a + b;
    }
    
    // 写法2
    const name = 'calculator';
    const add = function (a,b) {
        return a + b;
    }
    export {name, add};

    在使用命名导出时,可以通过as关键字对变量重命名。如:

    const name = 'calculator';
    const add = function (a,b) {
        return a + b;
    }
    export {name, add as getSum};  // 在导入时即为name 和 getSum

    默认导出

    export default {
        name: 'calculator';, 
        add: function (a,b) {
            return a + b;
        }
    }; 

    导入

    针对命名导出的模块,导入方式如下:

    // calculator.js
    const name = 'calculator';
    const add = function (a,b) {
        return a + b;
    }
    export {name, add};
    
    // 一般导入方式
    import {name, add} from './calculator.js'
    add(2,3);
    
    // 通过as关键字对导入的变量重命名
    import {name, add as calculateSum} from './calculator.js'
    calculateSum(2,3);
    
    // 使用 import * as <myModule>可以把所有导入的变量作为属性值添加到<myModule>对象中,从而减少了对当前作用域的影响
    import * as calculateObj from './calculator.js'
    calculateObj.add(2,3);

    对于默认导出来说,import后面直接跟变量名,并且这个名字可以自由指定,它指代了calculator.js中默认导出的值。从原理上可以这样理解:

    import {default as myCalculator} from './calculator.js'

    还有两种导入方式混合起来使用的例子,如下:

    // index.js
    import React, {Component} from 'react';

    注:这里的React必须写在大括号前面,而不能顺序颠倒,否则会提示语法错误。

     复合写法

    在工程中,有时候需要把一个模块导入后立即导出,比如专门用来集合所有页面或组件的入口文件。此时可以采用复合形式的写法:

    export {name, add } from './calculator.js'

    复合写法只支持通过命名导出的方式暴露出来的变量,默认导出则没有对应的复合形式,只能将导入和导出拆分开。

    import calculator from './calculator.js'
    export default calculator;

     UMD

    UMD并不能说是一种模块标准,不如说它是一组模块形式的集合更准确。UMD的全称是Universal Module Definition,也就是通用模块标准。它的目标是使一个模块能运行在各种环境下,不论是CommonJS、AMD,还是非模块化的环境(当时ES6 Module还未被提出)

    (function(root, factory) {
        if (typeof define === 'function' && define.amd) {
            // AMD
            define(['jquery'], factory);
        } else if (typeof exports === 'object') {
            // Node, CommonJS之类的
            module.exports = factory(require('jquery'));
        } else {
            // 浏览器全局变量(root 即 window)
            root.returnExports = factory(root.jQuery);
        }
    }(this, function($) {
        // 方法
        function myFunc() {};
    
        // 暴露公共方法
        return myFunc;
    
    }));

     详细可参考:《可能是最详细的UMD模块入门指南》《AMD , CMD, CommonJS,ES Module,UMD》

  • 相关阅读:
    钱多,人傻,快来快来
    Rabbitmq的使用及Web监控工具使用
    Fiddler的配置
    哪个微信编辑器比较好用?
    js手机号批量滚动抽奖代码实现
    Webform和MVC,为什么MVC更好一些?
    自学MVC看这里——全网最全ASP.NET MVC 教程汇总
    客如云系统访谈
    Asp.Net MVC2.0 Url 路由入门---实例篇
    架设自己的FTP服务器 Serv-U详细配置图文教程
  • 原文地址:https://www.cnblogs.com/moqiutao/p/13268861.html
Copyright © 2020-2023  润新知