網(wǎng)站首頁 編程語言 正文
1. 介紹
require/exports 和 import/exoprt 屬于兩種不同的模塊化規(guī)范. require/exports 遵循 CommonJS 模塊規(guī)范, 而 import/exoprt 遵循 ES6 模塊規(guī)范.
那么怎么理解模塊化規(guī)范?
模塊化規(guī)范: 即為javascript提供模塊編寫 模塊依賴 模塊運行的方案
CommonJS模塊規(guī)范
- 出現(xiàn)的時間在2010年左右, 屬于是野生規(guī)范, 即 JavaScript 社區(qū)中的開發(fā)者自己草擬的規(guī)則,得到了大家的承認或者廣泛的應(yīng)用
- nodejs 使用的就是 CommonJS 規(guī)范
ES6模塊規(guī)范
- 出現(xiàn)的時間是在2015年, 屬于是名門正派, 是 TC39 制定的新的 ECMAScript 版本, 即ES6(2015)包含進來的
2. ES model 和 CommonJS model 使用(node環(huán)境)
2.1 CommonJS
// a.js
let a = 1
let b = 1
function add(a, b) {
return a + b
}
// 導(dǎo)出1
module.exports = {
a,
b,
add
}
// 導(dǎo)出2
// exports.a = a
// exports.b = b
// exports.add = add
// index.js
// 導(dǎo)入
let obj = require("./a")
console.log(obj); // { a: 1, b: 1, add: [Function: add] }
console.log(obj.a); // 1
console.log(obj.b); // 2
console.log(obj.add); // add: [Function: add]
2.2 ES6
注意: CommonJS 模塊是 Node.js 專用的,與 ES6 模塊不兼容. 如果想要在node環(huán)境下執(zhí)行import/export, 需要采用xxx.mjs的后綴名
// a.mjs
// 導(dǎo)出方式1
export const aaa = 'aaa'
export const bbb = 'bbb'
export const ccc = 'ccc'
const str = 'hello es module'
// 導(dǎo)出方式2
export default str
// index.mjs
// 引入方式1
import { aaa , bbb, ccc } from "./a.mjs"
console.log(aaa); // 'aaa'
console.log(ccc); // 'bbb'
console.log(str); // 'ccc'
// 引入方式2 對應(yīng)導(dǎo)出方式2
// import str from "./a.mjs"
// console.log(str); // hello es module
// 引入方式3 1 + 2結(jié)合
// import str, { aaa , bbb, ccc } from "./a.mjs"
// console.log(str);
// console.log(aaa);
// console.log(ccc);
// console.log(str);
// 引入方式4 as別名
// import { aaa as ddd } from "./a.mjs"
// console.log(ddd); // 'aaa'
// 引入方式5 * as
// import * as obj from "./a.mjs"
// console.log(obj); // { aaa: 'aaa', bbb: 'bbb', ccc: 'ccc', default: 'hello es module' }
3. ES model 和 CommonJS model 區(qū)別
3-1. ES6 模塊輸出的是值的引用,CommonJS 模塊輸出的是值的拷貝。
3-1-1. ES6 ? 值的引用
解釋一下, CommonJS 是值的拷貝(淺拷貝),怎么理解, 可以理解為 ? 輸出一個值, 如果模塊內(nèi)部這個值改變,輸出的值不會受影響, 看下面代碼
// a.js
var num = 1
function add() {
num++
}
module.exports = {
num,
add,
}
// index.js
// 導(dǎo)入
let obj = require("./a")
console.log(obj.num); // 1 輸出一個值
obj.add() // 模塊內(nèi)部這個值改變
console.log(obj.num); // 1 輸出的值不受影響
可以看到當我執(zhí)行obj.add()之后,在打印obj.num,發(fā)現(xiàn)這個值并沒有改變. 為什么呢? 這是因為mod.counter是一個原始類型的值,會被緩存。除非寫成一個函數(shù),才能得到內(nèi)部變動后的值。
3-1-2. CommonJS ? 值的拷貝
ES module 運行機制和 Commonjs 不一樣, 預(yù)編譯的時候如果讀到了 import, 那么就會生成一個只讀的引用, 再根據(jù)這個引用去對應(yīng)模塊取值. 意思就是原始值變了, import加載的值也會跟這邊, 因此,ES6 模塊是動態(tài)引用,并且不會緩存值,模塊里面的變量綁定其所在的模塊
// a.mjs
export var num = 1
export function add() {
num++
}
// index.mjs
import { num , add } from "./a.mjs"
console.log(num); // 1 輸出一個值
add() // 模塊內(nèi)部這個值改變
console.log(num); // 2 輸出的值受影響
3-2. CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。
因為 CommonJS 加載的是一個對象(即module.exports屬性),該對象只有在腳本運行完才會生成。而 ES6 模塊不是對象,它的對外接口只是一種靜態(tài)定義,在代碼靜態(tài)解析階段就會生成
// commonjs
let _fs = require('fs')
let stat = _fs.stat
let exists = _fs.exists
let readfile = _fs.readfile
// 上面需要等待整體加載玩fs模塊,生成一個_fs模塊,然后再從對象上讀取三個方法.這種加載稱為運行時加載
// es
import { stat, exists, readfile } from 'fs'
// 上面直接沖fs模塊中加載3個方法,其他方法不加載,這種加載稱為編譯時加載. 即es6可以在編譯的時候就完成模塊加載
3-3. CommonJS 模塊的require()是同步加載模塊,ES6 模塊的import命令是異步加載,有一個獨立的模塊依賴的解析階段。
- 同步: 會阻塞后續(xù)代碼
- 異步: 不會阻塞后續(xù)代碼
commonjs
// index.js
const A = require('./a')
console.log('index.js執(zhí)行');
// a.js
console.log('a.js執(zhí)行')
const foo = () => {
console.log(require('./b').c);
}
foo()
module.exports = {
foo
}
// b.js
console.log('b.js執(zhí)行');
const c = 3
module.exports = {
c
}
//執(zhí)行node index.js
// a.js執(zhí)行
// b.js執(zhí)行
// 3
// index.js執(zhí)行
es
// index.mjs
import { foo } from "./a.mjs"
console.log('index.js執(zhí)行');
// a.mjs
console.log('a.mjs執(zhí)行')
export const foo = () => {
import('./b.mjs').then(({c}) => {
console.log(c);
})
}
foo()
// b.mjs
console.log('b.mjs運行');
export const c = 3
//執(zhí)行node index.mjs
// a.mjs執(zhí)行
// index.js執(zhí)行
// b.mjs運行
// 3
可以看出來: import()是異步加載的,因為index.js在前面打印了,而不是在最后打印,代表他沒有被阻塞
3-4. 變量提升
es6
// a.mjs
console.log('我是a.mjs內(nèi)容');
import { num } from './b.mjs'
console.log(num);
// b.mjs
console.log('我是b.mjs內(nèi)容');
export let num = 100
// 執(zhí)行 node a.mjs
// 我是b.mjs內(nèi)容
// 我是a.mjs內(nèi)容
// 100
commonjs
// a.js
console.log('我是a.js內(nèi)容');
let obj = require('./b')
console.log(obj.num);
// b.js
console.log('我是b.js內(nèi)容');
let num = 100
module.exports = {
num
}
// 執(zhí)行 node a.js
// 我是a.js內(nèi)容
// 我是b.js內(nèi)容
// 100
可以看到es6現(xiàn)打印了b.js內(nèi)容, 而connonjs現(xiàn)打印了a.js的內(nèi)容, 在es6模塊中,當預(yù)解析a.js時候,發(fā)現(xiàn)import,就會去加載b.js. 整個流程就是預(yù)編譯a.js ? 發(fā)現(xiàn)import ? 預(yù)解析b.js ? 執(zhí)行b.js ? 執(zhí)行a.js
4. 總結(jié)
1. ES module是值的引用 CommonJS module是值的拷貝
2. CommonJS 模塊是運行時加載,ES6 模塊是編譯時加載。
3. CommonJS 模塊是同步加載,ES6 模塊是異步加載,
5. 結(jié)語
如果這篇文章幫到了你,歡迎點贊??和關(guān)注??。
文章如有錯誤之處,希望在評論區(qū)指正????。
原文鏈接:https://blog.csdn.net/weixin_46391646/article/details/124705188
相關(guān)推薦
- 2022-03-31 C#客戶端HttpClient請求認證及數(shù)據(jù)傳輸_C#教程
- 2022-10-20 Python中使用Frozenset對象的案例詳解_python
- 2022-05-20 Redis 做接口限流,一個注解的事
- 2022-04-17 css制作一個簡單的上下跳動 動畫
- 2022-04-20 基于PyQT5制作一個桌面摸魚工具_python
- 2022-11-27 Rust指南之生命周期機制詳解_Rust語言
- 2022-03-31 C#判斷語句的表達式樹實現(xiàn)_C#教程
- 2022-11-28 Flutter?Widgets之標簽類控件Chip詳解_IOS
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支