JS模块化规范之ES6及UMD

JS模块化规范之ES6及总结

前言

ESM在模块之间的依赖关系是高度确定的,与运行状态无关,编译工具只需要对ESM模块做静态分析,就可以从代码字面中推断出哪些模块值未曾被其它模块使用,这是实现Tree Shaking技术的必要条件。

ES6模块化

概念

ES6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJSAMD模块,都只能在运行时确定这些东西。比如,CommonJS模块就是对象,输入时必须查找对象属性。

基本使用

export命令用于规定模块的对接接口,import命令用于输入其他模块提供的功能。

js 复制代码
/** 定义模块 math.js /
var basicNum = 0;
var add = function(a,b){
	return a + b;
};
export { basicNum,add };
*/
//引用模块
import { basicNum,add } from './math';
function test(){
	ele.textContext = add(99+basicNum);
}

如上例所示,使用import命令的时候,用户需要知道所要加载的变量名和或函数名,否则无法加载。为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。

js 复制代码
//export-default.js
export default function(){
	console.log('foo');
}
//import-default.js
import customName from './export-default';
customName(); // 'foo'

模块默认输出,其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。

ES6模块与CommonJS模块的差异

  1. CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用;
  2. CommonJS模块是运行时加载,ES6模块是编译时输出的接口;

第二个差异是因为CommonJS加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而ES6模块不是对象,他的对接接口只是一种静态定义,在代码静态解析阶段就会生成。

下面重点解释第一个差异,我们还是举上边这个CommonJS模块的加载机制例子:

js 复制代码
//lib.js
export let counter = 3;
export function incCounter(){
	counter++;
}
//main.js
import { counter,incCounter } from './lib';
console.log(counter);//3
incCounter();
console.log(counter);//4

ES6模块的运行机制与CommonJS不一样。ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

ES6实现

简单来说就一句话:使用Babel将ES6编译为ES5代码,使用Browserify编译打包js。

  1. 定义package.json文件
js 复制代码
{
	"name":"es6-balel-browserify",
	"version":"1.0.0"
}
  1. 按装babel-cli,babel-perset-es2015和browserify
linux 复制代码
npm install babel-cli browserify -g
npm install babel-perset-es2015 --save-dev
  1. 定义.babelrc文件
js 复制代码
{
	"presets":["es2015"]
}
  1. 定义模块代码
js 复制代码
//module1.js文件
//分别暴露
export function foo(){
	console.log('foo() module1')
}
export function bar(){
	console.log('bar() module1')
}
//module2.js文件
function fun1(){
	console.log('fun1() module2')
}
function fun2(){
	console.log('fun2() module2')
}
export { fun1,fun2 }

//module3.js文件
// 默认暴露 可以暴露任意数据类型,暴露什么数据,接收到就是什么数据
export default()=>{
	console.log('默认暴露')
}
//app.js文件
import { foo,bar } from './module1'
import { fun1,fun2 } from './module2'
import module3 from './module3'
foo()
bar()
fun1()
fun2()
module3()
  1. 编译并在index.html引入
    • 使用Babel将ES6编译为ES5代码(但包含CommonJS语法):babel js/src -d js/lib
    • 使用Browserify编译js:browserify js/lib/app.js -o js/lib/bundle.js然后在index.html文件中引入
js 复制代码
<script type="text/javascript" src="js/lib/bundle.js"></script>

最后得到如下结果:

js 复制代码
foo() module1
bar() module1
fun1() module2
fun2() module2
默认暴露
  1. 引入第三方库
    首先安装依赖npm install jquery@1
js 复制代码
//app.js
import { foo bar } from './module1'
import { fun1,fun2 } from './module2'
import module3 from './module3'
import $ from 'jquery'

foo()
bar()
fun1()
fun2()
module3()
$('body').css('background','green')

UMD(Universal Module Definition)

是一种JavaScript通用模块定义规范,让你的模块能在JavaScript所有运行环境中发挥作用。

意味着要同时满足CommonJS,AMD,CMD的标准,一下为实现:

js 复制代码
(function (root,factory){
	if(typeof module === 'object' && typeof module.exports === 'object'){
		console.log('是CommonJS模块规范,nodejs环境');
		module.exports = factory();
	}else if(typeof define === 'function' && define.amd){
		console.log('是AMD模块规范,如require.js')
		define(factory)
	}else if(typeof define === 'function' && define.cmd){
		console.log('是CMD模块规范,如sea.js')
		define(function(require,exports,module){
			module.exports = factory()
		})
	}else{
		console.log('没有模块环境,直接挂载在全局对象上')
		root.umdModule = factory();
	}
}(this,function(){
	return {
		name:'我是一个UMD模块'
	}
}))

总结

  1. CommonJS规范主要用于服务端编程,加载模块是同步的,这并不适合在浏览器环境,因为同步意味着阻塞加载,浏览器资源是异步加载的,因此有了AMD CMD解决方案;
  2. AMD规范是在浏览器环境中异步加载模块,而且可以并行加载多个模块。不过,AMD规范开发成本高,代码的阅读和书写比较困难,模块定义方式的语义不顺畅;
  3. CMD规范AMD规范很相似,用于浏览器编程,依赖就近,延迟执行,可以很容易在Node.js中运行
  4. ES6在语言标准的层面上,实现了模块功能,而且实现的相当简单,完全可以取代CommonJSAMD规范,成为浏览器和服务器通用的模块解决方案;
  5. UMD为同时满足CommonJS、AMD、CMD标准的实现;

好啦~JS模块化规范就说完啦!欢迎友友们留言讨论哟!

相关推荐
WeiXiao_Hyy5 分钟前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡22 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone28 分钟前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09011 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king1 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳2 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵2 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星2 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_3 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js