概述
JavaScript 模块化:CommonJS、AMD、CMD、UMD、ES Module
为什么要模块化
用原始方式加载,所有变量都挂载在window对象上,前端功能越来越多,引用的包越来越多,难免会有冲突。因此需要模块化来区分不同的功能。
以下简述下各种模块化方案的使用方法,只做了解,不做深入。
在webpack和babel工具统治下,我们只需要学好ES Module 即可
一、commonJS(CJS)
特点
-
所有代码都运行在模块作用域,不会污染全局作用域。
-
模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
-
模块加载的顺序,按照其在代码中出现的顺序。
nodejs中默认使用commonJS规范,适用于后端开发。
用法
简约写法(需要构建工具额外支持)
// 引入
const moment = require('moment');
const getDateFormat = function (value) {
return moment(value).format('L');
};
const data = {}
// 导出方式一
exports.data = data;
// 导出方式二
module.exports.getDateFormat = getDateFormat;
// 导出方式三
module.exports = {
data,
getDateFormat
}
// 错误的方式
exports = {
data,
getDateFormat
}
使用webpack 构建
- 输出代码
// util.js
(function(module, exports, require) {
// 引入
const moment = require('moment');
const getDateFormat = function (value) {
return moment(value).format('L');
};
const data = {}
module.exports = {
data,
getDateFormat
}
})(module, module.exports, require)
- 模块管理中心
// tiny-browser-require
function require(p){
var path = require.resolve(p);
var mod = require.modules[path];
if (!mod) throw new Error('failed to require "' + p + '"');
if (!mod.exports) {
mod.exports = {};
mod.call(mod.exports, mod, mod.exports, require.relative(path));
}
return mod.exports;
}
require.modules = {};
require.resolve = function (path){
var orig = path;
var reg = path + '.js';
var index = path + '/index.js';
return require.modules[reg] && reg
|| require.modules[index] && index
|| orig;
};
require.register = function (path, fn){
require.modules[path] = fn;
};
require.relative = function (parent) {
return function(p){
if ('.' != p.charAt(0)) return require(p);
var path = parent.split('/');
var segs = p.split('/');
path.pop();
for (var i = 0; i < segs.length; i++) {
var seg = segs[i];
if ('..' == seg) path.pop();
else if ('.' != seg) path.push(seg);
}
return require(path.join('/'));
};
};
require.register("moment",momentSource);
require.register("./util.js", function(module, exports, require){
// 引入
const moment = require('moment');
const getDateFormat = function (value) {
return moment(value).format('L');
};
const data = {}
// 导出方式一
exports.data = data;
// 导出方式二
module.exports.getDateFormat = getDateFormat;
// 导出方式三
module.exports = {
data,
getDateFormat
}
// 错误的方式
exports = {
data,
getDateFormat
}
});
const util = require('./util');
util.getDateFormat(new Date());
二、AMD (RequireJS)
特点
AMD规范则是非同步加载模块,允许指定回调函数。
适用前端模块化开发。
用法
define(id?, dependencies?, factory);
- 无依赖
define(function(){
const log = function (...args) {
return console.log(...args);
};
return {
log
}
})
- 有具体名字
define('base',function(){
const log = function (...args) {
return console.log(...args);
};
return {
log
}
})
- 有依赖
// util.js
define("util", ["moment"], function(moment){
const getDateFormat = function (value) {
return moment(value).format('L');
};
const data = {}
return {
data,
getDateFormat
}
})
- 包装模块(向commonJS妥协)
define(function(require, exports, module) {
const moment = require('moment');
const getDateFormat = function (value) {
return moment(value).format('L');
};
module.exports = {
getDateFormat
}
});
- 加载模块
// 加载模块
require(['util'], function (util){
util.getDateFormat(new Date());
});
三、CMD(sea.js)
https://www.jianshu.com/p/890c83fbcf50
define(function(require,exports,module){...});
很明显在使用方式来说,CMD是AMD的子集。区别在于加载机制不同。
- AMD在加载完成定义(define)好的模块就会立即执行,所有执行完成后,遇到require才会执行主逻辑。(提前加载)
- CMD在加载完成定义(define)好的模块,仅仅是下载不执行,在遇到require才会执行对应的模块。(按需加载)
- AMD用户体验好,因为没有延迟,CMD性能好,因为只有用户需要的时候才执行。
四、UMD(Universal Module Definition)
集结了 CommonJs、CMD、AMD 的规范于一身,没有自己的标准,只为适配多种模块化存在。
((root, factory) => {
if (typeof define === 'function' && define.amd) {
//AMD
define(['moment','exceljs'], factory);
} else if (typeof exports === 'object') {
//CommonJS
module.exports = factory(requie('jquery'),require('exceljs'));
} else {
root['util'] = factory(root.moment,root.exceljs);
}
})(this, (moment,exceljs) => {
const getDateFormat = function (value) {
return moment(value).format('L');
};
const exportExcel = function(column,dataSource){
exceljs.export('xx.xlsx',column,dataSource)
}
return {
exportExcel,
getDateFormat
}
});
五、ES Module (ES6)
ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
- export
// util.js
import moment from 'moment';
export const getDateFormat = function (value) {
return moment(value).format('L');
};
const data = {}
export default data;
- import
// app.js
import data,{ getDateFormat } from './util';
因为需要支持古董浏览器,所以需要用webpack、babel构建出AMD/CMD,CJS
。
babel转ES Module例子:
// rc-select es/index.js
import Select from './Select';
import Option from './Option';
import OptGroup from './OptGroup';
export { Option, OptGroup };
export default Select;
转换后:
// rc-select lib/index.js
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
// 只读
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "Option", {
enumerable: true,
get: function get() {
return _Option.default;
}
});
Object.defineProperty(exports, "OptGroup", {
enumerable: true,
get: function get() {
return _OptGroup.default;
}
});
exports.default = void 0;
var _Select = _interopRequireDefault(require("./Select"));
var _Option = _interopRequireDefault(require("./Option"));
var _OptGroup = _interopRequireDefault(require("./OptGroup"));
var _default = _Select.default;
exports.default = _default;
babel,直接require的非ES模块的对象加个default属性,使得与ESModule保持一致。
// @babel/runtime/helpers/interopRequireDefault
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
"default": obj
};
}
module.exports = _interopRequireDefault;
最后
以上就是如意摩托为你收集整理的JavaScript 模块化:CommonJS、AMD、CMD、UMD、ES ModuleJavaScript 模块化:CommonJS、AMD、CMD、UMD、ES Module的全部内容,希望文章能够帮你解决JavaScript 模块化:CommonJS、AMD、CMD、UMD、ES ModuleJavaScript 模块化:CommonJS、AMD、CMD、UMD、ES Module所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复