import and export 之 (export)

ES6提供了兩個關鍵字import導入和export導出,語法上有些差異。
!important: importexport必須,始終顯示在,其各自用法的,頂級範圍中。也就是說不能夠在if條件中放置importexport; 它們必須放在全部函數以外。函數

exporting API Members 導出API成員

export關鍵字要麼放在聲明以前,要麼做爲運算符(排序)使用要export特定綁定列表性能

export function foo() {
    // ..
}

export var awesome = 42;

var bar = [1,2,3];
export { bar };

相同的表達exports的方法:優化

function foo() {
    // ..
}

var awesome = 42;
var bar = [1,2,3];

export { foo, awesome, bar };

這些都稱爲 命名導出( named export) ,由於您實際上導出變量/函數/等名稱綁定
任何你不標記export,會在模塊的範圍內保持private。 也就是說,儘管var bar = ..看起來像是在頂級全局範圍聲明,頂級範圍其實是模塊自己; 模塊中沒有全局範圍設計

注意:模塊仍然能夠訪問window和全部的globals ,掛起它,只是否是做爲詞彙頂級範圍。 可是,你真的應該遠離全局模塊,若是可能的話。指針

您還能夠在命名導出期間對模塊成員進行「重命名」(也稱爲別名):code

function foo() { .. }

export { foo as bar };

導入此模塊時,只有bar成員名稱可用於導入; foo保持隱藏在模塊內。對象

模塊導出不只僅是值或引用的正常賦值,由於您習慣於=賦值運算符。 實際上,當你導出一些東西,你正在導出一個綁定(有點像一個指針)到那個東西(變量等)。排序

在模塊中,若是更改已導出綁定的變量的值,即便已經導入(參見下一部分),導入的綁定也將解析爲當前(更新)的值。作用域

試想一下:開發

var awesome = 42;
export { awesome };

// later
awesome = 100;

導入此模塊時,不管是在awesome = 100設置以前仍是以後,一旦分配已經發生,導入的綁定將解析爲值100,而不是42

這是由於綁定本質上是對awesome變量自己的引用或指針,而不是其值的副本。JS引入了ES6模塊綁定,這是一個大多數史無前例的概念。

雖然您能夠在模塊的定義中清楚地屢次使用export,但ES6絕對偏好模塊,具備單個導出的方法,這稱爲default export。用TC39委員會的一些成員的話來講,若是你遵循這種模式,你就會被「簡單的import語法」所獎勵,而若是你不這麼作,則反過來被更冗長的語法來「懲罰」。

默認導出將特定導出的綁定設置爲導入模塊時的默認值。綁定的名稱字面上是默認的。正如你將在後面看到的,當導入模塊綁定時,你也能夠重命名它們,就像你一般使用默認導出同樣。

每一個模塊定義只能有一個默認值。若是模塊具備默認導出,您將看到導入語法如何更簡潔。

對於默認導出語法有一個微妙的細微差異,您應該密切注意。比較這兩個片斷:

function foo(..) {
    // ..
}

export default foo;

and

function foo(..) {
    // ..
}

export { foo as default };

在第一個片斷中,您正在導出一個綁定到此時的函數表達式值,而不是標識符foo。 換句話說,導出export default ..採用一個表達式。 若是之後將foo分配給模塊中的其餘值,則模塊導入仍會顯示最初導出的函數,而不是新值。

順便說一下,第一個片斷也能夠寫成:

export default function foo(..) {
    // ..
}

警告:雖然這裏function foo..在技術上,是一個函數表達式,爲了模塊的內部範圍的目的,它被視爲一個函數聲明,由於foo名稱綁定在模塊的頂級做用域 稱爲「提高」)。 出口默認類Foo也是如此。可是,雖然你能夠作到export var foo = ..,但你目前不能作到export default var foo = ..(或let或const),在一個使人沮喪的不一致的狀況下。 在撰寫本文時,爲了一致性,已經討論了在ES6以後很快增長這種能力。

function foo(..) {
    // ..
}

export { foo as default };

在此版本的模塊導出中,默認導出綁定其實是foo標識符而不是它的,因此您得到前面描述的綁定行爲(即,若是您之後更改foo的值,你在import端看到的值也將更新)。

在默認導出語法中要很是當心這個微妙的問題,特別是若是你的邏輯須要更新導出值。 若是你歷來沒有計劃更新默認導出的值,export default ..是很好的。 若是您計劃更新值,則必須使用export {.. as default}。 不管哪一種方式,確保評論你的代碼如何來解釋你的意圖!

由於每一個模塊只能有一個默認值,因此您可能會試圖使用一個對象的默認導出,來設計您的模塊,其中包含全部的API方法,例如:

export default {
    foo() { .. },
    bar() { .. },
    ..
};

這種模式,彷佛很密切地,映射了不少開發人員,已經構建了,他們的ES6以前的模塊,因此,它彷佛是,一個天然的方法。 不幸的是,它存在一些缺點,並正式地不鼓勵這樣作。

特別是,JS引擎,不能靜態分析普通對象的內容,這意味着,它不能對靜態導入性能,作一些優化。 每一個成員單獨和顯式導出的優勢是,引擎能夠進行靜態分析和優化。

若是你的API,已經有多個成員,彷佛這些原則 - 每一個模塊一個默認導出,全部API成員名爲exports - 存在衝突,不是嗎? 可是您能夠有一個默認導出以及其餘命名導出; 它們不是相互排斥的。

所以,替換掉當前的(不建議的)模式:

export default function foo() { .. }

foo.bar = function() { .. };
foo.baz = function() { .. };

you can do that

export default function foo() { .. }

export function bar() { .. }
export function baz() { .. }

注意:在前面的代碼段中,我使用名稱foo做爲默認函數的標籤。 然而,名稱foo,爲了導出的目的被忽略 - default其實是導出的名稱。 當您導入此默認綁定時,您能夠爲其指定任何所需的名稱,以下一部分中所示。

function foo() { .. }
function bar() { .. }
function baz() { .. }

export { foo as default, bar, baz, .. };

當咱們短時間覆蓋import時,混合default命名exports的影響將更加清晰。但實質上它意味着最簡潔的默認import形式,將只檢索foo()函數。用戶能夠另外手動將barbaz列爲命名導入,若是他們想要的話。

你能夠想象若是你有不少命名的導出綁定,你模塊的用戶將是多麼乏味。這裏有一個通配符導入表單,您能夠在單個命名空間對象中導入全部模塊的exports,可是沒法將通配符導入到頂級綁定。

一樣,ES6模塊機制被有意設計爲阻止具備大量輸出的模塊;相對來講,但願這樣的方法有點困難,做爲一種社會工程,它鼓勵簡單的模塊設計,由於這將有利於大/複雜的模塊設計。

我建議你不要混合default export命名exports,這將是是不切實際或不須要,特別是若是你有一個大的API和重構單獨的模塊。在這種狀況下,只需使用全部named exports,並記錄您的模塊的用戶應該使用import * as ..(命名空間導入)方法在單個命名空間中當即帶來整個API。

咱們以前提到過,但讓咱們更詳細地回味一下。除了導出表達式值綁定的export default ...外,全部其餘導出表單,都正在導出綁定到本地標識符。

相關文章
相關標籤/搜索