Module 語法
ES6 模塊不是對象围肥,而是通過 export 命令顯示指定輸出的代碼,再通過 import 命令輸入。
import {stat,exists,readFile} from 'fs';
上述代碼的實(shí)質(zhì)是從 fs
模塊加載3個方法,其它方法不加載馅笙,這種加載稱為"編譯時加載"或者靜態(tài)加載。即ES6 可以在編譯時就完成模塊加載厉亏。
由于 ES6 模塊是編譯時加載董习,使得靜態(tài)分析稱為可能,有了它叶堆,就能進(jìn)一步擴(kuò)寬 JavaScript 的語法阱飘,比如引入宏和類型檢驗(yàn)斥杜,這些只能靠靜態(tài)分析實(shí)現(xiàn)的功能虱颗。
除了靜態(tài)加載帶來的各種好處, ES6 模塊還有以下好處蔗喂。
export 命令
模塊功能主要由兩個命令構(gòu)成: export
和 import
, export
命令用于規(guī)定模塊的對外接口忘渔, import
命令用于輸入其他模塊提供的功能。
一個模塊就是一個獨(dú)立的文件缰儿,該文件內(nèi)部的所有變量畦粮,外部無法獲取,如果你希望外部能夠讀取模塊內(nèi)部的某個變量,就必須使用 export
關(guān)鍵字輸出該變量宣赔。
//profile.js
export var firstName = '張';
export var lastName = "某人";
上述代碼是 profile.js
文件预麸,ES6 將其視為一個模塊,里面用 export
命令對外部輸出了三個變量儒将。
export
de寫法吏祸,除了上面樣子還有另外一種
var firstName = '張';
var lastName = '某人';
export {firstName, lastName};
上面代碼在 export
命令后面,使用大括號指定所要輸出的一組變量钩蚊,
export
命令出了輸出變量贡翘,還可以輸出函數(shù)或類(class).
export function multiply(x,y){
return x * y;
};
上述代碼對外輸出一個函數(shù) multiply
。
通常情況下砰逻, export
輸出的變量就是本來的名字鸣驱,但是可以使用 as
關(guān)鍵字重命名。
function v1(){...};
function v2(){...};
export {
v1 as streamV1;
v2 as streamV2;
v2 as streamLatestVerson;
}
上面代碼使用 as
關(guān)鍵字蝠咆,重命名了函數(shù) v1
和 v2
的對外接口踊东,重命名后, v2
可以用不同的名字輸出兩次勺美。
需要特別注意的是, export
命令規(guī)定的是對外的接口递胧,必須與模塊內(nèi)部的變量建立一一對應(yīng)關(guān)系。
//報(bào)錯
export 1;
// 報(bào)錯
var m = 1;
export m;
上面兩種寫法都會報(bào)錯赡茸,因?yàn)闆]有提供對外的接口缎脾,第一種寫法直接輸出1,第二種寫法通過變量 m
, 還是直接輸出1占卧,1
只是一個值遗菠,不是接口,正確的寫法是下面這樣.
// 寫法1
export var m=1;
// 寫法2
var m = 1;
export {m};
// 寫法3
var n=1;
export {n as m};
同樣华蜒, function
和 class
的輸出辙纬,也必須遵守這樣的寫法.
// 報(bào)錯
function f(){}
export f;
// 正確
export function f(){};
// 正確
function f(){}
export {f};
另外, export
語句輸出的接口,與其對應(yīng)的值是動態(tài)綁定關(guān)系叭喜,即通過該接口贺拣,可以取到模塊內(nèi)部實(shí)時的值。
export var foo = 'bar';
import 命令
使用 export
命令定義了模塊的對外接口以后捂蕴,其他 JS 文件就可以通過 import
命令加載這個模塊譬涡。
import {firstName,lastName} from './profile';
function setName(element){
element.textContent = firstName + '' + lastName;
}
如果想為輸入的變量重新取一個名字,import
命令要使用as
關(guān)鍵字啥辨,將輸入的變量重命名涡匀。
import {lastName as surname} from './profile';
import
后面的 from
指定模塊文件的位置,可以是相對路徑溉知,也可以是絕對路徑陨瘩,.js
路徑可以省略腕够,如果只是模塊名,不帶有路徑舌劳,那么必須有配置文件帚湘,告訴 JavaScript 引擎該模塊的位置。
import
命令具有提升效果甚淡,會提升到整個模塊的頭部客们,首先執(zhí)行.
foo();
import {foo} from 'my module';
上面代碼不會報(bào)錯,因?yàn)?import
的執(zhí)行早于 foo
的調(diào)用材诽,這種行為的本質(zhì)是: import 命令時編譯階段執(zhí)行的底挫,在代碼運(yùn)行之前。
由于 import是靜態(tài)執(zhí)行脸侥,所以不能使用表達(dá)式和變量建邓,這些只有在運(yùn)行時才能得到結(jié)果的語法結(jié)構(gòu).
// 報(bào)錯
import {'f'+'oo'} from 'my_module';
模塊的整體加載
除了指定加載某個輸出值,還可以使用整體加載睁枕,即用星號 (*)
指定一個對象官边,所有輸出值都加載在這個對象上面。
export function area(radius) {
return Math.PI * radius* radius;
}
export function circumference(radius) {
return 2*Math.PI * radius;
}
現(xiàn)在加載這個模塊
import (area, circumferernce) from './circle';
上面的寫法是逐一制定要加載的方法外遇,整體加載的寫法如下:
import * as circle from './circle';
注意整體加載所在的那么對象注簿,應(yīng)該是可以靜態(tài)分析的,所以不允許運(yùn)行時改變跳仿。
export default 命令
在使用 import
命令的時候诡渴,用戶需要知道索要加載的變量名或函數(shù)名,否則無法加載菲语,但是用戶肯定希望快速上手妄辩,未必愿意閱讀文檔,去了解模塊有哪些屬性和方法山上。
為了給用戶提供方便眼耀,讓他們不用閱讀文檔就能加載模塊,就要用到 export default
命令佩憾,為模塊指定默認(rèn)輸出哮伟。
// export default.js
export default function(){
}
上面代碼是一個模塊文件 export-default.js
, 它的默認(rèn)輸出是一個函數(shù)。其他模塊加載該模塊時妄帘,import
命令可以為該匿名函數(shù)指定任意名字楞黄。
import customName from './export-default';
customName();
上面代碼的 import
命令,可以用任意名稱指向 export-default.js
輸出的房啊寄摆,這時就不需要知道原模塊輸出的函數(shù)名谅辣,需要注意的是修赞,這時 import
命令后面婶恼,不使用大括號桑阶。
export default
命令用在非匿名函數(shù)前,也是可以的勾邦。
默認(rèn)輸出和正常輸出
// 第一組
export default function crc32(){
//輸出
}
import crc32 from 'crc32'; // 輸入
// 第二組
export function crc32(){
// 輸出
};
import {crc32} from 'crc32';// 輸入
export default
命令用于指定模塊的默認(rèn)輸出蚣录,顯然,一個模塊只能有一個默認(rèn)輸出眷篇,因此 export default
命令只能使用一次萎河,所以, import
命令后面才不用加大括號蕉饼,因?yàn)橹豢赡軐?yīng)一個方法虐杯。
本質(zhì)上, export default
就是輸出一個叫做 default
的變量或房啊昧港,然后系統(tǒng)允許你為它取任意名字擎椰,export default a
的含義是將變量 a
的值賦給變量 default
。
同樣的创肥,因?yàn)?export default
本質(zhì)是將該命令后面的值达舒,賦給 default
變量以后再默認(rèn),所以直接將一個值寫在 export default
之后叹侄。
有了 export default
命令巩搏,輸入模塊時就非常直觀了,以輸入