在前端的世界演变里,有着几种JS的模块规范,从出现的顺序来说就是:

①amd
②cmd
③common.js
④ umd
⑤ esm

现在Vue框架里面都是遵守esm规范,不得不说esm是目前最好最流行的一种js规范了

一、amd - 浏览器中的js模块化解决方案

AMD 全称是 Async Module Definition -中文: 异步模块化定义
require.js是AMD模块规范的一个具体实现
1、通过define方法定义模块
base.js

define(function (){
    var control = {};
    return control;
});

control.js

define(['jquery', 'jqmd5', 'cookie', 'base'], function (){
    var control = {};
 
    /**
     * 登录状态检测
     */
    control.cookie = function (){
        setTimeout(WK.LC.syncLoginState, 100);
    };
 
    /**
     * 模块调用及配置
     */
    control.template = function (){
        if($('.naver').length > 0) base.naver();
 
        if(CATEGORY == 'login')
        {
            if(MODEL == 'index'){
                // 登录页
                require(['login'], function (Login){
                    Login.form();
                });
            };
 
            if(MODEL == 'register' || MODEL == 'check'){
                // 注册页
                require(['register'], function (Register){
                    Register.form(MODEL);
                });
            };
        };
 
        if(CATEGORY == 'goods')
        {
            // 详情页
            if(MODEL == 'index'){
                require(['detail'], function (Detail){
                    // Detail.form();
                });
            };
        };
    };
 
    return control;
});

2、通过require方法加载模块(异步加载)

注意:参数里面有define声明的模块

require(['control'], function (Control){
    Control.cookie();
    Control.template();
});

二、cmd - 类似amd的用于浏览器中的js模块规范

CMD 全称是 Common Module Definition -中文: 通用模块化定义
sea.js是CMD模块规范的一个具体实现 Sea.js 文档 Seajs github
在定义模块方面, CMD和AMD一样通过define函数来定义模块; 两者的主要区别在于对依赖的加载上, CMD中不需要在define的参数中直接声明需要用到的模块
1、通过define方法定义模块
calculator.js

define('calculator', function(require, exports) {
    // 通过require方法加载其他模块
    var math = require('math');
    exports.add = function(left, right) { return math.add(left, right) };
    exports.subtract = function(left, right) { return math.subtract(left, right) };
})

可以看到calculator模块所的依赖的math模块没有在define函数的参数中进行声明, 而是通过require(‘math’)来引入的

2、使用calculator模块

seajs.use(['calculator'], function(calculator) {
    console.log('1 + 1 = ' + calculator.add(1, 1));
    console.log('2 - 2 = ' + calculator.subtract(2, 1));
})

三、common.js -Node中使用的模块规范

通过exports和module.exports来暴露模块中的内容。
通过require来加载模块。
demo
1、通过exports 暴露模块接口
study.js

var hello = function () {
    console.log('hello studygd.com.');
}
exports.hello = hello;

main.js

const studygd = require('./study');
studygd.hello();

2、通过module.exports 暴露模块接口
定义math模块
math.js

module.exports = {
    add: function(left, right) {
        return left + right;
    },
    subtract: function(left, right) {
        return left - right;
    }
}

使用刚才定义的math模块, 并再定义一个calculator模块
calculator.js

const math = require('./math.js');
module.exports = {
    add: math.add
}

四、umd - 一种同时兼容了amd cmd common.js的规范

amd cmd 通常只能在浏览器中使用, commonjs只能在服务端(Node)**环境下使用, 这样子搞会导致我们基于其中某一种模块规范写的js模块无法在服务端和浏览器端进行复用.

umd解决了这个问题, 它兼容并包, 使得使用此规范写的 js模块既可以在浏览器环境下使用, 也可以在Node(服务端)环境中用

(function (root, factory) {
    if (typeof exports === 'object' && typeof module === 'object')
        // commonjs
        module.exports = factory()
    else if (typeof define === 'function' && define.amd)
        // amd、cmd
        define([], factory)
    else if (typeof exports === 'object')
        // commonjs
        exports['math'] = factory()
    else
        // 全局对象, 浏览器中是 window
        root['math'] = factory()
})(this, function() {
    return { add: function(left, right) { return left + right; } }
})

*其实只要你看过jq源码,你就会觉得 上面的这段代码很熟悉,是的,jq源码里面就是采用了umd规范去做兼容,所以jq可以说是umd规范的一种代表

附:jq源码大体框架

( function( global, factory ) {
 
    "use strict";
 
    if ( typeof module === "object" && typeof module.exports === "object" ) {
 
        // For CommonJS and CommonJS-like environments where a proper `window`
        // is present, execute the factory and get jQuery.
        // For environments that do not have a `window` with a `document`
        // (such as Node.js), expose a factory as module.exports.
        // This accentuates the need for the creation of a real `window`.
        // e.g. var jQuery = require("jquery")(window);
        // See ticket #14549 for more info.
        module.exports = global.document ?
            factory( global, true ) :
            function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };
    } else {
        factory( global );
    }
 
// Pass this if window is not defined yet
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
 
    //这里编写jquery主体代码...
 
    // AMD
    if ( typeof define === "function" && define.amd ) {
        define( "jquery", [], function() {
            return jQuery;
        } );
    }
 
    var
        // Map over jQuery in case of overwrite
        _jQuery = window.jQuery,
 
        // Map over the $ in case of overwrite
        _$ = window.$;
 
    jQuery.noConflict = function( deep ) {
        if ( window.$ === jQuery ) {
            window.$ = _$;
        }
 
        if ( deep && window.jQuery === jQuery ) {
            window.jQuery = _jQuery;
        }
 
        return jQuery;
    };
 
    if ( !noGlobal ) {
        window.jQuery = window.$ = jQuery;
    }
 
    return jQuery;
} );

五、esm - ES6模块规范

使用import导入模块,通过export导出模块
math.js

export { add: (left, right) => left + right; }

在calculator.js导入

import { add } from './math.js';
 
console.log('1 + 1 = ' + add(1, 1));

总结
amd, cmd曾经是个很流行的js模块化产物,记得自己出来工作不久,去面试的时候,也被问过这个两个有什么不一样(上面已经答案),到底使用哪个好等问题,那时自己也是模糊不清,具体回答的不是很清楚,也许是当时那个公司在使用这些规范才考察我,不过现在amd、cmd感觉基本上是没有公司项目在使用了, 现在常用的模块规范一般就是es6模块和commonjs(只用于node)了, node中也已经提供了实验性的es模块支持.

随着微软放弃IE ,现代浏览器对es的import和export的支持也已经很不错了(除了IE其他主流浏览器都支持了)

标签: none

添加新评论