require | import |
---|---|
動態評估 | 靜態評估 |
再運行時報錯 | 再解析時報錯 |
不是關鍵詞 | 是關鍵詞 |
dep.jsnode
module.exports = { foo: function () {}, bar: 'a' }
app.js緩存
var dep = require('dep') console.log(dep.bar) dep.foo()
dep.jsapp
export foo function(){} export const bar = 'a'
app.js模塊化
import { foo, bar } from 'dep' console.log(bar) foo()
使用require的時候,其實會將module的代碼進行包裝,變成以下樣子的代碼:ui
function (exports, require, module, __filename, __dirname) { const m = 1; module.exports.m = m; }
而後在執行這個方法的時候,咱們能夠傳入:lua
const module = { exports: {} } const require = function(){/* ...some module load code here */} // __filename, __dirname是require的時候提供的路徑分析出來的 fun(module.exports, require, module, __filename, __dirname)
執行完成以後,就能經過module拿到方法中向外拋出的變量了。code
因此咱們能夠看到,module、require、exports都不是全局變量,而是專門爲這個模塊使用的局部變量。內存
require的時候真正作的事情以下:io
簡單來講就是根據require調用時傳入的路徑,首先要拿到真正的絕對路徑(是相對目錄的,仍是node_modules下面的等等),而後讀入代碼,包裝成上面顯示的樣子,而後傳給vm進行評估執行,獲得結果,最後進行緩存。console
因此,在模塊代碼執行完以前,node根本不知道這個模塊到底export出了什麼東西,這也是和ESM最大的區別,由於ESM是基於關鍵字的模塊化,是能夠在解析的過程當中就知道導出了什麼。
在解析ESM模塊的時候,在把代碼傳給VM執行以前,就能夠獲得一個叫作Module Record
的內部結構,他保存了模塊倒出的內容的列表,在你import {f} from f
的時候,他其實在你引用的地方和倒出的地方的f
之間創建了鏈接,即它們是指向同一內存的,即使是原始數據類型,你修改模塊中的指也會致使引用處的變化。啥意思呢?
// dep.js export let a = 1 setTimeout(() => a += 1, 500) // app.js import { a } from 'dep' setTimeout(function () { console.log(a) }, 1000)
輸出的會是2,可是你用require,CommonJs模塊來作,就會是1,由於CommonJs是普通的值傳遞或者引用傳遞
這就是require和import最大的區別