import命令與export命令
import命令
使用export
命令定義了模組的對外介面以後,其他JS檔案就可以通過import
命令載入這個模組(檔案)。
// main.js
import {firstName, lastName, year} from './profile';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
上面程式碼的import
命令,就用於載入profile.js
檔案,並從中輸入變數。import
命令接受一個物件(用大括號表示),裡面指定要從其他模組匯入的變數名。大括號裡面的變數名,必須與被匯入模組(profile.js
如果想為輸入的變數重新取一個名字,import命令要使用as
關鍵字,將輸入的變數重新命名。
import { lastName as surname } from './profile';
注意,import
命令具有提升效果,會提升到整個模組的頭部,首先執行。
foo();
import { foo } from 'my_module';
上面的程式碼不會報錯,因為import
的執行早於foo
的呼叫。
如果在一個模組之中,先輸入後輸出同一個模組,import
語句可以與export
語句寫在一起。
export { es6 as default } from './someModule' ;
// 等同於
import { es6 } from './someModule';
export default es6;
上面程式碼中,export
和import
語句可以結合在一起,寫成一行。但是從可讀性考慮,不建議採用這種寫法,而應該採用標準寫法。
另外,ES7有一個提案,簡化先輸入後輸出的寫法,拿掉輸出時的大括號。
// 提案的寫法
export v from 'mod';
// 現行的寫法
export {v} from 'mod';
import
語句會執行所載入的模組,因此可以有下面的寫法。
import 'lodash';
上面程式碼僅僅執行lodash
模組,但是不輸入任何值。
export
模組功能主要由兩個命令構成:export
和import
。export
命令用於規定模組的對外介面,import
命令用於輸入其他模組提供的功能。
一個模組就是一個獨立的檔案。該檔案內部的所有變數,外部無法獲取。如果你希望外部能夠讀取模組內部的某個變數,就必須使用export
關鍵字輸出該變數。下面是一個JS檔案,裡面使用export
命令輸出變數。
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
上面程式碼是profile.js
檔案,儲存了使用者資訊。ES6將其視為一個模組,裡面用export
命令對外部輸出了三個變數。
export
的寫法,除了像上面這樣,還有另外一種。
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
上面程式碼在export
命令後面,使用大括號指定所要輸出的一組變數。它與前一種寫法(直接放置在var
語句前)是等價的,但是應該優先考慮使用這種寫法。因為這樣就可以在指令碼尾部,一眼看清楚輸出了哪些變數。
export命令除了輸出變數,還可以輸出函式或類(class)。
export function multiply(x, y) {
return x * y;
};
上面程式碼對外輸出一個函式multiply
。
通常情況下,export
輸出的變數就是本來的名字,但是可以使用as
關鍵字重新命名。
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
上面程式碼使用as
關鍵字,重新命名了函式v1
和v2
的對外介面。重新命名後,v2
可以用不同的名字輸出兩次。
需要特別注意的是,export
命令規定的是對外的介面,必須與模組內部的變數建立一一對應關係。
// 報錯
export 1;
// 報錯
var m = 1;
export m;
上面兩種寫法都會報錯,因為沒有提供對外的介面。第一種寫法直接輸出1,第二種寫法通過變數m
,還是直接輸出1。1
只是一個值,不是介面。正確的寫法是下面這樣。
// 寫法一
export var m = 1;
// 寫法二
var m = 1;
export {m};
// 寫法三
var n = 1;
export {n as m};
上面三種寫法都是正確的,規定了對外的介面m
。其他指令碼可以通過這個介面,取到值1
。它們的實質是,在介面名與模組內部變數之間,建立了一一對應的關係。
同樣的,function
和class
的輸出,也必須遵守這樣的寫法。
// 報錯
function f() {}
export f;
// 正確
export function f() {};
// 正確
function f() {}
export {f};
另外,export
語句輸出的介面,與其對應的值是動態繫結關係,即通過該介面,可以取到模組內部實時的值。
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
上面程式碼輸出變數foo
,值為bar
,500毫秒之後變成baz
。
這一點與CommonJS規範完全不同。CommonJS模組輸出的是值的快取,不存在動態更新,詳見下文《ES6模組載入的實質》一節。
最後,export
命令可以出現在模組的任何位置,只要處於模組頂層就可以。如果處於塊級作用域內,就會報錯,下一節的import
命令也是如此。這是因為處於條件程式碼塊之中,就沒法做靜態優化了,違背了ES6模組的設計初衷。
function foo() {
export default 'bar' // SyntaxError
}
foo()
上面程式碼中,export
語句放在函式之中,結果報錯。
參考資料,阮一峰http://es6.ruanyifeng.com/#docs/module#import%E5%91%BD%E4%BB%A4