ES6標準發(fā)布后县钥,module成為標準伺绽,標準的使用是以export指令導出接口甲馋,以import引入模塊埂奈,但是在我們一貫的node模塊中,我們采用的是CommonJS規(guī)范定躏,使用require引入模塊账磺,使用module.exports導出接口。
CommonJS
CommonJS定義的模塊分為:{模塊引用(require)} {模塊定義(exports)} {模塊標識(module)}
require()用來引入外部模塊痊远;exports對象用于導出當前模塊的方法或變量垮抗,唯一的導出口;module對象就代表模塊本身碧聪。
require統(tǒng)治了ES6之前的所有模塊化編程冒版,即使現(xiàn)在,在ES6 module被完全實現(xiàn)之前逞姿,還是這樣辞嗡。
// a.js
// -------- node -----------
module.exports = {
a : function() {},
b : 'xxx'
};
// b.js
// ------------ node ---------
var m = require('./a');
m.a();
require()是同步方法
ES6發(fā)布的module并沒有直接采用CommonJS,甚至連require都沒有采用滞造,也就是說require仍然只是node的一個私有的全局方法续室,module.exports也只是node私有的一個全局變量屬性
注意:module.exports方法不會多次生效,只執(zhí)行最后一行語句的導出方法谒养,這個與下面要介紹的export是有區(qū)別的挺狰,后面會介紹這個
ES6 模塊
ES6 模塊不是對象,而是通過export命令顯式指定輸出的代碼买窟,再通過import命令輸入丰泊。
模塊功能主要由兩個命令構(gòu)成:export和import。export命令用于規(guī)定模塊的對外接口始绍,import命令用于輸入其他模塊提供的功能夕吻。
// ES6模塊
import { stat, exists, readFile } from 'fs';
上面代碼的實質(zhì)是從fs模塊加載 3 個方法,其他方法不加載焊夸。這種加載稱為“編譯時加載”或者靜態(tài)加載,即 ES6 可以在編譯時就完成模塊加載满葛,效率要比 CommonJS 模塊的加載方式高。但是這樣會造成import時無法動態(tài)加載
//react native根據(jù)平臺動態(tài)加載js罢屈,無法使用import方式加載
var NativeAPI = require('./Native_API/NativeAPI.' + Platform.OS);
export導出模塊
// module "my-module.js"
function cube(x) {
return x * x * x;
}
const foo = Math.PI + Math.SQRT2;
export { cube, foo };
注意嘀韧,export命令規(guī)定的是對外的接口,必須與模塊內(nèi)部的變量建立一一對應關(guān)系缠捌。但是module.exports是可以的
// 錯誤演示
// 報錯
export 1; // 絕對不可以
// 報錯
var a = 100;
export a;
//module.exports
var a = 1;
module.exports = a
export在導出接口的時候锄贷,必須與模塊內(nèi)部的變量具有一一對應的關(guān)系。直接導出1沒有任何意義曼月,也不可能在import的時候有一個變量與之對應谊却。 export a 雖然看上去成立,但是 a 的值是一個數(shù)字哑芹,根本無法完成解構(gòu)炎辨,因此必須寫成 export {a} 的形式。即使a被賦值為一個function聪姿,也是不允許的碴萧。
// 寫法一
export var m = 1;
// 寫法二
var m = 1;
export {m};
// 寫法三
var n = 1;
export {n as m};
注意:export可以在代碼中導出多個
var m = 1;
export {m};//導出m
var b = 2;
export //導出b
import導入模塊
import的語法跟require不同末购,而且import必須放在文件的最開始破喻,且前面不允許有其他邏輯代碼。
// import "user.js"
import { cube, foo } from 'my-module';
console.log(cube(3)); // 27
console.log(foo); // 4.555806215962888
import后面跟上花括號的形式是最基本的用法盟榴,花括號里面的變量與export后面的變量一一對應曹质。這里,你必須了解 對象的解構(gòu)賦值 的知識擎场,也可參考阮一峰的結(jié)構(gòu)賦值
as關(guān)鍵字
簡單的說就是取一個別名羽德。export中可以用,import中其實可以用:
// a.js
var a = function() {};
export {a as fun};
// b.js
import {fun as a} from './a';
a();
export的時候顶籽,對外提供的接口是fun玩般,它是a.js內(nèi)部a這個函數(shù)的別名,但是在模塊外面礼饱,認不到a坏为,只能認到fun。
import中的as就很簡單镊绪,就是你在使用模塊里面的方法的時候匀伏,給這個方法取一個別名,好在當前的文件里面使用蝴韭。兩個不同文件可能都export同一個fun的對象
export default 命令
export default命令够颠,為模塊指定默認輸出。
// 第一組
export default function crc32() { // 輸出
// ...
}
import crc32 from 'crc32'; // 輸入
// 第二組
export function crc32() { // 輸出
// ...
};
import {crc32} from 'crc32'; // 輸入
default其實是as的語法糖榄鉴,這個語法糖的好處就是import的時候履磨,可以省去花括號{}蛉抓。
*符號
*代表所有
import * as _ from 'xxx.js';//表示把xxx模塊中的所有接口掛載到 _ 這個對象上
通過*號直接繼承某一個模塊的接口
export * from '_';
// 等效于:
import * as all from '_';
export all;
盡量少用,它使用的所有的export的接口剃诅,但是你當前模塊其實并不一定需要用到所有的接口巷送,還是用{}按照需要去引用
Require Or Import
require理論上可以運用在代碼的任何地方,甚至不需要賦值給某個變量之后再使用矛辕;但是import則不同笑跛,它是編譯時的(require是運行時的),它必須放在文件開頭聊品,而且使用格式也是確定的飞蹂,不容置疑。它不會將整個模塊運行后賦值給某個變量翻屈,而是只選擇import的接口進行編譯陈哑,這樣在性能上比require好很多。
按照規(guī)范module.exports =>require妖胀,export=>import芥颈,但是現(xiàn)在開發(fā)為了兼容低版本的JS引擎會對import進行降級處理惠勒,會把import轉(zhuǎn)換成require赚抡;這樣就造成了各種方法可以混合使用,如
//import.js:導出模塊a和d
export class a {//分開導出
constructor(arg=2) {
this.t = 1;
this.t2 = arg;
}
b(){
console.log('b');
console.log(this.t2);
}
c(){
console.log('c')
console.log(this.t);
}
}
var d = function(){
};
export rrp9bvh;
//require.js:導出模塊a,d,e
class a {//分開導出
constructor(arg=2) {
this.t = 1;
this.t2 = arg;
}
b(){
console.log('b');
console.log(this.t2);
}
c(){
console.log('c')
console.log(this.t);
}
}
var d = function(){
console.log(d)
};
var e = 1
module.exports = {a,d,e};
//index.js
var require_a = require('./require')
var import_a = require('./import')
import {a as test} from './import'
import a from './require'
import * as all_require from './require'
import * as all_import from './import'
console.log(require_a);//{a: ?, d: ?, e: 1}
console.log(import_a);//{a: ?, d: ?, __esModule: true}
console.log(test);//? a()
console.log(a);//{a: ?, d: ?, e: 1}
console.log(all_require);//{a: ?, d: ?, e: 1, default: {…}}
console.log(all_import);//{a: ?, d: ?, __esModule: true}
//a1,a2數(shù)據(jù)不影響
//constructor可傳參數(shù)纠屋,但參數(shù)名不能與變量名相同
var a1 = new test();
var a2 = new test(4);
console.log(a1.t,a1.t2);//1,2
a1.b();//b,2
a1.t=3;
a1.c();//c,3
console.log(a2.t,a2.t2);//1,4
a2.b();//b,4
a2.t=5;
a2.c();//c,5
可以看到在混用時require和import在編碼是是都可以使用的涂臣,需要注意的是require是把所有模塊加載進去,與import * 基本相同售担,但是import *會增加default屬性赁遗。import需要指定模塊名,如果不存在會返回undefined族铆。
require 取到整個對象
import a 取到default的對象岩四,如果無default對象,在編譯時會報錯
import {a} 取到 a對象
import * as XX 取到所有對象哥攘,并放到XX里面
//a.js
export default class xxxx {}
var xxx = require('./a.js');//{default:? xxx()}
import xxx from './a.js';//? xxx()
當export有default時,在使用require時剖煌,需要從default中才能取到要使用的對象,而import可以直接拿到對應的屬性
//a.js
module.exports = class a {}
var a = require('./a.js');//? xxx()
import a from './a.js';//? xxx()
如果module.exports導出的是單一的對象時逝淹,使用require和import取到的對象是同樣的耕姊,都是可以直接使用,和default的效果基本一致栅葡。
注意:webpack3在module.exports編譯時茉兰,在模塊前自增加了default屬性