JS模块系统:
传统方法:
script加载
defer/async 渲染完执行/下载完执行
AMD 、 CMD、 CommonJS、 ES6 Modules
AMD define([‘a’,’b’],function(){}) 提前执行 依赖前置
CMD define(function(){
a = require('a')
})
延迟执行 依赖就近
CommonJs node规则
ES6 Modules
ES6的模块不是对象,import命令会被 JavaScript 引擎静态分析,在编译时就引入模块代码,而不是在代码运行时加载,所以无法实现条件加载。也正因为这个,使得静态分析成为可能。
ES6 Modules Vs CommonJs
CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
运行时加载: CommonJS 模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。
编译时加载: ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,import时采用静态命令的形式。即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载称为“编译时加载”。
CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
CommonJs总结:生成一个对象,然后再从这个对象上面读取属性。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象。运行时,当遇到require命令,就会全部执行,输出已执行部分,未执行部分不输出(这也是CommonJS解决循环加载的办法)
ES6 模块是动态引用,并且不会缓存值。这样宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能就有机会在JS里实现了。但是由于import是静态执行,所以不能使用表达式、变量、if结构,这些只有在运行时才能得到结果的语法结构,也就无法直接实现条件加载,按需加载等功能。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
CommonJS 模块输出的是值的拷贝,ES6 模块输出的是值的引用。