commonjs 中有幾個特別的變量,module
、exports
、require
、global
、__filename
、__dirname
。javascript
在一個 js 文件中輸入下面這行,你會發現能夠打印出 5 個 argument。html
console.log(arguments);
複製代碼
它們分別對應的就是:exports
、require
、module
、__filename
、__dirname
。java
commonjs 的導出機制比較簡單,只有 module.exports
和 exports
。須要注意的是,他們指向的都是同一個對象。若是對 module.exports
賦值,則經過 exports.xxx
導出的全部變量都會失效,它所指向的對象和 module.exports
指向的不是同一個對象,而導出時是以 module.exports
指向的對象爲準。node
require
是動態導入模塊的,只有執行到 require
語句的時候纔會導入模塊,它導入的是模塊的一個拷貝。模塊導入一次以後就會被緩存起來,後面再導入時都是使用的已緩存的版本。react
舉個簡單例子,下面代碼會先打印 index
再打印 a
。若是把 require
換成 import
,則會先打印 a
再打印 index
。webpack
// a.js
console.log('a')
// index.js
console.log('index')
require('./a')
複製代碼
node index.js
複製代碼
ESM 全稱叫 ECMA Script Modules,是在 ES6 語言層面提出的一種模塊化標準。es6
ES6 中主要有 import
、export
兩個關鍵詞。要注意他們是語法層面的關鍵詞,因此不能使用 console.log(import)
這種方式來打印。而 commonjs 中的變量都是能夠打印的。web
常見的導入導出:瀏覽器
// 導入
import React from 'react'
import * as React from 'react'
import { Component } from 'react'
import {default as a} from 'react'
import {Button as Btn} from 'antd'
import 'index.less'
export default 1
export const name = 'lxfriday'
export { age }
export {name as nickname}
export { foo } from './foo-bar'
export * from './foo-bar'
複製代碼
ES6 模塊在編譯階段就能夠分析出導出的結果,同時它導出的是值的引用。緩存
下面是一個例子:
ESM 模塊語法能夠在比較新的瀏覽器中使用,它的使用方式像下面的代碼,須要使用 type = module
區分。瀏覽器對 script 標籤默認的 type 是 application/javascript
。
瀏覽器對 module 標籤的腳本是異步加載並執行的,模塊的加載不會阻塞瀏覽器渲染,等到整個頁面渲染完成以後,module 纔會執行,這種加載執行策略和 defer
屬性相同(async
是異步加載完就會當即執行,會中斷瀏覽器渲染)。
<script type="module" src="./index.js">xxx</script>
複製代碼
下面是一個例子
// cc.js
export default { aa: "aaa", bb: "bbb" };
var value = 100;
// index.js
import cc from "./cc.js";
console.log("module in browser", cc);
console.log(value);
複製代碼
<body>
hello
<script src="./index.js" type="module"></script>
</body>
複製代碼
執行結果
能夠看到,模塊正常導入並打印了,可是在 cc.js
中定義的變量 value
,在 index.js
中獲取不到,這說明 type=module
有做用域限制。
當它們混合使用的時候很容易產生混亂,在導入的時候,推薦把 import
語句都放在 require
語句前面。在不一樣時期,因爲語法標準不完善,導入導出都存在差別,下面例子基於 webpack 4.41.2
測試得出。
看看下面的例子:
// 對 import xx from './aa.js'
module.exports = xx
// 等同於
export default xx
複製代碼
// 對 import { aa, bb } from './cc.js' 或者 const { aa, bb } = require('./cc.js')
module.exports = { aa: 'aaa', bb: 'bbb' }
// 等同於
exports.aa = 'aaa'
exports.bb = 'bbb'
// 等同於
export const aa = 'aaa'
export const bb = 'bbb'
複製代碼
下面兩個例子要多加註意
// cc.js
module.exports = { aa: 'aaa', bb: 'bbb' }
// index.js
import cc from './cc.js'
import * as dd from './cc.js'
console.log(cc)
console.log(dd)
// 打印的結果相同,爲 {aa: "aaa", bb: "bbb"}
複製代碼
// cc.js
export default { aa: 'aaa', bb: 'bbb' }
// index.js
import cc from './cc.js'
import * as dd from './cc.js'
console.log(cc)
console.log(dd)
// 打印的結果不一樣
// cc => {aa: "aaa", bb: "bbb"}
// dd => Module {default: {…}, __esModule: true, Symbol(Symbol.toStringTag): "Module"}
複製代碼
能夠看出,使用 export default
這種 ES6 方式導出的結果,import * as
能夠準確的實現自身的語義,把模塊裏面全部導出的都掛載模塊對象中。
ES6 模塊中,import a from './xx'
是 import { default as a } from './xx'
的簡寫。表示把 xx
模塊中用 export default
導出的變量導入。
參考
今天的文章就到這裏,感謝閱讀~
歡迎你們關注個人掘金和公衆號