精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

很全很全的JavaScript模塊講解,看了絕不后悔!

開發(fā) 前端
模塊通常是指編程語言所提供的代碼組織機制,利用此機制可將程序拆解為獨立且通用的代碼單元。所謂模塊化主要是解決代碼分割、作用域隔離、模塊之間的依賴管理以及發(fā)布到生產(chǎn)環(huán)境時的自動化打包與處理等多個方面。

模塊通常是指編程語言所提供的代碼組織機制,利用此機制可將程序拆解為獨立且通用的代碼單元。所謂模塊化主要是解決代碼分割、作用域隔離、模塊之間的依賴管理以及發(fā)布到生產(chǎn)環(huán)境時的自動化打包與處理等多個方面。

模塊的優(yōu)點

  1. 可維護性。 因為模塊是獨立的,一個設計良好的模塊會讓外面的代碼對自己的依賴越少越好,這樣自己就可以獨立去更新和改進。
  2. 命名空間。 在 JavaScript 里面,如果一個變量在最***的函數(shù)之外聲明,它就直接變成全局可用。因此,常常不小心出現(xiàn)命名沖突的情況。使用模塊化開發(fā)來封裝變量,可以避免污染全局環(huán)境。
  3. 重用代碼。 我們有時候會喜歡從之前寫過的項目中拷貝代碼到新的項目,這沒有問題,但是更好的方法是,通過模塊引用的方式,來避免重復的代碼庫。

CommonJS

CommonJS 最開始是 Mozilla 的工程師于 2009 年開始的一個項目,它的目的是讓瀏覽器之外的 JavaScript (比如服務器端或者桌面端)能夠通過模塊化的方式來開發(fā)和協(xié)作。

在 CommonJS 的規(guī)范中,每個 JavaScript 文件就是一個獨立的模塊上下文(module context),在這個上下文中默認創(chuàng)建的屬性都是私有的。也就是說,在一個文件定義的變量(還包括函數(shù)和類),都是私有的,對其他文件是不可見的。

需要注意的是,CommonJS 規(guī)范的主要適用場景是服務器端編程,所以采用同步加載模塊的策略。如果我們依賴3個模塊,代碼會一個一個依次加載它們。

該模塊實現(xiàn)方案主要包含 require 與 module 這兩個關(guān)鍵字,其允許某個模塊對外暴露部分接口并且由其他模塊導入使用。

  1. //sayModule.js 
  2.  
  3. function SayModule () {   
  4.  
  5. this.hello = function () { 
  6.  
  7.         console.log('hello'); 
  8.  
  9.     };     
  10.  
  11. this.goodbye = function () { 
  12.  
  13.         console.log('goodbye'); 
  14.  
  15.     }; 
  16.  
  17.  
  18. module.exports = SayModule; 
  19.  
  20. //main.js 引入sayModule.js 
  21.  
  22. var Say = require('./sayModule.js'); 
  23.  
  24. var sayer = new Say(); 
  25.  
  26. sayer.hello();  //hello
  27.  

 

作為一個服務器端的解決方案,CommonJS 需要一個兼容的腳本加載器作為前提條件。該腳本加載器必須支持名為 require 和 module.exports 的函數(shù),它們將模塊相互導入導出。 

Node.js 

Node 從 CommonJS 的一些創(chuàng)意中,創(chuàng)造出自己的模塊化實現(xiàn)。由于Node 在服務端的流行,Node 的模塊形式被(不正確地)稱為 CommonJS。

Node.js模塊可以分為兩大類,一類是核心模塊,另一類是文件模塊。

核心模塊

就是Node.js標準的API中提供的模塊,如fs、http、net等,這些都是由Node.js官方提供的模塊,編譯成了二進制代碼,可以直接通過require獲取核心模塊,例如require('fs'),核心模塊擁有***的加載優(yōu)先級,如果有模塊與核心模塊命名沖突,Node.js總是會加載核心模塊。

文件模塊

是存儲為單獨的文件(或文件夾)的模塊,可能是JavaScript代碼、JSON或編譯好的C/C++代碼。在不顯式指定文件模塊擴展名的時候,Node.js會分別試圖加上.js、.json、.node(編譯好的C/C++代碼)。

加載方式

按路徑加載模塊

如果require參數(shù)一"/"開頭,那么就以絕對路徑的方式查找模塊名稱,如果參數(shù)一"./"、"../"開頭,那么則是以相對路徑的方式來查找模塊。

通過查找node_modules目錄加載模塊

如果require參數(shù)不以"/"、"./"、"../"開頭,而該模塊又不是核心模塊,那么就要通過查找node_modules加載模塊了。我們使用的npm獲取的包通常就是以這種方式加載的。

加載緩存

Node.js模塊不會被重復加載,這是因為Node.js通過文件名緩存所有加載過的文件模塊,所以以后再訪問到時就不會重新加載了。

注意:Node.js是根據(jù)實際文件名緩存的,而不是require()提供的參數(shù)緩存的,也就是說即使你分別通過require('express')和require('./node_modules/express')加載兩次,也不會重復加載,因為盡管兩次參數(shù)不同,解析到的文件卻是同一個。

Node.js 中的模塊在加載之后是以單例化運行,并且遵循值傳遞原則:如果是一個對象,就相當于這個對象的引用。

模塊載入過程

加載文件模塊的工作,主要由原生模塊module來實現(xiàn)和完成,該原生模塊在啟動時已經(jīng)被加載,進程直接調(diào)用到runMain靜態(tài)方法。

例如運行: node app.js

  1. Module.runMain = function () {     
  2.  
  3. // Load the main module--the command line argument.     
  4.  
  5. Module._load(process.argv[1], nulltrue); 
  6.  
  7. }; 
  8.  
  9. //_load靜態(tài)方法在分析文件名之后執(zhí)行 
  10.  
  11. var module = new Module(id, parent); 
  12.  
  13. //并根據(jù)文件路徑緩存當前模塊對象,該模塊實例對象則根據(jù)文件名加載。 
  14.  
  15. module.load(filename); 

 

具體說一下上文提到了文件模塊的三類模塊,這三類文件模塊以后綴來區(qū)分,Node.js會根據(jù)后綴名來決定加載方法,具體的加載方法在下文 require.extensions中會介紹。

  • .js 通過fs模塊同步讀取js文件并編譯執(zhí)行。
  • .node 通過C/C++進行編寫的Addon。通過dlopen方法進行加載。
  • .json 讀取文件,調(diào)用JSON.parse解析加載。

接下來詳細描述js后綴的編譯過程。Node.js在編譯js文件的過程中實際完成的步驟有對js文件內(nèi)容進行頭尾包裝。以app.js為例,包裝之后的app.js將會變成以下形式:

  1. //circle.js 
  2.  
  3. var PI = Math.PI; 
  4.  
  5. exports.area = function (r) {     
  6.  
  7. return PI * r * r; 
  8.  
  9. }; 
  10.  
  11. exports.circumference = function (r) {     
  12.  
  13. return 2 * PI * r; 
  14.  
  15. }; 
  16.  
  17. //app.js 
  18.  
  19. var circle = require('./circle.js'); 
  20.  
  21. console.log( 'The area of a circle of radius 4 is ' + circle.area(4)); 
  22.  
  23. //app包裝后 
  24.  
  25. (function (exports, require, module, __filename, __dirname) {     
  26.  
  27. var circle = require('./circle.js'); 
  28.  
  29.     console.log('The area of a circle of radius 4 is ' + circle.area(4)); 
  30.  
  31. }); 
  32.  
  33. //這段代碼會通過vm原生模塊的runInThisContext方法執(zhí)行(類似eval,只是具有明確上下文,不污染全局),返回為一個具體的function對象。***傳入module對象的exports,require方法,module,文件名,目錄名作為實參并執(zhí)行。 

 

這就是為什么require并沒有定義在app.js 文件中,但是這個方法卻存在的原因。從Node.js的API文檔中可以看到還有 __filename、 __dirname、 module、 exports幾個沒有定義但是卻存在的變量。其中 __filename和 __dirname在查找文件路徑的過程中分析得到后傳入的。 module變量是這個模塊對象自身, exports是在module的構(gòu)造函數(shù)中初始化的一個空對象({},而不是null)。

在這個主文件中,可以通過require方法去引入其余的模塊。而其實這個require方法實際調(diào)用的就是module._load方法。

load方法在載入、編譯、緩存了module后,返回module的exports對象。這就是circle.js文件中只有定義在exports對象上的方法才能被外部調(diào)用的原因。

以上所描述的模塊載入機制均定義在lib/module.js中。

require 函數(shù)

require 引入的對象主要是函數(shù)。當 Node 調(diào)用 require() 函數(shù),并且傳遞一個文件路徑給它的時候,Node 會經(jīng)歷如下幾個步驟:

  • Resolving:找到文件的絕對路徑;
  • Loading:判斷文件內(nèi)容類型;
  • Wrapping:打包,給這個文件賦予一個私有作用范圍。這是使 require 和 module 模塊在本地引用的一種方法;
  • Evaluating:VM 對加載的代碼進行處理的地方;
  • Caching:當再次需要用這個文件的時候,不需要重復一遍上面步驟。

require.extensions 來查看對三種文件的支持情況:

可以清晰地看到 Node 對每種擴展名所使用的函數(shù)及其操作:對 .js 文件使用 module._compile;對 .json 文件使用 JSON.parse;對 .node 文件使用 process.dlopen。

文件查找策略

從文件模塊緩存中加載

盡管原生模塊與文件模塊的優(yōu)先級不同,但是優(yōu)先級***的是從文件模塊的緩存中加載已經(jīng)存在的模塊。

從原生模塊加載

原生模塊的優(yōu)先級僅次于文件模塊緩存的優(yōu)先級。require方法在解析文件名之后,優(yōu)先檢查模塊是否在原生模塊列表中。以http模塊為例,盡管在目錄下存在一個 http、 http.js、 http.node、 http.json文件, require(“http”)都不會從這些文件中加載,而是從原生模塊中加載。

原生模塊也有一個緩存區(qū),同樣也是優(yōu)先從緩存區(qū)加載。如果緩存區(qū)沒有被加載過,則調(diào)用原生模塊的加載方式進行加載和執(zhí)行。

從文件加載

當文件模塊緩存中不存在,而且不是原生模塊的時候,Node.js會解析require方法傳入的參數(shù),并從文件系統(tǒng)中加載實際的文件,加載過程中的包裝和編譯細節(jié)在前面說過是調(diào)用load方法。

當 Node 遇到 require(X) 時,按下面的順序處理。

1、如果 X 是內(nèi)置模塊(比如 require('http'))

  • a. 返回該模塊。
  • b. 不再繼續(xù)執(zhí)行。

2、如果 X 以 "./" 或者 "/" 或者 "../" 開頭

  • a. 根據(jù) X 所在的父模塊,確定 X 的絕對路徑。
  • b. 將 X 當成文件,依次查找下面文件,只要其中有一個存在,就返回該文件,不再繼續(xù)執(zhí)行。
    • X
    • X.js
    • X.json
    • X.node
  • c. 將 X 當成目錄,依次查找下面文件,只要其中有一個存在,就返回該文件,不再繼續(xù)執(zhí)行。
    • X/package.json(main字段)
    • X/index.js
    • X/index.json
    • X/index.node

3、如果 X 不帶路徑

  • a. 根據(jù) X 所在的父模塊,確定 X 可能的安裝目錄。
  • b. 依次在每個目錄中,將 X 當成文件名或目錄名加載。

4、拋出 "not found"

模塊循環(huán)依賴

  1. //創(chuàng)建兩個文件,module1.js 和 module2.js,并且讓它們相互引用     
  2.  
  3. // module1.js 
  4.  
  5.     exports.a = 1;     
  6.  
  7. require('./module2'); 
  8.  
  9.     exports.b = 2; 
  10.  
  11.     exports.c = 3;     
  12.  
  13. // module2.js     
  14.  
  15. const Module1 = require('./module1'); 
  16.  
  17.     console.log('Module1 is partially loaded here', Module1); 

 

在 module1 完全加載之前需要先加載 module2,而 module2 的加載又需要 module1。這種狀態(tài)下,我們從 exports 對象中能得到的就是在發(fā)生循環(huán)依賴之前的這部分。上面代碼中,只有 a 屬性被引入,因為 b 和 c 都需要在引入 module2 之后才能加載進來。

Node 使這個問題簡單化,在一個模塊加載期間開始創(chuàng)建 exports 對象。如果它需要引入其他模塊,并且有循環(huán)依賴,那么只能部分引入,也就是只能引入發(fā)生循環(huán)依賴之前所定義的這部分。

AMD

AMD 是 Asynchronous Module Definition 的簡稱,即“異步模塊定義”,是從 CommonJS 討論中誕生的。AMD 優(yōu)先照顧瀏覽器的模塊加載場景,使用了異步加載和回調(diào)的方式。

AMD 和 CommonJS 一樣需要腳本加載器,盡管 AMD 只需要對 define 方法的支持。define 方法需要三個參數(shù):模塊名稱,模塊運行的依賴數(shù)組,所有依賴都可用之后執(zhí)行的函數(shù)(該函數(shù)按照依賴聲明的順序,接收依賴作為參數(shù))。只有函數(shù)參數(shù)是必須的。define 既是一種引用模塊的方式,也是定義模塊的方式。

  1. // file lib/sayModule.js 
  2.  
  3. define(function (){     
  4.  
  5. return { 
  6.  
  7.         sayHello: function () { 
  8.  
  9.             console.log('hello'); 
  10.  
  11.         } 
  12.  
  13.     }; 
  14.  
  15. }); 
  16.  
  17. //file main.js 
  18.  
  19. define(['./lib/sayModule'], function (say){ 
  20.  
  21.     say.sayHello(); //hello 
  22.  
  23. }) 

 

main.js 作為整個應用的入口模塊,我們使用 define 關(guān)鍵字聲明了該模塊以及外部依賴(沒有生命模塊名稱);當我們執(zhí)行該模塊代碼時,也就是執(zhí)行 define 函數(shù)的第二個參數(shù)中定義的函數(shù)功能,其會在框架將所有的其他依賴模塊加載完畢后被執(zhí)行。這種延遲代碼執(zhí)行的技術(shù)也就保證了依賴的并發(fā)加載。

RequireJS

RequireJS 是一個前端的模塊化管理的工具庫,遵循AMD規(guī)范,通過一個函數(shù)來將所有所需要的或者說所依賴的模塊實現(xiàn)裝載進來,然后返回一個新的函數(shù)(模塊),我們所有的關(guān)于新模塊的業(yè)務代碼都在這個函數(shù)內(nèi)部操作,其內(nèi)部也可***制的使用已經(jīng)加載進來的以來的模塊。

  1. <script data-main='scripts/main' src='scripts/require.js'></script> 
  2.  
  3. //scripts下的main.js則是指定的主代碼腳本文件,所有的依賴模塊代碼文件都將從該文件開始異步加載進入執(zhí)行。 

 

defined用于定義模塊,RequireJS要求每個模塊均放在獨立的文件之中。按照是否有依賴其他模塊的情況分為獨立模塊和非獨立模塊。

1、獨立模塊 不依賴其他模塊。直接定義:

 

  1. define({    
  2.  
  3.     methodOne: function (){}, 
  4.  
  5.     methodTwo: function (){}}); 
  6.  
  7. //等價于 
  8.  
  9. define(function (){     
  10.  
  11. return { 
  12.  
  13.         methodOne: function (){}, 
  14.  
  15.         methodTwo: function (){} 
  16.  
  17.     }; 
  18.  
  19. }); 

 

2、非獨立模塊,對其他模塊有依賴。

 

  1. define([ 'moduleOne''moduleTwo' ], function(mOne, mTwo){ 
  2.  
  3.     ... 
  4.  
  5. }); 
  6.  
  7. //或者 
  8.  
  9. define( function( require ){     
  10.  
  11. var mOne = require( 'moduleOne' ), 
  12.  
  13.         mTwo = require( 'moduleTwo' ); 
  14.  
  15.     ... 
  16.  
  17. }); 

 

如上代碼, define中有依賴模塊數(shù)組的 和 沒有依賴模塊數(shù)組用require加載 這兩種定義模塊,調(diào)用模塊的方法合稱為AMD模式,定義模塊清晰,不會污染全局變量,清楚的顯示依賴關(guān)系。AMD模式可以用于瀏覽器環(huán)境并且允許非同步加載模塊,也可以按需動態(tài)加載模塊。

CMD

CMD(Common Module Definition),在CMD中,一個模塊就是一個文件。

全局函數(shù)define,用來定義模塊。

參數(shù) factory 可以是一個函數(shù),也可以為對象或者字符串。

當 factory 為對象、字符串時,表示模塊的接口就是該對象、字符串。

定義JSON數(shù)據(jù)模塊:

  1. define({ "foo""bar" }); 

factory 為函數(shù)的時候,表示模塊的構(gòu)造方法,執(zhí)行構(gòu)造方法便可以得到模塊向外提供的接口。

 

  1. define( function(require, exports, module) {      
  2.  
  3. // 模塊代碼 
  4.  
  5. }); 

 

SeaJS

sea.js 核心特征:

  1. 遵循CMD規(guī)范,與NodeJS般的書寫模塊代碼。
  2. 依賴自動加載,配置清晰簡潔。

seajs.use用來在頁面中加載一個或者多個模塊。 

 

  1. // 加載一個模塊  
  2.  
  3. seajs.use('./a'); 
  4.  
  5. // 加載模塊,加載完成時執(zhí)行回調(diào) 
  6.  
  7. seajs.use('./a'function(a){ 
  8.  
  9.     a.doSomething(); 
  10.  
  11. }); 
  12.  
  13. // 加載多個模塊執(zhí)行回調(diào) 
  14.  
  15. seajs.use(['./a','./b'],function(a , b){ 
  16.  
  17.     a.doSomething(); 
  18.  
  19.     b.doSomething(); 
  20.  
  21. }); 

 

AMD和CMD***的區(qū)別是對依賴模塊的執(zhí)行時機處理不同,注意不是加載的時機或者方式不同。

很多人說requireJS是異步加載模塊,SeaJS是同步加載模塊,這么理解實際上是不準確的,其實加載模塊都是異步的,只不過AMD依賴前置,js可以方便知道依賴模塊是誰,立即加載,而CMD就近依賴,需要使用把模塊變?yōu)樽址馕鲆槐椴胖酪蕾嚵四切┠K,這也是很多人詬病CMD的一點,犧牲性能來帶來開發(fā)的便利性,實際上解析模塊用的時間短到可以忽略。

為什么說是執(zhí)行時機處理不同?

同樣都是異步加載模塊,AMD在加載模塊完成后就會執(zhí)行該模塊,所有模塊都加載執(zhí)行完后會進入回調(diào)函數(shù),執(zhí)行主邏輯,這樣的效果就是依賴模塊的執(zhí)行順序和書寫順序不一定一致,看網(wǎng)絡速度,哪個先下載下來,哪個先執(zhí)行,但是主邏輯一定在所有依賴加載完成后才執(zhí)行。

CMD加載完某個依賴模塊后并不執(zhí)行,只是下載而已,在所有依賴模塊加載完成后進入主邏輯,遇到require語句的時候才執(zhí)行對應的模塊,這樣模塊的執(zhí)行順序和書寫順序是完全一致的。

UMD

統(tǒng)一模塊定義(UMD:Universal Module Definition )就是將 AMD 和 CommonJS 合在一起的一種嘗試,常見的做法是將CommonJS 語法包裹在兼容 AMD 的代碼中。

 

  1. (function(define) {    
  2.  
  3. define(function () {        
  4.  
  5. return { 
  6.  
  7.             sayHello: function () { 
  8.  
  9.                 console.log('hello'); 
  10.  
  11.             } 
  12.  
  13.         }; 
  14.  
  15.     }); 
  16.  
  17. }(     
  18.  
  19. typeof module === 'object' && module.exports && typeof define !== 'function' ?     
  20.  
  21. function (factory) { module.exports = factory(); } : 
  22.  
  23.     define 
  24.  
  25. )); 

 

該模式的核心思想在于所謂的 IIFE(Immediately Invoked Function Expression),該函數(shù)會根據(jù)環(huán)境來判斷需要的參數(shù)類別。

ES6模塊(module)

嚴格模式 

ES6 的模塊自動采用嚴格模式,不管有沒有在模塊頭部加上"use strict";。

嚴格模式主要有以下限制。

  • 變量必須聲明后再使用
  • 函數(shù)的參數(shù)不能有同名屬性,否則報錯
  • 不能使用with語句
  • 不能對只讀屬性賦值,否則報錯
  • 不能使用前綴0表示八進制數(shù),否則報錯
  • 不能刪除不可刪除的屬性,否則報錯
  • 不能刪除變量delete prop,會報錯,只能刪除屬性delete global[prop]
  • eval不會在它的外層作用域引入變量
  • eval和arguments不能被重新賦值
  • arguments不會自動反映函數(shù)參數(shù)的變化
  • 不能使用arguments.callee
  • 不能使用arguments.caller
  • 禁止this指向全局對象
  • 不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧
  • 增加了保留字(比如protected、static和interface)

模塊Module

一個模塊,就是一個對其他模塊暴露自己的屬性或者方法的文件。

導出Export

作為一個模塊,它可以選擇性地給其他模塊暴露(提供)自己的屬性和方法,供其他模塊使用。

  1. // profile.js 
  2.  
  3. export var firstName = 'qiqi'
  4.  
  5. export var lastName = 'haobenben'
  6.  
  7. export var year = 1992; 
  8.  
  9. //等價于 
  10.  
  11. var firstName = 'qiqi'
  12.  
  13. var lastName = 'haobenben'
  14.  
  15. var year = 1992; 
  16.  
  17. export {firstName, lastName, year

 

1、 通常情況下,export輸出的變量就是本來的名字,但是可以使用as關(guān)鍵字重命名。

  1. function v1() { ... } 
  2.  
  3. function v2() { ... } 
  4.  
  5. export { 
  6.  
  7.   v1 as streamV1, 
  8.  
  9.   v2 as streamV2, 
  10.  
  11.   v2 as streamLatestVersion}; 
  12.  
  13. //上面代碼使用as關(guān)鍵字,重命名了函數(shù)v1和v2的對外接口。重命名后,v2可以用不同的名字輸出兩次。 

 

2、 需要特別注意的是,export命令規(guī)定的是對外的接口,必須與模塊內(nèi)部的變量建立一一對應關(guān)系。

 

  1. // 報錯 
  2.  
  3. export 1; 
  4.  
  5. // 報錯 
  6.  
  7. var m = 1; 
  8.  
  9. export m; 
  10.  
  11. //上面兩種寫法都會報錯,因為沒有提供對外的接口。***種寫法直接輸出1,第二種寫法通過變量m,還是直接輸出1。1只是一個值,不是接口。 
  12.  
  13. // 寫法一 
  14.  
  15. export var m = 1; 
  16.  
  17. // 寫法二 
  18.  
  19. var m = 1; 
  20.  
  21. export {m}; 
  22.  
  23. // 寫法三 
  24.  
  25. var n = 1; 
  26.  
  27. export {n as m}; 

 

//上面三種寫法都是正確的,規(guī)定了對外的接口m。其他腳本可以通過這個接口,取到值1。它們的實質(zhì)是,在接口名與模塊內(nèi)部變量之間,建立了一一對應的關(guān)系。

3、***,export命令可以出現(xiàn)在模塊的任何位置,只要處于模塊頂層就可以。如果處于塊級作用域內(nèi),就會報錯,接下來說的import命令也是如此。

 

  1. function foo() {   
  2.  
  3. export default 'bar' // SyntaxError 
  4.  
  5.  
  6. foo() 

 

導入import

作為一個模塊,可以根據(jù)需要,引入其他模塊的提供的屬性或者方法,供自己模塊使用。

1、 import命令接受一對大括號,里面指定要從其他模塊導入的變量名。大括號里面的變量名,必須與被導入模塊(profile.js)對外接口的名稱相同。如果想為輸入的變量重新取一個名字,import命令要使用as關(guān)鍵字,將輸入的變量重命名。

  1. import { lastName as surename } from './profile'

2、import后面的from指定模塊文件的位置,可以是相對路徑,也可以是絕對路徑,.js路徑可以省略。如果只是模塊名,不帶有路徑,那么必須有配置文件,告訴 JavaScript 引擎該模塊的位置。

3、注意,import命令具有提升效果,會提升到整個模塊的頭部,首先執(zhí)行。

  1. foo(); 
  2.  
  3. import { foo } from 'my_module'
  4.  
  5. //上面的代碼不會報錯,因為import的執(zhí)行早于foo的調(diào)用。這種行為的本質(zhì)是,import命令是編譯階段執(zhí)行的,在代碼運行之前。 

 

4、由于import是靜態(tài)執(zhí)行,所以不能使用表達式和變量,這些只有在運行時才能得到結(jié)果的語法結(jié)構(gòu)。

  1. // 報錯 
  2.  
  3. import { 'f' + 'oo' } from 'my_module'
  4.  
  5. // 報錯 
  6.  
  7. let module = 'my_module'
  8.  
  9. import { foo } from module; 
  10.  
  11. // 報錯 
  12.  
  13. if (x === 1) {   
  14.  
  15.    import { foo } from 'module1'
  16.  
  17. }  
  18.  
  19. else {   
  20.  
  21.   import { foo } from 'module2'
  22.  

 

5、***,import語句會執(zhí)行所加載的模塊,因此可以有下面的寫法。

  1. import 'lodash'
  2.  
  3. //上面代碼僅僅執(zhí)行l(wèi)odash模塊,但是不輸入任何值。 

 

默認導出(export default)

每個模塊支持我們導出 一個沒有名字的變量,使用關(guān)鍵語句export default來實現(xiàn)。

  1. export default function(){ 
  2.  
  3.             console.log("I am default Fn"); 
  4.  
  5.  
  6. //使用export default關(guān)鍵字對外導出一個匿名函數(shù),導入這個模塊的時候,可以為這個匿名函數(shù)取任意的名字 
  7.  
  8. //取任意名字均可 
  9.  
  10. import sayDefault from "./module-B.js"
  11.  
  12. sayDefault(); 
  13.  
  14. //結(jié)果:I am default Fn 

 

1、默認輸出和正常輸出的比較

  1. // ***組 
  2.  
  3. export default function diff() {  
  4.  
  5. // 輸出   
  6.  
  7. // ... 
  8.  
  9.  
  10. import diff from 'diff';  
  11.  
  12. // 輸入 
  13.  
  14. // 第二組 
  15.  
  16. export function diff() {  
  17.  
  18. // 輸出   
  19.  
  20. // ... 
  21.  
  22. }; 
  23.  
  24. import {diff} from 'diff';  
  25.  
  26. // 輸入 
  27.  
  28. //上面代碼的兩組寫法,***組是使用export default時,對應的import語句不需要使用大括號;第二組是不使用export default時,對應的import語句需要使用大括號。 

 

export default命令用于指定模塊的默認輸出。顯然,一個模塊只能有一個默認輸出,因此export default命令只能使用一次。所以,import命令后面才不用加大括號,因為只可能對應一個方法。

2、因為export default本質(zhì)是將該命令后面的值,賦給default變量以后再默認,所以直接將一個值寫在export default之后。

  1. // 正確 
  2.  
  3. export default 42; 
  4.  
  5. // 報錯 
  6.  
  7. export 42; 
  8.  
  9. //上面代碼中,后一句報錯是因為沒有指定對外的接口,而前一句指定外對接口為default。 

 

3、如果想在一條import語句中,同時輸入默認方法和其他變量,可以寫成下面這樣。

  1. import _, { each } from 'lodash'
  2.  
  3. //對應上面代碼的export語句如下 
  4.  
  5. export default function (){     
  6.  
  7. //... 
  8.  
  9.  
  10. export function each (obj, iterator, context){     
  11.  
  12. //... 
  13.  

 

export 與 import 的復合寫法

如果在一個模塊之中,先輸入后輸出同一個模塊,import語句可以與export語句寫在一起。

  1. export { foo, bar } from 'my_module'
  2.  
  3. // 等同于 
  4.  
  5. import { foo, bar } from 'my_module'
  6.  
  7. export { foo, bar }; 
  8.  
  9. / 接口改名 
  10.  
  11. export { foo as myFoo } from 'my_module'
  12.  
  13. // 整體輸出 
  14.  
  15. export * from 'my_module'

 

注意事項

  1. 聲明的變量,對外都是只讀的。但是導出的是對象類型的值,就可修改。
  2. 導入不存在的變量,值為undefined。

ES6 中的循環(huán)引用

ES6 中,imports 是 exprts 的只讀視圖,直白一點就是,imports 都指向 exports 原本的數(shù)據(jù),比如:

 

  1. //------ lib.js ------ 
  2.  
  3. export let counter = 3; 
  4.  
  5. export function incCounter() { 
  6.  
  7.     counter++; 
  8.  
  9.  
  10. //------ main.js ------ 
  11.  
  12. import { counter, incCounter } from './lib'
  13.  
  14. // The imported value `counter` is live 
  15.  
  16. console.log(counter);  
  17.  
  18. // 3 
  19.  
  20. incCounter(); 
  21.  
  22. console.log(counter);  
  23.  
  24. // 4 
  25.  
  26. // The imported value can’t be changed 
  27.  
  28. counter++;  
  29.  
  30. // TypeError 

 

因此在 ES6 中處理循環(huán)引用特別簡單,看下面這段代碼:

  1. //------ a.js ------ 
  2.  
  3. import {bar} from 'b';  
  4.  
  5. // (1) 
  6.  
  7. export function foo() { 
  8.  
  9.   bar();  
  10.  
  11. // (2) 
  12.  
  13.  
  14. //------ b.js ------ 
  15.  
  16. import {foo} from 'a';  
  17.  
  18. // (3) 
  19.  
  20. export function bar() {   
  21.  
  22. if (Math.random()) { 
  23.  
  24.     foo();  
  25.  
  26. // (4) 
  27.  
  28.   } 
  29.  

 

假設先加載模塊 a,在模塊 a 加載完成之后,bar 間接性地指向的是模塊 b 中的 bar。無論是加載完成的 imports 還是未完成的 imports,imports 和 exports 之間都有一個間接的聯(lián)系,所以總是可以正常工作。

實例

 

  1. //---module-B.js文件--- 
  2.  
  3. //導出變量:name 
  4.  
  5. export var name = "cfangxu"
  6.  
  7. moduleA模塊代碼: 
  8.  
  9. //導入 模塊B的屬性 name     
  10.  
  11. import { name } from "./module-B.js";    
  12.  
  13. console.log(name)
  14.  
  15. //打印結(jié)果:cfangxu 

 

批量導出:

 

  1. //屬性name 
  2.  
  3. var name = "cfangxu"
  4.  
  5. //屬性age 
  6.  
  7. var age  = 26; 
  8.  
  9. //方法 say 
  10.  
  11. var say = function(){ 
  12.  
  13.             console.log("say hello"); 
  14.  
  15.   } 
  16.  
  17. //批量導出 
  18.  
  19. export {name,age,say} 

 

批量導入:

 

  1. //導入 模塊B的屬性 
  2.  
  3. import { name,age,say } from "./module-B.js"
  4.  
  5. console.log(name
  6.  
  7. //打印結(jié)果:cfangxu 
  8.  
  9. console.log(age) 
  10.  
  11. //打印結(jié)果:26 
  12.  
  13. say() 
  14.  
  15. //打印結(jié)果:say hello 

 

重命名導入變量:

 

  1. import {name as myName} from './module-B.js'
  2.  
  3. console.log(myName)  
  4.  
  5. //cfangxu 

 

整體導入:

 

  1. //使用*實現(xiàn)整體導入 
  2.  
  3. import * as obj from "./module-B.js"
  4.  
  5. console.log(obj.name
  6.  
  7. //結(jié)果:"cfangxu" 
  8.  
  9. console.log(obj.age) 
  10.  
  11. //結(jié)果:26 
  12.  
  13. obj.say(); 
  14.  
  15. //結(jié)果:say hello  

 

責任編輯:龐桂玉 來源: 前端大全
相關(guān)推薦

2017-12-28 15:20:50

2020-05-12 08:39:50

JavaScript工具技術(shù)

2020-01-14 09:13:48

Tomcat調(diào)優(yōu)配置

2015-02-13 10:35:08

openstackapi文檔

2017-10-16 18:29:36

數(shù)據(jù)庫Oracle常用語句

2010-08-10 08:58:55

2019-05-23 10:18:19

監(jiān)控組件cpu

2011-09-13 08:55:59

在這兒IM在這兒職業(yè)

2023-11-20 21:56:57

入職微軟

2019-08-13 09:29:14

Kafka運營數(shù)據(jù)

2012-11-08 00:46:00

AMD服務器芯片

2013-12-09 09:42:50

JavaScript全棧式

2024-01-31 12:13:02

JavaScriptSet元素

2009-06-14 08:34:53

OpenSolaris開源

2017-04-06 10:27:01

JavaScript基礎Java

2010-04-26 13:53:47

Unix Shell

2014-04-02 11:22:26

JavascriptMEAN

2012-07-17 11:40:10

情景音樂華為

2012-03-15 16:52:02

聯(lián)想筆記本

2018-01-12 15:36:09

JavaScript參數(shù)功能
點贊
收藏

51CTO技術(shù)棧公眾號

91亚洲一线产区二线产区| 久久伊人资源站| 国产精品夜夜夜爽阿娇| 国产精品xnxxcom| 亚洲欧美日韩久久精品| 99久久精品无码一区二区毛片 | 99国产一区二区三精品乱码| 57pao国产精品一区| 在线小视频你懂的| 99视频有精品高清视频| 亚洲自拍偷拍欧美| 久久综合九色99| 国产又大又黑又粗| 伊人影院久久| 中文字幕日韩av| 国产ts在线观看| 一区在线影院| 亚洲成人高清在线| 亚洲精品一区二区三| 精品国产无码一区二区| 亚洲欧美网站| 欧美日本亚洲视频| 中文字幕第20页| 日本久久久久| 日韩欧美国产激情| 潘金莲一级淫片aaaaa免费看| 色综合久久久久久| 美女精品在线| 欧美国产日韩一区二区| 性猛交娇小69hd| 波多野结衣欧美| 欧美日韩国产123区| 国产无限制自拍| 黄色动漫在线观看| 91伊人久久大香线蕉| 91在线网站视频| 国产乡下妇女三片| 99在线|亚洲一区二区| 日韩日本欧美亚洲| 91视频在线网站| 99这里只有精品视频| 欧美福利一区二区| 热久久精品免费视频| 白浆视频在线观看| 一个色综合av| 宅男av一区二区三区| 青青草超碰在线| 不卡欧美aaaaa| 操一操视频一区| 国产一区二区三区成人| 日韩高清不卡一区| 欧美在线视频免费| 日韩免费在线视频观看| 国产一区二区三区四区三区四| 色狠狠av一区二区三区香蕉蜜桃| 久久国产精品影院| 欧美日韩一区二区三区在线电影| 欧美一级艳片视频免费观看| 五月婷婷之婷婷| 99热播精品免费| 色呦呦国产精品| 男人操女人免费软件| 免费av不卡在线观看| 亚洲色图在线看| 看全色黄大色大片| 国产黄网站在线观看| 国产精品国产三级国产| 亚洲自拍三区| 麻豆传媒视频在线观看免费| 中文字幕中文字幕在线一区| 中文精品视频一区二区在线观看| 在线看的av网站| 国产精品久久久久四虎| 亚洲午夜精品久久久中文影院av| 137大胆人体在线观看| 国产精品丝袜在线| 国产一区一区三区| 性欧美video高清bbw| 一区二区三区中文字幕电影| 欧美性猛交内射兽交老熟妇| 岛国片av在线| 狠狠躁夜夜躁人人爽天天天天97| 免费无码av片在线观看| 日韩一区二区三区在线免费观看 | 国产偷国产偷亚洲高清人白洁| 欧美精品中文字幕一区二区| 国产福利电影在线| 国产精品的网站| 亚洲精品天堂成人片av在线播放| 久久亚洲资源| 日韩欧美aaa| 男女视频在线看| 国产精品视频首页| 亚洲国产精品99久久| 免费a级黄色片| heyzo久久| 久久影院资源网| 中文字幕影音先锋| 国产精品最新自拍| 国产免费一区视频观看免费| av小说天堂网| 久久亚洲私人国产精品va媚药| 视频三区二区一区| 91麻豆国产福利在线观看宅福利| 五月婷婷激情综合网| mm1313亚洲国产精品无码试看| 国产精品麻豆| 亚洲欧美一区二区激情| 91大神福利视频| 亚洲精品乱码久久久久久蜜桃麻豆| 日韩av观看网址| 国产黄频在线观看| 久久美女高清视频| 女同性恋一区二区| 亚洲承认视频| 亚洲成人av在线| 国产精品夜夜夜爽阿娇| 国产婷婷精品| 91黄在线观看| 91caoporm在线视频| 亚洲一区二区3| 好男人www社区| 国产成人高清精品免费5388| 在线播放国产一区二区三区| 精品无码av在线| 久久精品国产精品亚洲精品| 久久精品日产第一区二区三区精品版 | 麻豆久久精品| 国产精品10p综合二区| 四虎久久免费| 久久综合88| 久久久综合免费视频| 亚洲熟妇av乱码在线观看| 成人v精品蜜桃久久一区| 亚洲一区二区精品在线观看| 九九精品调教| 欧美福利电影网| 日本一道本视频| 免费日韩av片| 国模精品娜娜一二三区| av在线免费播放| 欧美日韩国产系列| 中文字幕人妻一区二区三区在线视频| 一区久久精品| 99久久自偷自偷国产精品不卡| 在线播放麻豆| 在线观看av一区二区| 一本色道久久综合亚洲精品图片| 亚洲精品极品| 国产在线一区二| sm在线播放| 亚洲国产美女久久久久| 久久久久久天堂| 国产成人精品www牛牛影视| 黄色高清视频网站| 亚洲高清影院| 精品国内产的精品视频在线观看| 亚洲图片欧美日韩| 久久久91精品国产一区二区精品| 少妇性饥渴无码a区免费| 国产在线播放精品| 高清欧美性猛交xxxx| 国产成人自拍一区| 午夜国产精品一区| 国产精品果冻传媒| 99精品99| 免费看成人av| 小明成人免费视频一区| 国产一区二区三区在线视频| 久久久久精彩视频| 一区精品在线播放| 国产精品嫩草影视| 国产精品a级| 国产专区一区二区| 欧美三级精品| www.欧美精品| www.黄色av| 亚洲va韩国va欧美va| 久久午夜夜伦鲁鲁片| 午夜亚洲激情| 亚洲永久激情精品| 日本精品一区二区三区在线观看视频| 欧美激情免费看| 无码精品在线观看| 欧洲国产伦久久久久久久| 男女男精品视频网站| 激情综合色播激情啊| 国产精品videossex国产高清 | 丁香花在线观看完整版电影| 日韩精品久久久久久福利| a天堂视频在线观看| 99热这里只有精品8| 日本免费高清不卡| 91视频亚洲| 97视频色精品| 婷婷视频在线| 精品动漫一区二区三区在线观看| 天堂网中文字幕| 最新日韩在线视频| www.四虎精品| 日韩专区一卡二卡| japanese在线播放| 亚洲aa在线| 亚洲精品女av网站| 中文日产幕无线码一区二区| yellow中文字幕久久| 好吊色视频一区二区| 在线一区二区三区四区五区 | 亚洲国产日日夜夜| 精品国产成人亚洲午夜福利| 国产成人自拍高清视频在线免费播放| 91免费视频网站在线观看| 久久中文亚洲字幕| 蜜桃视频在线观看成人| 国产亚洲亚洲国产一二区| 欧洲成人性视频| 色操视频在线| xvideos国产精品| 免费国产在线观看| 日韩女优av电影在线观看| 波多野结衣黄色网址| 亚洲高清不卡在线| 九九精品视频免费| 久久精品这里都是精品| 亚洲激情 欧美| 国产黄色精品视频| 国产三级三级看三级| 国产视频一区三区| 成人性生活视频免费看| 91精品高清| 亚洲午夜精品福利| 欧美日韩激情| 欧美精品久久久| 欧美日韩导航| 精品国产乱码久久久久久蜜柚| 日本成人精品| 成人妇女淫片aaaa视频| 午夜影院在线播放| 欧美激情精品久久久久| av免费看在线| 久久亚洲精品视频| 浪潮av一区| yellow中文字幕久久| 四虎久久免费| www.日韩免费| 看女生喷水的网站在线观看| 日韩在线观看免费全集电视剧网站| 国产福利在线| 宅男66日本亚洲欧美视频| 国产在线观看网站| 亚洲一区999| 成人在线观看免费| 伊人久久精品视频| 久久综合九色综合久| 亚洲人成免费电影| 国产视频网址在线| 亚洲午夜激情免费视频| 国产一级片在线| 最新国产精品拍自在线播放| 自拍视频在线免费观看| 日韩有码在线电影| 精精国产xxxx视频在线| 久久久国产影院| 色爱综合区网| 91国产一区在线| 周于希免费高清在线观看| 欧美一级免费视频| 日本精品在线中文字幕| 国产精品美女www爽爽爽视频| 国产黄色精品| 444亚洲人体| 成人福利免费在线观看| 久久99导航| 成人激情电影在线| 激情图片qvod| 亚洲美女啪啪| 亚洲免费av一区二区三区| 日韩成人免费电影| 在线免费看v片| 播五月开心婷婷综合| xxxx日本黄色| 亚洲精品免费在线| 毛片视频网站在线观看| 欧美性淫爽ww久久久久无| 国产av无码专区亚洲av| 亚洲精品电影网| 在线视频婷婷| 国内精品模特av私拍在线观看| 欧美片第1页| 3d动漫啪啪精品一区二区免费 | 日韩理论片在线观看| 天天色综合色| 看av免费毛片手机播放| 蜜臀av性久久久久蜜臀av麻豆| 亚洲精品无码久久久久久久| 99伊人成综合| 国产日韩欧美久久| 成人免费视频播放| 人成免费在线视频| 亚洲国产日产av| 在线观看xxxx| 亚洲精品二三区| 黄色免费网站在线观看| 456亚洲影院| 欧美经典影片视频网站| 美女亚洲精品| 欧美视频二区| 免费一区二区三区在线观看| 成人免费精品视频| 夫妇交换中文字幕| 亚洲欧洲一区二区在线播放| 久久精品国产亚洲AV无码男同| 精品久久久久久久久中文字幕| 超碰在线免费97| 亚洲第一网站免费视频| 免费黄网站在线| 欧美亚洲伦理www| 欧美视频免费看| 久久久影院一区二区三区| 日韩毛片视频| 免费日韩中文字幕| 国产成人免费在线视频| 欧美aaa级片| 欧美性黄网官网| 亚洲国产一二三区| 久久精品国产一区二区电影| 竹内纱里奈兽皇系列在线观看 | 国产香蕉一区二区三区| 噜噜噜在线观看免费视频日韩| √天堂资源在线| 国产亚洲一区二区三区四区 | 天天射,天天干| 欧美成人精品h版在线观看| 写真福利精品福利在线观看| 精品日韩美女| 国内自拍一区| 日韩欧美中文视频| 中文一区在线播放| 亚洲不卡视频在线观看| 国产视频欧美视频| xxxx另类黑人| caoporen国产精品| 欧美日韩午夜| 精品人妻一区二区三区免费| 亚洲欧洲日本在线| 亚洲精品国产精品乱码视色| 精品国产乱码久久久久久浪潮| 超碰在线无需免费| 国产日韩精品入口| 久久亚洲影视| 天天色综合天天色| 国产日产欧美精品一区二区三区| 国产精品一区无码| 亚洲久久久久久久久久| 永久免费毛片在线播放| 精品久久久三级| 激情综合中文娱乐网| 久久久久亚洲AV成人网人人小说| 亚洲天堂久久久久久久| 国产精品怡红院| 久久精品国产电影| 国产精久久久| 中文字幕人妻熟女人妻洋洋| 国产成人综合视频| 日韩成人在线免费视频| 亚洲大胆人体在线| 日本天码aⅴ片在线电影网站| 91青青草免费观看| 国产综合网站| 国产老熟女伦老熟妇露脸| 午夜私人影院久久久久| 日本中文字幕电影在线观看| 奇门遁甲1982国语版免费观看高清| 亚洲欧美日本伦理| 高清一区在线观看| 中文字幕亚洲精品在线观看| 99久久精品国产成人一区二区| 美女精品久久久| 999精品视频在线观看| 青青草免费在线视频观看| 国产激情一区二区三区四区 | 国产精品aaa| 四季av一区二区凹凸精品| 手机av在线网站| 亚洲自拍另类综合| 美女做暖暖视频免费在线观看全部网址91 | 精品无人区一区二区三区 | 欧美在线观看日本一区| 99这里只有精品视频| 国产女女做受ⅹxx高潮| 中文字幕免费不卡| 亚洲国产www| 日本精品视频在线播放| 97精品国产一区二区三区| 4438x全国最大成人| 亚洲国产日日夜夜| 91se在线| 狠狠色伊人亚洲综合网站色| 欧美aaaaaa午夜精品| 欧美又粗又大又长|