ES6 支持 javascript 模塊化,模塊之間的導(dǎo)入導(dǎo)出有一定的規(guī)則,因?yàn)榭偸怯洸蛔」统酰鲆幌聦W(xué)習(xí)筆記。
export 導(dǎo)出
export 命令用于規(guī)定對(duì)外的接口减响。一個(gè)模塊就是一個(gè)獨(dú)立的文件靖诗,文件內(nèi)部的變量郭怪,外部是無法獲取的,如果想讀取模塊內(nèi)部的某個(gè)變量刊橘,必須使用 export 關(guān)鍵字輸出該變量鄙才。
export 語(yǔ)句輸出的接口,與其對(duì)應(yīng)的值是動(dòng)態(tài)綁定關(guān)系促绵,即通過該接口攒庵,可以取到模塊內(nèi)部實(shí)時(shí)的值。
export 命令可以出現(xiàn)在模塊的任何位置绞愚,只要處于模塊頂層就可以。如果處于塊級(jí)作用域內(nèi)颖医,就會(huì)報(bào)錯(cuò)位衩,也就是不能出現(xiàn)在表達(dá)式,if 判斷等塊內(nèi)熔萧。
// export 第一個(gè)種寫法
export var firstName = "zhangsan";
// 第二種寫法糖驴,輸出一組變量時(shí),一定要有大括號(hào)
var secondName = "lisi";
var thirdName = "andy";
export {secondName, thirdName};
// 輸出函數(shù)
function v1(){}
export {v1}
// 也可以更改輸出的名字佛致,對(duì)外暴露的就是newFn
export {v1 as newFn}
import 命令
- 獨(dú)立加載
不允許修改 import 進(jìn)來的變量贮缕,除非操作的是一個(gè)變量中的屬性,一般情況下不建議修改變量俺榆,僅做只讀感昼。
import 命令具有提升效果,會(huì)提升到整個(gè)模塊的頭部罐脊,首先執(zhí)行定嗓。
由于 import 是靜態(tài)執(zhí)行,所以不能使用表達(dá)式和變量萍桌,這些只有在運(yùn)行時(shí)才能得到結(jié)果的語(yǔ)法結(jié)構(gòu)宵溅。所謂靜態(tài)執(zhí)行,指的是在編譯時(shí)執(zhí)行上炎,在程序運(yùn)行時(shí)不執(zhí)行恃逻。
如果多次重復(fù)執(zhí)行同一句import語(yǔ)句,那么只會(huì)執(zhí)行一次藕施,而不會(huì)執(zhí)行多次寇损。
// 第一種引入,直接引入輸出的裳食,大括號(hào)里面的變量名必須與export里面的一一對(duì)應(yīng)
import {firstName,secondName} from './profile.js';
// 第二種寫法润绵,改變名稱,將lastName 改為 surname
import {lastName as surname} from './profile.js';
// 僅僅執(zhí)行胞谈,不輸入尘盼。以下僅僅執(zhí)行l(wèi)odash模塊憨愉,但是不輸入任何值。
import 'lodash';
- 整體加載
整體加載用在不知道導(dǎo)出來的名字卿捎,用星號(hào)(*)指定一個(gè)對(duì)象配紫,所有輸出值都加載在這個(gè)對(duì)象上面。
// circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
// main.js
// 整體加載
import * as circle from './circle';
console.log('圓面積:' + circle.area(4));
console.log('圓周長(zhǎng):' + circle.circumference(14));
// 下面兩行都是不允許的午阵,因?yàn)椴辉试S運(yùn)行時(shí)改變
circle.foo = 'hello';
circle.area = function () {};
export default 默認(rèn)輸出
export default 為模塊指定默認(rèn)輸出躺孝。模塊只能有一個(gè) export default,但是可以有多個(gè) export
// export-default.js
export default function () {
console.log('foo');
}
// 其他函數(shù)在加載時(shí)底桂,可以以任意名字來加載
// import-default.js
import customName form './export-default';
customName(); // 'foo'
// 后面不能跟表達(dá)式植袍,因?yàn)閑xport default 輸出的是一個(gè)default變量
export default var a = 1; // 錯(cuò)誤
// 當(dāng)輸出 export default 后,可以同時(shí) import 多個(gè)
import _, {each, each as forEach} from 'lodash';
// export default 也可以用來輸出類籽懦。
// MyClass.js
export default class { ... }
// main.js
import MyClass from 'MyClass';
let o = new MyClass();
export 與 import 的復(fù)合寫法
export 與 import 的復(fù)合寫法相當(dāng)于轉(zhuǎn)手導(dǎo)出于个,當(dāng)前模塊沒有引用導(dǎo)出的模塊。
export { foo, bar } from 'my_module';
// foo和bar實(shí)際上并沒有被導(dǎo)入當(dāng)前模塊暮顺,只是相當(dāng)于對(duì)外轉(zhuǎn)發(fā)了這兩個(gè)接口厅篓,導(dǎo)致當(dāng)前模塊不能直接使用 foo 和 bar。
// 可以簡(jiǎn)單理解為
import { foo, bar } from 'my_module';
export { foo, bar };
// 接口改名
export { foo as myFoo } from 'my_module';
// 整體輸出
export * from 'my_module';
// 具名接口改為默認(rèn)接口的寫法如下捶码。
export { es6 as default } from './someModule';
// 等同于
import { es6 } from './someModule';
export default es6;
// 同樣地羽氮,默認(rèn)接口也可以改名為具名接口。
export { default as es6 } from './someModule';
CommonJS 的寫法
CommonJS通過 module 對(duì)象來把 javascript 代碼模塊化惫恼。引入模塊通過 require語(yǔ)法档押,導(dǎo)出模塊通過 module.exports = {} 。范例
// lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter,
};
// 在main.js里面加載這個(gè)模塊祈纯。
// main.js
var mod = require('./lib');
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 3
// 上面代碼說明汇荐,lib.js模塊加載以后,它的內(nèi)部變化就影響不到輸出的mod.counter了盆繁。這是因?yàn)閙od.counter是一個(gè)原始類型的值掀淘,會(huì)被緩存。除非寫成一個(gè)函數(shù)油昂,才能得到內(nèi)部變動(dòng)后的值革娄。
讀取模塊內(nèi)的數(shù)值 需要通過取值器函數(shù)。
// lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
get counter() {
return counter
},
incCounter: incCounter,
};
// 上面代碼中冕碟,輸出的counter屬性實(shí)際上是一個(gè)取值器函數(shù)±雇铮現(xiàn)在再執(zhí)行main.js,就可以正確讀取內(nèi)部變量counter的變動(dòng)了安寺。
$ node main.js
3
4
ES6 模塊的引用是復(fù)制的引用厕妖,一處修改,其他地方都會(huì)改挑庶。
// lib.js
export let counter = 3;
export function incCounter() {
counter++;
}
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4
node 中的 import
目前言秸,Node 的import命令只支持加載本地模塊(file:協(xié)議)软能,不支持加載遠(yuǎn)程模塊。
如果模塊名不含路徑举畸,那么import命令會(huì)去node_modules目錄尋找這個(gè)模塊查排。
如果模塊名包含路徑,那么import命令會(huì)按照路徑去尋找這個(gè)名字的腳本文件抄沮。范例
import 'file:///etc/config/app.json';
import './foo';
import './foo?search';
import '../bar';
import '/baz';
/* 如果腳本文件省略了后綴名跋核,比如import './foo',Node 會(huì)依次嘗試四個(gè)后綴名:./foo.mjs叛买、./foo.js砂代、./foo.json、./foo.node率挣。如果這些腳本文件都不存在刻伊,Node 就會(huì)去加載./foo/package.json的main字段指定的腳本。如果./foo/package.json不存在或者沒有main字段难礼,那么就會(huì)依次加載./foo/index.mjs娃圆、./foo/index.js玫锋、./foo/index.json蛾茉、./foo/index.node。如果以上四個(gè)文件還是都不存在撩鹿,就會(huì)拋出錯(cuò)誤谦炬。
最后,Node 的import命令是異步加載节沦,這一點(diǎn)與瀏覽器的處理方法相同 键思。