久久精品五月,日韩不卡视频在线观看,国产精品videossex久久发布 ,久久av综合

站長資訊網
最全最豐富的資訊網站

JavaScript高級語法之模塊化(建議收藏)

本篇文章給大家帶來了關于JavaScript中模塊化的相關知識,希望對大家有幫助。

JavaScript高級語法之模塊化(建議收藏)

眾所周知,js在前端開發中的地位。學好它,真的很重要。

下面這篇文章,介紹一下模塊化。

什么是模塊化?

到底什么是模塊化、模塊化開發呢?

  • 事實上模塊化開發最終的目的是將程序劃分成一個個小的結構。

  • 這個結構中編寫屬于自己的邏輯代碼,有自己的作用域,不會影響到其他的結構。

  • 這個結構可以將自己希望暴露的變量、函數、對象等導出給其結構使用。

  • 也可以通過某種方式,導入另外結構中的變量、函數、對象等。

上面說提到的結構,就是模塊;按照這種結構劃分開發程序的過程,就是模塊化開發的過程。

模塊化的歷史

在網頁開發的早期,Brendan Eich開發JavaScript僅僅作為一種腳本語言,做一些簡單的表單驗證或動畫實現等,那個時候代碼還是很少的:

  • 這個時候我們只需要講JavaScript代碼寫到

  • 并沒有必要放到多個文件中來編寫。

但是隨著前端和JavaScript的快速發展,JavaScript代碼變得越來越復雜了:

  • ajax的出現,前后端開發分離,意味著后端返回數據后,我們需要通過JavaScript進行前端頁面的渲染。

  • SPA的出現,前端頁面變得更加復雜:包括前端路由、狀態管理等等一系列復雜的需求需要通過JavaScript來實現。

  • 包括Node的實現,JavaScript編寫復雜的后端程序,沒有模塊化是致命的硬傷。

所以,模塊化已經是JavaScript一個非常迫切的需求。所以ES6(2015)才推出了自己的模塊化方案。

在此之前,為了讓JavaScript支持模塊化,涌現出了很多不同的模塊化規范:AMD、CMD、CommonJS等。

沒有模塊化帶來的問題

比如命名沖突的問題。

通過立即函數調用表達式(IIFE)來解決上面的問題。因為函數有自己的作用域,不會造成不同文件命名沖突。

    // a.js     var moduleA = (function() {       var name = "llm"       var age = 22       var isFlag = true       return {         name: name,         isFlag: isFlag       }     })()
    // b.js     var moduleB = (function() {       var name = "zh"       var isFlag = false       return {         name: name,         isFlag: isFlag       }     })()
    // 使用     moduleA.name     moduleB.name

但是,我們其實帶來了新的問題:

  • 我必須記得每一個模塊中返回對象的命名,才能在其他模塊使用過程中正確的使用。

  • 代碼寫起來混亂不堪,每個文件中的代碼都需要包裹在一個匿名函數中來編寫。

  • 在沒有合適的規范情況下,每個人、每個公司都可能會任意命名、甚至出現模塊名稱相同的情況。

所以,我們會發現,雖然實現了模塊化,但是我們的實現過于簡單,并且是沒有規范的。

我們需要制定一定的規范來約束每個人都按照這個規范去編寫模塊化的代碼。這個規范中應該包括核心功能:模塊本身可以導出暴露的屬性,模塊又可以導入自己需要的屬性。JavaScript社區為了解決上面的問題,涌現出一系列好用的規范,接下來我們就學習具有代表性的一些規范。

CommonJS規范和Node

我們需要知道CommonJS是一個規范,最初提出來是在瀏覽器以外的地方使用,并且當時被命名為ServerJS,后來為了體現它的廣泛性,修改為CommonJS,平時我們也會簡稱為CJS。

  • Node是CommonJS在服務器端一個具有代表性的實現。

  • Browserify是CommonJS在瀏覽器中的一種實現。

  • webpack打包工具具備對CommonJS的支持和轉換。

所以,Node中對CommonJS進行了支持和實現,讓我們在開發node的過程中可以方便的進行模塊化開發。

  • 在Node中每一個js文件都是一個單獨的模塊。

  • 這個模塊中包括CommonJS規范的核心變量:exports、module.exports、require。

  • 我們可以使用這些變量來方便的進行模塊化開發。

前面我們提到過模塊化的核心是導出和導入,Node中對其進行了實現:

  • exports和module.exports可以負責對模塊中的內容進行導出。

  • require函數可以幫助我們導入其他模塊(自定義模塊、系統模塊、第三方庫模塊)中的內容。

Node.js模塊化

Node中對CommonJS進行了支持和實現,讓我們在開發node的過程中可以方便的進行模塊化開發:

  • 在Node中每一個js文件都是一個單獨的模塊。

  • 這個模塊中包括CommonJS規范的核心變量:exports、module.exports、require。

  • exports和module.exports可以負責對模塊中的內容進行導出。

  • require函數可以幫助我們導入其他模塊(自定義模塊、系統模塊、第三方庫模塊)中的內容。

下面我們將來介紹exports、module.exports、require的使用。

  • exports是一個對象,我們可以在這個對象中添加很多個屬性,添加的屬性會導出。

  • 我們也可以通過module.exports直接導出一個對象。

  • 我們通過require()函數導入一個文件。并且該文件導出的變量。

下面來詳細介紹一個module.exports。

CommonJS中是沒有module.exports的概念的。

但是為了實現模塊的導出,Node中使用的是Module的類,每一個模塊都是Module的一個實例,也就是module。

所以在Node中真正用于導出的其實根本不是exports,而是module.exports。

因為module才是導出的真正實現者。

并且內部將exports賦值給module.exports。

該方式的導入導出有以下特點:

Node中的文件都運行在一個函數中。可以通過打印console.log(arguments.callee + "")來驗證。

JavaScript高級語法之模塊化(建議收藏)

導入導出是值的引用,如果導出的是一個基本數據類型值,那么導出文件改變該值,然后導入文件該變量的值也不會變。

    // a.js     const obj = require("./b.js")     console.log(obj)     setTimeout(() => {       obj.name = "llm"     }, 1000)
    // b.js     const info = {       name: "zh",       age: 22,       foo: function() {         console.log("foo函數~")       }     }     setTimeout(() => {       console.log(info.name) // llm     }, 2000)     module.exports = info

他是通過require 函數來導入的,只有在執行js代碼才會知道模塊的依賴關系。

代碼是同步執行的。

模塊多次引入,只會加載一次。每個module內部會存在一個loaded來確定是否被加載過。

代碼循環引入的時候,深度優先來加載模塊。然后再廣度優先。

下面來詳細介紹一個require的導入細節

我們現在已經知道,require是一個函數,可以幫助我們引入一個文件(模塊)中導出的對象。

那么,require的查找規則是怎么樣的呢?

詳細查找規則,請訪問這里

這里我總結比較常見的查找規則:導入格式如下:require(X)

JavaScript高級語法之模塊化(建議收藏)

模塊的加載細節

模塊在被第一次引入時,模塊中的js代碼會被運行一次

模塊被多次引入時,會緩存,最終只加載(運行)一次

為什么只會加載運行一次呢?

這是因為每個模塊對象module都有一個屬性:loaded。為false表示還沒有加載,為true表示已經加載。

如果有循環引入,那么加載順序是什么?

JavaScript高級語法之模塊化(建議收藏)

如上圖,Node采用的是深度優先算法:main -> aaa -> ccc -> ddd -> eee ->bbb

CommonJS規范缺點

CommonJS加載模塊是同步的:

同步的意味著只有等到對應的模塊加載完畢,當前模塊中的內容才能被運行。

這個在服務器不會有什么問題,因為服務器加載的js文件都是本地文件,加載速度非常快。

如果將它應用于瀏覽器呢?

瀏覽器加載js文件需要先從服務器將文件下載下來,之后再加載運行。

那么采用同步的就意味著后續的js代碼都無法正常運行,即使是一些簡單的DOM操作。所以在瀏覽器中,我們通常不使用CommonJS規范。當然在webpack中使用CommonJS是另外一回事。因為它會將我們的代碼轉成瀏覽器可以直接執行的代碼。

AMD規范

在早期為了可以在瀏覽器中使用模塊化,通常會采用AMD或CMD。但是目前一方面現代的瀏覽器已經支持ES Modules,另一方面借助于webpack等工具可以實現對CommonJS或者ES Module代碼的轉換。AMD和CMD已經使用非常少了,所以這里我們進行簡單的演練。

AMD主要是應用于瀏覽器的一種模塊化規范:

AMD是Asynchronous Module Definition(異步模塊定義)的縮寫。它采用的是異步加載模塊。

我們提到過,規范只是定義代碼的應該如何去編寫,只有有了具體的實現才能被應用。

AMD實現的比較常用的庫是require.js和curl.js。

require.js的使用

定義HTML的script標簽引入require.js和定義入口文件。data-main屬性的作用是在加載完src的文件后會加載執行該文件

// index.html  <script src="./require.js" data-main="./index.js"></script>
    //main.js     require.config({       baseUrl: '', // 默認是main.js的文件夾路徑       paths: {         foo: "./foo"       }     })     require(["foo"], function(foo) {       console.log("main:", foo)     })
    // foo.js     define(function() {       const name = "zh"       const age = 22       function sum(num1, num2) {         return num1 + num2       }       return {         name,         age,         sum       }     })

CMD規范

CMD規范也是應用于瀏覽器的一種模塊化規范:

CMD 是Common Module Definition(通用模塊定義)的縮寫。它也采用了異步加載模塊,但是它將CommonJS的優點吸收了過來。

AMD實現的比較常用的庫是SeaJS。

SeaJS的使用

引入sea.js和使用主入口文件。

    // index.html       <script src="./sea.js"></script>       <script>         seajs.use("./main.js")       </script>
    //main.js     define(function(require, exports, module) {       const foo = require("./foo")       console.log("main:", foo)     })
    // foo.js    define(function(require, exports, module) {       const name = "zh"       const age = 22       function sum(num1, num2) {         return num1 + num2       }       // exports.name = name       // exports.age = age       module.exports = {         name,         age,         sum       }     });

ES Module

ES Module和CommonJS的模塊化有一些不同之處:

  • 一方面它使用了import和export關鍵字來實現模塊化。

  • 另一方面它采用編譯期的靜態分析,并且也加入了動態引用的方式。

  • export負責將模塊內的內容導出。

  • import負責從其他模塊導入內容。

  • 采用ES Module將自動采用嚴格模式:use strict。

基本使用

    // index.html     <script src="./main.js" type="module"></script>
    // foo.js     let obj = {       name: "zh",       age: 22     }          export default sum
    // main.js     import foo from './foo.js'     console.log(foo)

在html文件加載入口文件的時候,需要指定type為module。

在打開html文件時,需要開啟本地服務,而不能直接打開運行在瀏覽器上。

這個在MDN上面有給出解釋:

你需要注意本地測試 — 如果你通過本地加載Html 文件 (比如一個 file:// 路徑的文件), 你將會遇到 CORS 錯誤,因為Javascript 模塊安全性需要。

你需要通過一個服務器來測試。

exports關鍵字

export關鍵字將一個模塊中的變量、函數、類等導出。

我們希望將其他中內容全部導出,它可以有如下的方式:

方式一:在語句聲明的前面直接加上export關鍵字。

    export const name = "zh"     export const age = 22

方式二:將所有需要導出的標識符,放到export后面的 {} 中。注意:這里的 {}里面不是ES6的對象字面量的增強寫法,{}也不是表示一個對象的。所以: export {name: name},是錯誤的寫法。

    const name = "zh"     const age = 22     function foo() {       console.log("foo function")     }     export {       name,       age,       foo     }

方式三:導出時給標識符起一個別名。(基本沒用,一般在導入文件中起別名)。然后在導入文件中就只能使用別名來獲取。

    export {       name as fName,       age as fAge,       foo as fFoo     }

import關鍵字

import關鍵字負責從另外一個模塊中導入內容。

導入內容的方式也有多種:

方式一:import {標識符列表} from '模塊'。注意:這里的{}也不是一個對象,里面只是存放導入的標識符列表內容。

    import { name, age } from "./foo.js"

方式二:導入時給標識符起別名。

    import { name as fName, age as fAge } from './foo.js'

方式三:通過 * 將模塊功能放到一個模塊功能對象(a module object)上。然后通過起別名來使用。

    import * as foo from './foo.js'

export和import結合使用

表示導入導出。

    import { add, sub } from './math.js'     import {otherProperty} from './other.js'     export {       add,       sub,       otherProperty     }

等價于

    // 導入的所有文件會統一被導出     export { add, sub } from './math.js'     export {otherProperty} from './other.js'

等價于

    export * from './math.js'     export * from './other.js'

為什么要這樣做呢?

在開發和封裝一個功能庫時,通常我們希望將暴露的所有接口放到一個文件中。 這樣方便指定統一的接口規范,也方便閱讀。這個時候,我們就可以使用export和import結合使用。

default用法

前面我們學習的導出功能都是有名字的導出(named exports):

在導出export時指定了名字。

在導入import時需要知道具體的名字。

還有一種導出叫做默認導出(default export)

    // foo.js     const name = "zh"     cconst age = 22     export {       name,       // 或者這樣的默認導出       // age as default     }     export default age
    // 導入語句: 導入的默認的導出     import foo, {name} from './foo.js'     console.log(foo, name) // 22 zh

默認導出export時可以不需要指定名字。

在導入時不需要使用 {},并且可以自己來指定名字。

它也方便我們和現有的CommonJS等規范相互操作。

注意:在一個模塊中,只能有一個默認導出(default export)。

import函數

通過import加載一個模塊,是不可以在其放到邏輯代碼中的,比如:

    if(true) {         import foo from './foo.js'     }

為什么會出現這個情況呢?

這是因為ES Module在被JS引擎解析時,就必須知道它的依賴關系。

由于這個時候js代碼沒有任何的運行,所以無法在進行類似于if判斷中根據代碼的執行情況。

但是某些情況下,我們確確實實希望動態的來加載某一個模塊:

如果根據不同的條件,動態來選擇加載模塊的路徑。

這個時候我們需要使用 import() 函數來動態加載。import函數返回的結果是一個Promise。

    import("./foo.js").then(res => {       console.log("res:", res.name)     })

es11新增了一個屬性。meta屬性本身也是一個對象: { url: "當前模塊所在的路徑" }

    console.log(import.meta)

ES Module的解析流程

ES Module是如何被瀏覽器解析并且讓模塊之間可以相互引用的呢?

ES Module的解析過程可以劃分為三個階段:

階段一:構建(Construction),根據地址查找js文件,并且下載,將其解析成模塊記錄(Module Record)。

階段二:實例化(Instantiation),對模塊記錄進行實例化,并且分配內存空間,解析模塊的導入和導出語句,把模塊指向對應的內存地址。

階段三:運行(Evaluation),運行代碼,計算值,并且將值填充到內存地址中。

JavaScript高級語法之模塊化(建議收藏)

階段一:

JavaScript高級語法之模塊化(建議收藏)

階段二和三:

JavaScript高級語法之模塊化(建議收藏)

所以,從上面可以看出在導出文件中,修改變量的值會影響到導入文件中的值。而且導入文件被限制修改導出文件的值。

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
久久精品五月,日韩不卡视频在线观看,国产精品videossex久久发布 ,久久av综合
一区二区国产在线| 日本精品一区二区三区在线观看视频| 亚洲欧美高清| 亚洲午夜天堂| 91精品丝袜国产高跟在线| 欧美日韩国产一区二区三区不卡 | 欧美在线资源| 在线看片不卡| 狠狠色综合网| 亚洲免费成人| 石原莉奈在线亚洲二区| 水蜜桃久久夜色精品一区的特点| 美女毛片一区二区三区四区| 99视频精品全国免费| 日韩和的一区二在线| 欧美日韩国产观看视频| 在线一区视频观看| 日韩综合精品| 欧美亚洲国产精品久久| 亚洲午夜av| 久久高清一区| 日本亚洲不卡| 国产精品主播| 美女性感视频久久| 韩国一区二区三区视频| 精品日韩一区| 日本一区二区免费高清| 桃色av一区二区| 久久精品二区三区| 国产精品美女久久久| 日韩三级视频| 久久超级碰碰| 欧美激情日韩| 久久久久久夜| 日韩不卡在线| 妖精视频成人观看www| 亚洲三级视频| 国产精品一国产精品k频道56| 欧美激情视频一区二区三区免费 | 日韩a一区二区| 日韩黄色大片| 日韩中文字幕区一区有砖一区| 国产精品婷婷| 日韩精品免费视频一区二区三区| 麻豆国产91在线播放| 少妇精品导航| 蜜桃视频在线观看一区二区| 国产欧美日韩精品一区二区三区| av免费不卡国产观看| 怡红院精品视频在线观看极品| 中文字幕一区二区三区日韩精品| 国产精品一区二区精品视频观看| 久久久精品网| 亚洲影院天堂中文av色| 国产精品羞羞答答在线观看| 精品捆绑调教一区二区三区| 蜜桃视频一区二区| 国产激情欧美| 不卡一区综合视频| 国产精品一区二区美女视频免费看| 91精品国产91久久久久久黑人| 亚洲综合福利| 中文在线免费视频| 亚洲美女91| 国产日韩视频在线| 另类中文字幕国产精品| 亚洲一级大片| 日韩中文欧美| 日韩av网站免费在线| 亚洲黄色网址| 欧美亚洲免费| 狠狠色综合网| 国产一区二区三区四区五区| 欧美网站在线| 久久精品一区二区国产| 在线亚洲精品| av在线资源| 少妇精品久久久一区二区三区| 中文字幕在线免费观看视频| 在线免费观看亚洲| 麻豆成人av在线| 国产毛片一区| 激情视频网站在线播放色| 日韩av中文字幕一区二区| 人人草在线视频| 日本欧美一区二区| 国产专区一区| 久久一区欧美| 日韩在线电影| 欧美日韩国产欧| 精品久久亚洲| 青青草国产精品亚洲专区无| 国产国产精品| 麻豆国产91在线播放| 综合亚洲色图| 亚洲视频综合| 精品一二三区| 国产色噜噜噜91在线精品| 亚洲一区中文| 国产精品久久亚洲不卡| 日韩有吗在线观看| 99综合视频| 激情丁香综合| 精品午夜av| 国产精品调教视频| 亚洲人成毛片在线播放女女| 在线日韩视频| 久久国产毛片| 一区二区精品伦理...| 欧美国产另类| 国产调教精品| 日韩在线成人| 午夜久久av| 亚洲三区欧美一区国产二区| 欧美日韩国产一区精品一区| 三级精品视频| 日韩理论视频| 国产99在线| 久久久久久色| 亚洲精品成人一区| 中文字幕av一区二区三区人| 免费在线观看日韩欧美| 在线视频亚洲| 欧美一区=区| 国产一区二区精品| 日韩视频中文| 国产综合亚洲精品一区二| 久久在线电影| 日本高清不卡一区二区三区视频| 麻豆视频一区二区| 欧美国产另类| 国产不卡一区| 精品国产午夜| 国产999精品在线观看| 欧美激情视频一区二区三区免费| 欧美aaaaaa午夜精品| 久久av免费| 国产一区二区视频在线看| 成人精品视频| 日韩综合在线| 日韩国产欧美| 国产精品亚洲一区二区三区在线观看| 成人综合一区| 日本综合字幕| av在线最新| 久久精品播放| 噜噜噜躁狠狠躁狠狠精品视频| 蜜桃久久久久久| 日韩av黄色在线| 欧美xxxx性| 99精品一区| 丝袜诱惑制服诱惑色一区在线观看| 蜜桃久久精品一区二区| 日韩欧美激情电影| 免费精品一区| 日韩高清中文字幕一区二区| 国产精品88久久久久久| 亚洲精品四区| 精品久久福利| 国产成人精品三级高清久久91| 亚洲香蕉网站| 日韩国产在线观看| 麻豆视频在线看| 免费在线观看成人| 国产精品入口久久| 国产精品xx| 亚洲免费网址| 欧美日韩1区2区3区| 国产盗摄——sm在线视频| av亚洲免费| 国产精品一区二区三区美女 | 欧美精品第一区| 九九色在线视频| 免费成人av在线播放| 91精品丝袜国产高跟在线| 最近高清中文在线字幕在线观看1| 亚洲成人精选| 日韩精品一区二区三区中文在线| 精品国产中文字幕第一页| 国产aⅴ精品一区二区三区久久 | 欧美一级专区| 亚洲精品黄色| www在线观看黄色| 免费人成网站在线观看欧美高清| 亚洲精品日本| 亚洲日本免费电影| 欧美综合精品| 国产精品欧美在线观看| 日韩毛片在线| 91欧美在线| 日韩av在线播放网址| 国产欧美日韩在线观看视频| 国产成人免费精品| 国产午夜久久| 日韩一级不卡| 日韩二区在线观看| 视频一区国产视频| 午夜亚洲一区| 中文字幕一区日韩精品| 国产一区二区三区视频在线|