瀏覽器端模塊化方式es module詳解

在es module出現以前還有社區推出amd和cmd的規範,這二者還有其特定的編寫方式,使用起來不算很方便。es module被官方推出來就成爲了瀏覽器端實現模塊化的一個很好的方案。javascript

想要在瀏覽器端使用 es module ,首先在 html 當中引入 js 文件的時候,就須要將script標籤中的type設置爲modulehtml

index.html  
<script src="b.js" type="module"></script>

這樣瀏覽器才能執行使用es module的js文件,定義以後就能夠在對應的js文件中使用模塊化的方式來編寫文件,導出和導入的方式有幾種,但都是相同的關鍵字,export 與 import,一塊兒來看看能夠如何定義導入導出。java

第一種,直接導出定義的變量,這種方式導出的內容互不關聯,適用於導出本身定義的常量,redux中定義action就常用這種導出node

a.js
export const name = 'alice'
export const age = 16

b.js
import { name, age } from "./a.js";
console.log(name, age) // alice 16

第二種,先定義變量,再使用 export 一塊兒導出,導入方式可使用上面的方式,也能夠經過一個 * 來將全部的導出內容定義爲一個對象,從對象中再去取值 ,redux中定義的reducer、action在 index.js 中導出會常用這種方式json

a.js
const name = 'alice'
const age = 16
export { name, age }

b.js
import * as obj from "./a.js";
console.log(obj.name, obj.age) // alice 16

第三種,給導出的變量取別名,導入的變量一樣能夠取別名,當名字發生衝突時、導出變量名太長時,均可以取個別名,取完別名以後,原先的名字就不可用了redux

a.js
const name = 'alice'
const age = 16

export { name as myName, age as myAge }

b.js
import { myName as aliceName, myAge } from "./a.js";

console.log(aliceName, myAge)  // alice 16

第四種,默認導出,默認導出在一個js文件中只容許存在一個,默認導出能夠不用定義變量名,在導入的時候能夠隨意起名,而且導入的時候不須要加 {} ,這樣的定義方式在編寫redux中的reducer函數時很常見segmentfault

a.js
export default function(){
    return 'hello world'
}

b.js
import foo from './a.js'

console.log(foo()) // hello world

第五種,合併導出,在b.js文件導入a.js文件中導出的內容,b.js文件不對導入的內容作任何操做,直接導出,最後由index.js導入b.js並進行處理promise

a.js
export const name = 'alice'

b.js
export { name } from './a.js'

index.js
import { name } from './b.js'

console.log(name) // alice

以上是es module的具體的語法表現,導入導出的方式有不少,能夠根據具體須要的場景進行判斷和使用,另外,es module 還有一些特色。瀏覽器

一、異步加載,當script標籤中定義 type="module"以後,至關於給js標籤加上了 async 的標識,表明異步加載資源,不會阻塞其它內容的執行,按照以下代碼,打印的hi有多是在引入的index.js文件以前,要根據 index.js 的執行速度來判斷。異步

<script src="index.js" type="module"></script>
<script type="text/javascript">
    console.log('hi')
</script>

二、編譯時解析,簡單來講javascript的執行過程須要將原代碼編譯成抽象語法樹,運行的時候再轉成機器可識別的語言,在編譯階段解析數據,並不知道該不應加載此js文件,只有等到文件運行時,才知道文件裏具體邏輯的執行過程,因此不可以在編譯時解析的模塊化方式出現相似條件判斷,動態引入等代碼

const flag = true
if(flag){
    import xxx from './a.js'
 }

若是真的須要根據一些條件才執行代碼,能夠經過 require 函數來動態的引入,require函數執行完是一個promise對象,能夠經過then方法來獲取所須要的數據

const flag = true

if(flag){
  import('./b.js')
  .then(({name})=>{
    console.log(name)
  })
}

三、export 關鍵字後面跟的大括號並非表明對象,在對象中也沒有經過 as 取別名這樣的方式,若是咱們嘗試如下把它當成對象來導出,必定是會報錯的

let name = 'alice'
export {
    name: name
}

export 導出的 name 就對應着 name 這個變量,若是修改 name 的值,export 導出的內容會發生變化,import 導入的內容也會發生變化

a.js
let name = 'kiki', age = 18

setTimeout(()=>{
  name = '嘻嘻嘻'
}, 1000)

export {
  name,
    age
}

b.js
import { name, age } from './a.js'

console.log(name)

setTimeout(()=>{
  console.log(name)
},2000)

// 依次打印 kiki 嘻嘻嘻

export 導出的內容有一個模塊環境記錄,用來記錄導出時更改的變量,當變量更改時,使用新的變量值替換舊變量值

可是不能夠反向的修改,由於 import 導入的內容是一個經過 const 定義的常量,常量是不能夠被修改的,如下操做是不可行的

import { name } from './a.js'
name = '哈哈哈哈'

通常而言,咱們都是在瀏覽器端使用 es module,若是想要在 node 端編寫es module代碼,能夠有兩種方式,一種是在 package.json 中配置 type:module,另外一種是直接把js文件的後綴名爲改成 .mjs

node端經常使用的模塊化方式是 commonjs,一樣是模塊化,那麼 es module 和 commonjs 之間是否能互相調用呢,看看以下代碼

a.mjs
const name = 'alice'
const age = 18

export {
  name,
  age
}

b.js
const a = require('./a.mjs')

console.log(a)

以上代碼執行會報錯 Must use import to load ES Module,而以下的方式在高版本的nodejs中是能夠的

a.js
const name = 'alice'
const age = 18

module.exports = {
  name,
  age
}

b.js
import b from './b.js'

console.log(b) // { name: 'alice', age: 18 }

以上就是瀏覽器端模塊方式es module的概念與用法,模塊化可以更好的將代碼分塊並複用,nodejs端也有經常使用實現模塊化的方式,即commonjs,若是不熟悉能夠看看這篇文章 -> nodejs端模塊化方式comomjs詳解

相關文章
相關標籤/搜索