全面理解JS模块的标准(AMD、CMD、COMMON.JS 、 UMD、ESM)

本文介绍了JavaScript模块规范的发展历程,包括AMD、CMD、CommonJS、UMD和ESM。AMD(异步模块定义)如require.js,CMD(通用模块定义)如sea.js,CommonJS主要在Node.js中使用,UMD为了兼容多种环境,而ESM(ECMAScript模块)成为现代浏览器和Node.js的标准。文章通过示例解释了各种规范的使用方式,并指出目前ESM是最流行的选择。

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

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

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

一、amd - 浏览器中的js模块化解决方案
AMD 全称是 Async Module Definition -中文: 异步模块化定义

require.js是AMD模块规范的一个具体实现

核心是通过define方法对无序的代码进行有序的模块化定义,通过require方法实现代码的模块化加载

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其他主流浏览器都支持了)
————————————————
版权声明:本文为优快云博主「春风得意之时」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/u012513962/article/details/124187656

VM23268 uplodPython.vue:58 [Vue warn]: Missing required prop: "percentage" found in ---> <ElProgress> at packages/progress/src/progress.vue <FlowerClassifierAvatar> at src/views/uplodPython.vue <App> at src/App.vue <Root> warn @ vue.runtime.esm.js:4644 assertProp @ vue.runtime.esm.js:5178 validateProp @ vue.runtime.esm.js:5138 _loop_1 @ vue.runtime.esm.js:5433 initProps$1 @ vue.runtime.esm.js:5459 initState @ vue.runtime.esm.js:5402 Vue._init @ vue.runtime.esm.js:5726 VueComponent @ vue.runtime.esm.js:5861 createComponentInstanceForVnode @ vue.runtime.esm.js:4583 init @ vue.runtime.esm.js:4445 createComponent @ vue.runtime.esm.js:6602 createElm @ vue.runtime.esm.js:6556 createChildren @ vue.runtime.esm.js:6675 createElm @ vue.runtime.esm.js:6579 createChildren @ vue.runtime.esm.js:6675 createElm @ vue.runtime.esm.js:6579 createChildren @ vue.runtime.esm.js:6675 createElm @ vue.runtime.esm.js:6579 patch @ vue.runtime.esm.js:7144 Vue._update @ vue.runtime.esm.js:3810 updateComponent @ vue.runtime.esm.js:3916 Watcher.get @ vue.runtime.esm.js:3487 Watcher.run @ vue.runtime.esm.js:3563 flushSchedulerQueue @ vue.runtime.esm.js:4162 eval @ vue.runtime.esm.js:3184 flushCallbacks @ vue.runtime.esm.js:3106 Promise.then timerFunc @ vue.runtime.esm.js:3131 nextTick @ vue.runtime.esm.js:3196 queueWatcher @ vue.runtime.esm.js:4248 Watcher.update @ vue.runtime.esm.js:3554 Dep.notify @ vue.runtime.esm.js:780 reactiveSetter @ vue.runtime.esm.js:1010 proxySetter @ vue.runtime.esm.js:5395 recognizeImage @ VM23268 uplodPython.vue:58 await in recognizeImage handleAvatarSuccess @ VM23268 uplodPython.vue:50 handleSuccess @ element-ui.common.js:29874 onSuccess @ element-ui.common.js:29584 onload @ element-ui.common.js:29270 XMLHttpRequest.send upload @ element-ui.common.js:29286 post @ element-ui.common.js:29592 upload @ element-ui.common.js:29547 eval @ element-ui.common.js:29511 uploadFiles @ element-ui.common.js:29509 handleChange @ element-ui.common.js:29490 invokeWithErrorHandling @ vue.runtime.esm.js:3058 invoker @ vue.runtime.esm.js:1859 original_1._wrapper @ vue.runtime.esm.js:7508 vue.runtime.esm.js:4644 [Vue warn]: Invalid prop: type check failed for prop "percentage". Expected Number with value 85.92, got String with value "85.92". found in ---> <ElProgress> at packages/progress/src/progress.vue <FlowerClassifierAvatar> <App> at src/App.vue <Root>
10-22
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值