做者:Dmitri Pavlutin翻譯:瘋狂的技術宅javascript
https://dmitripavlutin.com/ja...前端
未經容許嚴禁轉載java
讓咱們從一個問題開始。程序員
名爲 increment
的 ES2015 模塊包含如下代碼:面試
// increment.js let counter = 0; counter++; export default counter;
而後在另外一個模塊 consumer
中,將上述模塊 increment
導入兩次:segmentfault
// consumer.js import counter1 from './increment'; import counter2 from './increment'; counter1; // => ??? counter2; // => ???
問題是:當 consumer
模塊運行時,變量 counter1
和 counter2
的內容是什麼?瀏覽器
要回答這個問題,首先你須要瞭解 JavaScript 如何評估和導入模塊。服務器
理解 JavaScript 內部原理的一個好方法是查看其說明。微信
根據規範,每一個 JavaScript 模塊都與模塊記錄相關聯。模塊記錄具備方法 Evaluate()
,該方法對模塊進行評估:多線程
若是該模塊已經被成功評估,則返回 undefined
;……不然,即可遞歸地評估此模塊全部的模塊依賴性,而後再評估此模塊。
因此同一模塊僅被評估一次。
不幸的是,問題不止於此。如何確保使用相同路徑兩次調用 import 語句返回相同的模塊?
將路徑(也稱爲說明符)關聯到具體模塊的職責由 HostResolveImportedModule() 執行操做。
import module from 'path';
根據規則:
HostResolveImportedModule
的實現必須符合如下要求:
Module Record
的具體子類的實例。referencingScriptOrModule, specifier
對相對應的 Module Record
不存在或沒法建立,則必須引起異常。referencingScriptOrModule, specifier
對做爲參數調用此操做時,若是正常完成,則必須返回相同的 Module Record
實例。讓咱們以一種易於理解的方式看看都發生了什麼。
HostResolveImportedModule(referencingScriptOrModule, specifier)
是一個抽象操做,該操做返回對應於ReferencingScriptOrModule, specifier
的模塊:
referencingScriptOrModule
是當前模塊,即進行導入的模塊。specifier
是對應 import
語句中模塊路徑的字符串。最後,HostResolveImportedModule()
從相同路徑導入模塊時,將導入相同模塊:
import moduleA from 'path'; import moduleB from 'path'; import moduleC from 'path'; // moduleA, moduleB and moduleC are equal moduleA === moduleB; // => true moduleB === moduleC; // => true
有趣的是,規範指出主機(指瀏覽器,Node 或任未嘗試運行 JavaScript 的東西)必須提供 HostResolveImportedModule()
的具體實現。
查看規範以後,你將知道對 JavaScript 模塊進行了一次評估。另外,從相同路徑導入模塊時,將返回相同的模塊實例。
讓咱們回到問題。
increment
模塊老是被評估一次:
// increment.js let counter = 0; counter++; export default counter;
無論 increment
模塊被導入多少次,counter++
語句僅執行一次。默認導出的 counter
變量的值爲 1
。
如今看 consumer
模塊:
// consumer.js import counter1 from './increment'; import counter2 from './increment'; counter1; // => 1 counter2; // => 1
import counter1 from './increment'
和 import counter2 from './increment'
有相同的路徑:'./increment'
。因此你將會導入相同的模塊實例。
最後,consumer
內部的 counter1
和 counter2
變量都等於 1
。
僅經過研究提出的簡單問題,就能夠找到有關如何評估和導入 JavaScript 模塊的詳細信息。
規則很是簡單:同一模塊僅被評估一次,換句話說,模塊級做用於僅被執行一次。若是評估後的模塊再次導入,則會跳過第二次評估,並使用已解決的已導出文件。
若是某個模塊屢次導入但使用相同的說明符(即路徑),則 JavaScript 規範可確保你將獲得相同的模塊實例。