模块
CMD/AMD/UMD/ES6
AMD 与 CMD:
AMD是 RequireJS 在推广过程中对模块定义的规范化产出。
CMD是 SeaJS 在推广过程中对模块定义的规范化产出。
CMD推崇依赖就近,AMD推崇依赖前置。
ES Module与CommonJS:
CommonJS模块是对象,是运行时加载,运行时才把模块挂载在exports之上(加载整个模块的所有),加载模块其实就是查找对象属性。
ES Module不是对象,是使用export显示指定输出,再通过import输入。此法为编译时加载,编译时遇到import就会生成一个只读引用。等到运行时就会根据此引用去被加载的模块取值。所以不会加载模块所有方法,仅取所需。
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口
CommonJS与AMD/CMD:
AMD/CMD是CommonJS在浏览器端的解决方案。
CommonJS是同步加载(代码在本地,加载时间基本等于硬盘读取时间)。
AMD/CMD是异步加载(浏览器必须这么做,代码在服务端)
UMD与AMD/CMD
UMD(Universal Module Definition)是AMD和CommonJS的糅合,跨平台的解决方案。
AMD模块以浏览器第一的原则发展,异步加载模块。
CommonJS模块以服务器第一原则发展,选择同步加载,它的模块无需包装(unwrapped modules)。
UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式。再判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。
用法
umd 模块(通用模块)
如果你在js
文件头部看到这样的代码,那么这个文件使用的就是 UMD
规范
实际上就是 amd + commonjs + 全局变量 这三种风格的结合
这段代码就是对当前运行环境的判断,如果是 Node
环境 就是使用 CommonJs
规范, 如果不是就判断是否为 AMD
环境, 最后导出全局变量
有了 UMD
后我们的代码和同时运行在 Node
和 浏览器上
所以现在前端大多数的库最后打包都使用的是 UMD
规范
CommonJS
CommonJS
是 JavaScript 的一个模块化规范,主要用于服务端Nodejs 中,当然,通过转换打包,也可以运行在浏览器端。毕竟服务端加载的模块都是存放于本地磁盘中,所以加载起来比较快,不需要考虑异步方式。
导出使用module.exports,也可以exports。就是在此对象上挂属性。exports指向module.exports,即exports= module.exports
加载模块使用require('xxx')。相对、绝对路径均可。默认引用js,可以不写.js后缀
AMD/RequireJS
Asynchronous Module Definition:异步模块定义。
也就是解决我们上面说的 CommonJS 在浏览器端致命的问题:假死。
CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是异步加载模块,允许指定回调函数。
由于这并非原生 js 所支持的那种写法。所以使用 AMD 规范开发的时候就需要大名鼎鼎的函数库 require.js
的支持了。
定义模块:define(id?, dependencies?, factory)
依赖有三个默认的,即"require", "exports", "module"。顺序个数均可视情况
如果忽略则factory默认此三个传入参数
id一般是不传的,默认是文件名
加载模块:require([module], factory)
CMD/SeaJS
CMD是阿里的玉伯提出来的(大神的成长故事可在公众号回复【大佬】),js 的函数为 sea.js
,它和 AMD 其实非常的相似,文件即为模块,但是其最主要的区别是实现了按需加载。推崇依赖就近的原则,模块延迟执行
定义模块:define(factory)
require, exports, module参数顺序不可乱
暴露api方法可以使用exports、module.exports、return
与requirejs不同的是,若是未暴露,则返回{},requirejs返回undefined
加载模块:require
定义模块无需列依赖,它会调用factory的toString方法对其进行正则匹配以此分析依赖
预先下载,延迟执行
ES Module
输出/export
输入/import
输入的模块变量是不可重新赋值的,它只是个可读引用,不过却可以改写属性
总结:
区别项
es模块化
commonJS
AMD
可用于服务端还是浏览器
服务端和浏览器
服务端
浏览器
模块依赖关系何时确定(即:何时加载模块)
编译时
运行时
运行时
设计思想
尽量的静态化
模块是不是对象
不是
是
是否整体加载模块(即加载的所有方法)
否
是
是否是动态更新(即通过接口,可以取到模块内部实时的值)
是。es module输出的是值的引用
不是。commonJS模块输出的是值的拷贝,不存在动态更新
模块变量是否是只读的
v是。原因:ES6 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。
commonJS模块就是对象,整体加载模块(即加载的所有方法)
ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系
export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时
export命令和import命令可以出现在模块的任何位置,只要处于模块顶层就可以。 如果处于块级作用域内,就会报错,这是因为处于条件代码块之中,就没法做静态优化了,违背了ES6模块的设计初衷。
import命令具有提升效果,会提升到整个模块的头部,首先执行。
CommonJs 和 ES6 Module 的区别
其实上面我们已经说到了一些区别
CommonJs
导出的是变量的一份拷贝,ES6 Module
导出的是变量的绑定(export default
是特殊的)CommonJs
是单个值导出,ES6 Module
可以导出多个CommonJs
是动态语法可以写在判断里,ES6 Module
静态语法只能写在顶层CommonJs
的this
是当前模块,ES6 Module
的this
是undefined
核心区别:
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
ES6 import 的顺序?
最后更新于