es6模块(amd标准)和node使用的标准(commonjs)模块的区别
- CommonJs模块是在运行加载,ES6是在编译时输出接口(使得静态分析成为可能,才可以对代码执行treesharking)
- CommonJs模块输出的是一个值的复制(不变),ES6模块输出的是值的引用(可变)。
注:es6的export语句输出的接口与其对应的值是动态绑定关系,通过该接口可以取到模块内部的实时值。CommonJs的规范完全不同,CommonJs模块输出的是值得缓存,不能动态更新。
CommonJs模块的导出示例
//lib.js
var counter = 1;
function incCounter(){
counter ++;
}
module.exports = {
counter:counter,
incCounter: incCounter
}
// main.js
var mod = require("./lib.js")
console.log(mod.counter) // 1
mod.incCounter();
console.log(mod.counter) // 1
说明lib.js模块加载以后内部变化就不会影响到输出的值。因为mod.counter是一个原始类型的值,会被缓存。如果写成函数,就可以得到内部变动的值。
//lib.js
var counter = 1;
function incCounter(){
counter ++;
}
module.exports = {
get counter(){
return counter
},
incCounter: incCounter
}
// main.js
var mod = require("./lib.js")
console.log(mod.counter) // 1
mod.incCounter();
console.log(mod.counter) // 2
ES6模块的导出示例
// lib.js
export let counter = 1;
export function incCounter(){
counter ++;
}
// main.js
import {counter, incCounter} from './lib.js'
console.log(counter) //1
incCounter()
console.log(counter) //2
ES6模块是动态引用,JS引擎对脚本做静态分析时,遇到模块加载命令import会生成一个只读对象的引用,不会缓存值,等待脚本执行期间,再根据这个只读引用到被加载的模块中取值。
Es6在编译时做静态分析,可以使用tree-shaking功能。
注意,ES6模块整体加载所在的那个对象是只读的,应该是静态的,所以不允许运行时改变。
// lib.js
export let obj = {}
// main.js
import {obj} from './lib.js'
obj.prop = 12 //可以执行
obj = {name:"oob"} // TypeError
不允许给引入的对象赋值
ES6中,export命令只能出现在模块顶层,即不能放在函数或条件语句块中(否则没法做静态优化),在模块的任何位置都可以。
import()类似于Node的require方法,主要区别是,import()是异步加载,require是同步加载。commonjs是同步加载的,没法直接使用tree-shaking功能。