溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript模塊知識(shí)點(diǎn)有哪些

發(fā)布時(shí)間:2021-11-15 15:01:28 來源:億速云 閱讀:180 作者:iii 欄目:web開發(fā)

這篇文章主要介紹“JavaScript模塊知識(shí)點(diǎn)有哪些”,在日常操作中,相信很多人在JavaScript模塊知識(shí)點(diǎn)有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”JavaScript模塊知識(shí)點(diǎn)有哪些”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

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

模塊的優(yōu)點(diǎn)

  1. 可維護(hù)性。 因?yàn)槟K是獨(dú)立的,一個(gè)設(shè)計(jì)良好的模塊會(huì)讓外面的代碼對(duì)自己的依賴越少越好,這樣自己就可以獨(dú)立去更新和改進(jìn)。

  2. 命名空間。 在 JavaScript 里面,如果一個(gè)變量在最***的函數(shù)之外聲明,它就直接變成全局可用。因此,常常不小心出現(xiàn)命名沖突的情況。使用模塊化開發(fā)來封裝變量,可以避免污染全局環(huán)境。

  3. 重用代碼。 我們有時(shí)候會(huì)喜歡從之前寫過的項(xiàng)目中拷貝代碼到新的項(xiàng)目,這沒有問題,但是更好的方法是,通過模塊引用的方式,來避免重復(fù)的代碼庫(kù)。

CommonJS

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

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

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

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

//sayModule.js  function SayModule () {    this.hello = function () {          console.log('hello');      };      this.goodbye = function () {          console.log('goodbye');      };  }  module.exports = SayModule;  //main.js 引入sayModule.js  var Say = require('./sayModule.js');  var sayer = new Say();  sayer.hello();  //hello

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

Node.js 

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

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

核心模塊

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

文件模塊

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

加載方式

按路徑加載模塊

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

通過查找node_modules目錄加載模塊

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

加載緩存

Node.js模塊不會(huì)被重復(fù)加載,這是因?yàn)镹ode.js通過文件名緩存所有加載過的文件模塊,所以以后再訪問到時(shí)就不會(huì)重新加載了。

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

Node.js 中的模塊在加載之后是以單例化運(yùn)行,并且遵循值傳遞原則:如果是一個(gè)對(duì)象,就相當(dāng)于這個(gè)對(duì)象的引用。

模塊載入過程

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

例如運(yùn)行: node app.js

Module.runMain = function () {      // Load the main module--the command line argument.      Module._load(process.argv[1], null, true);  };  //_load靜態(tài)方法在分析文件名之后執(zhí)行  var module = new Module(id, parent);  //并根據(jù)文件路徑緩存當(dāng)前模塊對(duì)象,該模塊實(shí)例對(duì)象則根據(jù)文件名加載。  module.load(filename);

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

  • .js 通過fs模塊同步讀取js文件并編譯執(zhí)行。

  • .node 通過C/C++進(jìn)行編寫的Addon。通過dlopen方法進(jìn)行加載。

  • .json 讀取文件,調(diào)用JSON.parse解析加載。

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

//circle.js  var PI = Math.PI;  exports.area = function (r) {      return PI * r * r;  };  exports.circumference = function (r) {      return 2 * PI * r;  };  //app.js  var circle = require('./circle.js');  console.log( 'The area of a circle of radius 4 is ' + circle.area(4));  //app包裝后  (function (exports, require, module, __filename, __dirname) {      var circle = require('./circle.js');      console.log('The area of a circle of radius 4 is ' + circle.area(4));  });  //這段代碼會(huì)通過vm原生模塊的runInThisContext方法執(zhí)行(類似eval,只是具有明確上下文,不污染全局),返回為一個(gè)具體的function對(duì)象。***傳入module對(duì)象的exports,require方法,module,文件名,目錄名作為實(shí)參并執(zhí)行。

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

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

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

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

require 函數(shù)

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

  • Resolving:找到文件的絕對(duì)路徑;

  • Loading:判斷文件內(nèi)容類型;

  • Wrapping:打包,給這個(gè)文件賦予一個(gè)私有作用范圍。這是使 require 和 module 模塊在本地引用的一種方法;

  • Evaluating:VM 對(duì)加載的代碼進(jìn)行處理的地方;

  • Caching:當(dāng)再次需要用這個(gè)文件的時(shí)候,不需要重復(fù)一遍上面步驟。

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

JavaScript模塊知識(shí)點(diǎn)有哪些

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

文件查找策略

從文件模塊緩存中加載

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

從原生模塊加載

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

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

從文件加載

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

當(dāng) Node 遇到 require(X) 時(shí),按下面的順序處理。

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

  • a. 返回該模塊。

  • b. 不再繼續(xù)執(zhí)行。

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

  • a. 根據(jù) X 所在的父模塊,確定 X 的絕對(duì)路徑。

  • b. 將 X 當(dāng)成文件,依次查找下面文件,只要其中有一個(gè)存在,就返回該文件,不再繼續(xù)執(zhí)行。

    • X

    • X.js

    • X.json

    • X.node

  • c. 將 X 當(dāng)成目錄,依次查找下面文件,只要其中有一個(gè)存在,就返回該文件,不再繼續(xù)執(zhí)行。

    • X/package.json(main字段)

    • X/index.js

    • X/index.json

    • X/index.node

3、如果 X 不帶路徑

  • a. 根據(jù) X 所在的父模塊,確定 X 可能的安裝目錄。

  • b. 依次在每個(gè)目錄中,將 X 當(dāng)成文件名或目錄名加載。

4、拋出 "not found"

JavaScript模塊知識(shí)點(diǎn)有哪些

模塊循環(huán)依賴

//創(chuàng)建兩個(gè)文件,module1.js 和 module2.js,并且讓它們相互引用      // module1.js      exports.a = 1;      require('./module2');      exports.b = 2;      exports.c = 3;      // module2.js      const Module1 = require('./module1');      console.log('Module1 is partially loaded here', Module1);

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

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

AMD

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

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

// file lib/sayModule.js  define(function (){      return {          sayHello: function () {              console.log('hello');          }      };  });  //file main.js  define(['./lib/sayModule'], function (say){      say.sayHello(); //hello  })

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

RequireJS

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

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

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

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

define({         methodOne: function (){},      methodTwo: function (){}});  //等價(jià)于  define(function (){      return {          methodOne: function (){},          methodTwo: function (){}      };  });

2、非獨(dú)立模塊,對(duì)其他模塊有依賴。

define([ 'moduleOne', 'moduleTwo' ], function(mOne, mTwo){      ...  });  //或者  define( function( require ){      var mOne = require( 'moduleOne' ),          mTwo = require( 'moduleTwo' );      ...  });

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

CMD

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

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

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

當(dāng) factory 為對(duì)象、字符串時(shí),表示模塊的接口就是該對(duì)象、字符串。

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

define({ "foo": "bar" });

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

define( function(require, exports, module) {       // 模塊代碼  });

SeaJS

sea.js 核心特征:

  1. 遵循CMD規(guī)范,與NodeJS般的書寫模塊代碼。

  2. 依賴自動(dòng)加載,配置清晰簡(jiǎn)潔。

seajs.use用來在頁(yè)面中加載一個(gè)或者多個(gè)模塊。

// 加載一個(gè)模塊   seajs.use('./a');  // 加載模塊,加載完成時(shí)執(zhí)行回調(diào)  seajs.use('./a',function(a){      a.doSomething();  });  // 加載多個(gè)模塊執(zhí)行回調(diào)  seajs.use(['./a','./b'],function(a , b){      a.doSomething();      b.doSomething();  });

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

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

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

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

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

UMD

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

(function(define) {     define(function () {         return {              sayHello: function () {                  console.log('hello');              }          };      });  }(      typeof module === 'object' && module.exports && typeof define !== 'function' ?      function (factory) { module.exports = factory(); } :      define  ));

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

ES6模塊(module)

嚴(yán)格模式 

ES6 的模塊自動(dòng)采用嚴(yán)格模式,不管有沒有在模塊頭部加上"use strict";。

嚴(yán)格模式主要有以下限制。

  • 變量必須聲明后再使用

  • 函數(shù)的參數(shù)不能有同名屬性,否則報(bào)錯(cuò)

  • 不能使用with語(yǔ)句

  • 不能對(duì)只讀屬性賦值,否則報(bào)錯(cuò)

  • 不能使用前綴0表示八進(jìn)制數(shù),否則報(bào)錯(cuò)

  • 不能刪除不可刪除的屬性,否則報(bào)錯(cuò)

  • 不能刪除變量delete prop,會(huì)報(bào)錯(cuò),只能刪除屬性delete global[prop]

  • eval不會(huì)在它的外層作用域引入變量

  • eval和arguments不能被重新賦值

  • arguments不會(huì)自動(dòng)反映函數(shù)參數(shù)的變化

  • 不能使用arguments.callee

  • 不能使用arguments.caller

  • 禁止this指向全局對(duì)象

  • 不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧

  • 增加了保留字(比如protected、static和interface)

模塊Module

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

導(dǎo)出Export

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

// profile.js  export var firstName = 'qiqi';  export var lastName = 'haobenben';  export var year = 1992;  //等價(jià)于  var firstName = 'qiqi';  var lastName = 'haobenben';  var year = 1992;  export {firstName, lastName, year}

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

function v1() { ... }  function v2() { ... }  export {    v1 as streamV1,    v2 as streamV2,    v2 as streamLatestVersion};  //上面代碼使用as關(guān)鍵字,重命名了函數(shù)v1和v2的對(duì)外接口。重命名后,v2可以用不同的名字輸出兩次。

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

// 報(bào)錯(cuò)  export 1;  // 報(bào)錯(cuò)  var m = 1;  export m;  //上面兩種寫法都會(huì)報(bào)錯(cuò),因?yàn)闆]有提供對(duì)外的接口。***種寫法直接輸出1,第二種寫法通過變量m,還是直接輸出1。1只是一個(gè)值,不是接口。  // 寫法一  export var m = 1;  // 寫法二  var m = 1;  export {m};  // 寫法三  var n = 1;  export {n as m};

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

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

function foo() {    export default 'bar' // SyntaxError  }  foo()

導(dǎo)入import

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

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

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

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

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

foo();  import { foo } from 'my_module';  //上面的代碼不會(huì)報(bào)錯(cuò),因?yàn)閕mport的執(zhí)行早于foo的調(diào)用。這種行為的本質(zhì)是,import命令是編譯階段執(zhí)行的,在代碼運(yùn)行之前。

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

// 報(bào)錯(cuò)  import { 'f' + 'oo' } from 'my_module';  // 報(bào)錯(cuò)  let module = 'my_module';  import { foo } from module;  // 報(bào)錯(cuò)  if (x === 1) {       import { foo } from 'module1';  }   else {      import { foo } from 'module2';  }

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

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

默認(rèn)導(dǎo)出(export default)

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

export default function(){              console.log("I am default Fn");  }  //使用export default關(guān)鍵字對(duì)外導(dǎo)出一個(gè)匿名函數(shù),導(dǎo)入這個(gè)模塊的時(shí)候,可以為這個(gè)匿名函數(shù)取任意的名字  //取任意名字均可  import sayDefault from "./module-B.js";  sayDefault();  //結(jié)果:I am default Fn

1、默認(rèn)輸出和正常輸出的比較

// ***組  export default function diff() {   // 輸出    // ...  }  import diff from 'diff';   // 輸入  // 第二組  export function diff() {   // 輸出    // ...  };  import {diff} from 'diff';   // 輸入  //上面代碼的兩組寫法,***組是使用export default時(shí),對(duì)應(yīng)的import語(yǔ)句不需要使用大括號(hào);第二組是不使用export default時(shí),對(duì)應(yīng)的import語(yǔ)句需要使用大括號(hào)。

export default命令用于指定模塊的默認(rèn)輸出。顯然,一個(gè)模塊只能有一個(gè)默認(rèn)輸出,因此export default命令只能使用一次。所以,import命令后面才不用加大括號(hào),因?yàn)橹豢赡軐?duì)應(yīng)一個(gè)方法。

2、因?yàn)閑xport default本質(zhì)是將該命令后面的值,賦給default變量以后再默認(rèn),所以直接將一個(gè)值寫在export default之后。

// 正確  export default 42;  // 報(bào)錯(cuò)  export 42;  //上面代碼中,后一句報(bào)錯(cuò)是因?yàn)闆]有指定對(duì)外的接口,而前一句指定外對(duì)接口為default。

3、如果想在一條import語(yǔ)句中,同時(shí)輸入默認(rèn)方法和其他變量,可以寫成下面這樣。

import _, { each } from 'lodash';  //對(duì)應(yīng)上面代碼的export語(yǔ)句如下  export default function (){      //...  }  export function each (obj, iterator, context){      //...  }

export 與 import 的復(fù)合寫法

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

export { foo, bar } from 'my_module';  // 等同于  import { foo, bar } from 'my_module';  export { foo, bar };  / 接口改名  export { foo as myFoo } from 'my_module';  // 整體輸出  export * from 'my_module';

注意事項(xiàng)

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 聲明的變量,對(duì)外都是只讀的。但是導(dǎo)出的是對(duì)象類型的值,就可修改。

  3. 導(dǎo)入不存在的變量,值為undefined。

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

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

//------ lib.js ------  export let counter = 3;  export function incCounter() {      counter++;  }  //------ main.js ------  import { counter, incCounter } from './lib';  // The imported value `counter` is live  console.log(counter);   // 3  incCounter();  console.log(counter);   // 4  // The imported value can&rsquo;t be changed  counter++;   // TypeError

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

//------ a.js ------  import {bar} from 'b';   // (1)  export function foo() {    bar();   // (2)  }  //------ b.js ------  import {foo} from 'a';   // (3)  export function bar() {    if (Math.random()) {      foo();   // (4)    }  }

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

實(shí)例

//---module-B.js文件---  //導(dǎo)出變量:name  export var name = "cfangxu";  moduleA模塊代碼:  //導(dǎo)入 模塊B的屬性 name      import { name } from "./module-B.js";     console.log(name) //打印結(jié)果:cfangxu

批量導(dǎo)出:

//屬性name  var name = "cfangxu";  //屬性age  var age  = 26;  //方法 say  var say = function(){              console.log("say hello");    }  //批量導(dǎo)出  export {name,age,say}

批量導(dǎo)入:

//導(dǎo)入 模塊B的屬性  import { name,age,say } from "./module-B.js";  console.log(name)  //打印結(jié)果:cfangxu  console.log(age)  //打印結(jié)果:26  say()  //打印結(jié)果:say hello

重命名導(dǎo)入變量:

import {name as myName} from './module-B.js';  console.log(myName)   //cfangxu

整體導(dǎo)入:

//使用*實(shí)現(xiàn)整體導(dǎo)入  import * as obj from "./module-B.js";  console.log(obj.name)  //結(jié)果:"cfangxu"  console.log(obj.age)  //結(jié)果:26  obj.say();  //結(jié)果:say hello

到此,關(guān)于“JavaScript模塊知識(shí)點(diǎn)有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI