记录ES6 的模块化使用以及CommonJS的对比
构建扩展性强、复用性强一直是我编码的追求点。但工作中项目比较传统,感触不深,平时有所接触,学习使用Node
时使用过require
;使用React
使用过import
;再系统学习记录为好!
export
模块导出;每个模块指的是一个文件、不管文件中指向的是变量、函数、对象,对外使用export
后是一个模块对象。
导出的模块都是严格模式
use strict
user.js
// export
export const name = "admin";
export function getAge(){
return Math.random()*100;
}
index.js
import {name,getAge} from "./user";
console.log(name,getAge());
由于浏览器不支持,也不能直接测试,所以使用了es6-module-transpiler
转换后执行的测试结果
- 安装:注意安装时要全局安装,使得
compile-modules
命令全局可用。(安装完之后关掉窗口再打开使命令生效)npm install -g es6-module-transpiler
- 执行转化操作,主入口文件时
index.js
,在创建一个副本index-copy.js
用于接收转后的内容。compile-modules convert -o index-copy.js index.js
- 转换后的文件内容、还有个
index-copy.js.map
文件(function() { "use strict"; var $$user$$name = "admin"; function $$user$$getAge(){ return Math.random()*100; } console.log($$user$$name,$$user$$getAge()); }).call(this); //# sourceMappingURL=index-copy.js.map
- 执行
index-copy.js
,得到结果:
第一组:
第二组:
如果这样导入操作:
index.js
import name from "./user";
console.log(name);
转义时报错:error: compile-modules convert -- import default at index.js:1:8 has no matching export in ./user.js
即:模块的导入时一个整体的模块的对象导入,再引用使用内部的属性、方法等。
模块整体引入
使用*
可以整体引入模块,为了方便调用,给定一个别名* as ***
index.js
import * as user from "./user";
console.log(user.name,user.getAge());
相继的转义后的内容也不一样。
index-copy.js
(function() {
"use strict";
var $$user$$ = {
get name() {
return $$user$$name;
},
get getAge() {
return $$user$$getAge;
}
};
var $$user$$name = "admin";
function $$user$$getAge(){
return Math.random()*100;
}
console.log($$user$$.name,$$user$$.getAge());
}).call(this);
//# sourceMappingURL=index-copy.js.map
可以看到一些结构,慢慢理解这种转义工具是怎么工作的。
使用module
命令导入整体模块。搞不了,直接报错
export default
上面的例子中不管怎么导入,最后使用都必须知道这个模块中的变量名name
、方法名getAge
等,就很麻烦。通过export default
默认导出给与别名即可,只需要知道怎么用而不用关心它叫什么。
因为是默认导出,所以这个
export default
命令在模块中只允许使用一次
user.js
export var name = "admin";
export function getAge(){
return Math.random()*100;
}
var title = "user";
export default title;
当然,写法多种多样,也可以不声明,直接导出export default "user"
.
index.js
import title,* as user1 from "./user";
console.log(user1.name,user1.getAge(),title);
export default
默认导出的是一个值,导入时title
指向的就是默认输出。
* as user1
则接受的时指定名称的变量、方法。
转义后的结果:
(function() {
"use strict";
var $$user$$ = {
get name() {
return $$user$$name;
},
get getAge() {
return $$user$$getAge;
},
get default() {
return $$user$$default;
}
};
var $$user$$name = "admin";
function $$user$$getAge(){
return Math.random()*100;
}
var $$user$$title = "user";
var $$user$$default = $$user$$title;
console.log($$user$$.name,$$user$$.getAge(),$$user$$default);
}).call(this);
//# sourceMappingURL=index-copy.js.map
可以看到使用export default
命令导出的属性是default
。
import
前面的导出已经用到导入,用来接收模块中导出的变量、方法。导入的是一个整体
基本的应用在上面的例子中。
import
命令会提升到模块的头部执行。
导入执行:
即在其他模块中无引用操作,只做初始化数据时用。
index.js
import "./user";
```
`user.js`
```js
export default function(){
console.log("user model");
};
按照这样转以后执行是不会有任何输出的,模块导入但是没有调用执行。
user.js
导出的是执行后的结果,内部的代码在其他模块中导入时执行。
var title = "user";
export default (function(){
console.log("user model");
})();
导入即导出:
将模块汇总到一个文件中在导出,比如通常我们的组件中都会有index.js
文件,如果其中不做任何逻辑处理。就只负责汇总。
就像上述例子,就只是初始化执行了一下user.js
;那我们要把他执行的结果在导出。
user.js
: 加入了一个返回对象,有一个getTitle
方法。
var title = "user";
export default (function(){
console.log("user model");
return {
getTitle:()=>{
console.log(title);
}
}
})();
index.js
导入获得返回值对象后在导出。
import user from "./user";
export default user;
app.js
需要第三个组件去导入并调用执行。
import user from "./index";
user.getTitle();
这次转义的是app.js
,compile-modules convert -o index-copy.js app.js
.
得到执行结果。
简写index.js
ES 7提案,未得到有效测试
export user from "./user";
还有这种写法也不支持;书写不报错,编译时报错不支持。epxort * from './user.js'
动态导入
import
动态导入,返回的是一个Promise
对象。
未测试,暂不支持
import("./user").then((module)=>{
console.log(module.getAge());
},(err)=>{
throw err;
}});
// await 写法
let module = await import("./user");
module.getAge();
ES6模块VSCommonJS
NodeJS
中使用的就是CommonJS
规范。
require()
加载模块。
module.exports
导出模块。
加载实质
CommonJS
输出的模块是值得拷贝;ES6
输出的则是引用,会受原组件内部代码执行影响。
先看CommonJS
user.js
取得是随机数。看导入模块后的打印值变化。
var num = 0;
function getNum(){
num = Math.random()*100;
return num;
}
module.exports = {
num:num,
change:getNum
}
index.js
let user = require("./user");
console.log(user.num);
console.log(user.change());
console.log(user.num);
当然,执行
Node
执行需要环境。去官网安装Node
输出结果:
测试ES6
的模块:
user.js
export var num = 0;
export function getNum(){
num = Math.random()*100;
return num;
}
index.js
import * as user from "./user";
// let user = require("./user");
console.log(user.num);
console.log(user.getNum());
console.log(user.num);
执行输出结果:
测试时犯的错误,在导出了个默认对象把num
赋给对象中的属性。
export default {
num:num,
change:getNum
}
结果当然num
还是0。赋值阶段num:num
是值传递,所以不会改变。、
模块之间的循环加载
之上,由于CommonJS
是值拷贝,不是引用,所以不会导致循环加载而导致卡死状态;也正因为如此,再确认自己导入的模块是已经可以获取到值得,不然值为null
,再调用操作就会报错。
ES6
是动态引用,它会一直执行。直到有退出条件或者报错退出。