找遍度娘,发现好多文章都是拿来主义,阮一峰老师ECMAScript6入门的文档各种花式开枝散叶,语法上阮一峰老师讲的已经非常细致了,但是概念上的东西我还是有点模糊。
文档里讲了ES6模块加载和CommonJS的区别(ES5的模块引用表现形式可能有些不同,但本质其实都是把模块作为对象引用,所以这个区别也是ES6和ES5模块引用的区别):
1.CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
2.CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
我这人比较懒,不太习惯单纯的copy,强烈推荐大家先看一下阮一峰老师的
文档里针对这两点做了详细的解释,针对第一点解释说ES6 模块不是对象,那我就想知道不是对象他到底是什么,百度了好久,终于在google搜索的第一篇的文章里找到了答案:
每一个 ES6 模块都是一个包含 JS 代码的文件,模块本质上就是一段脚本,而不是用module关键字定义一个模块。其实我想知道的就是这句话, ES6 模块是脚本。
根据上面得到的概念,不难理解CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。 CommonJS的模块本质是一个对象的引用,因此需要运行时加载。而ES6的module其实就是引入了一个新的概念,模块不是对象而是脚本,这样就可以在编译的时候加载。
至于CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。这个点我们可以想象一下import和export到底做了什么,它们在程序加载的时候组成一对不同于"="的对应关系。
举个例子
case1 CommonJS模块引用//a.jslet func=require('./b').func, a=require('./b').b;a=1;func();//输出2//b.jslet b=2;function func() { console.log(b);}module.exports = { func: func, b: b};复制代码
case2 ES6模块引用
//a.mjsimport {b as a} from "./b.mjs"import {func} from "./b.mjs"a=1;//报错func();//b.mjsexport function func() { console.log(b)}export let b=2;复制代码
再来一张在下的大作
正常情况下,我们把一个存放值的变量b赋值给变量a,其实就是把b里面存放的值放进a的存储空间中,这一点没什么异议。而case1这种情况,CommonJS 模块是一个正常的JS对象,a=require('./b').b
等同于a=b
所以遵循JS的变量赋值的规则。
ES6 模块输出的是值的引用。在ES6中,case3这种情况下,如果我们试图直接修改a的值会报错,因为a不是b,a是指向变量b的变量,如果要修改a的值,只有在被引用的模块里修改b的值,a的值才会发生改变。所以我们可以认为export和import带来的关系是,a的存储空间指向变量b,并且这个关系不可以被破坏。
参考
[深入浅出 ES6(十六):模块 Modules]