探索export導(dǎo)出一個(gè)字面量會(huì)報(bào)錯(cuò)export?default不會(huì)報(bào)錯(cuò)
核心
其實(shí)總的來說就是 export 導(dǎo)出的是變量的句柄(或者說符號(hào)綁定、近似于 C 語言里面的指針,C++里面的變量別名),而 export default 導(dǎo)出的是變量的值。
需要注意的是:模塊里面的內(nèi)容只能在模塊內(nèi)部修改,模塊外部只能使用。esModule在語法層面做了一層淺層的保護(hù)(即將import導(dǎo)入的變量聲明為常量)
而變量的句柄必須通過 var、let、const、function 這些關(guān)鍵字聲明才可以由 js 引擎生成,而值(或者說數(shù)據(jù))可以通過變量運(yùn)算或者字面量直接生成。
下面是測(cè)試用例:
// a.js
export let a = 'a'
export let objA = { a: 'a' }
let defaultA = 1
export default defaultA
export function fn(str) {
a = str
defaultA = str
}
// test1.js
import b, { a, fn, objA } from './a.js'
console.log(a, '---', b, '---', objA.a, '---', 'test1.js')
setTimeout(() => {
objA.a = 'hello world'
fn('hello world')
console.log(a, '---', b, '---', objA.a, '---', 'test1.js')
})
// test2.js
import b, { a, objA } from './a.js'
console.log(a, '---', b, '---', objA.a, '---', 'test2.js')
setTimeout(() => {
console.log(a, '---', b, '---', objA.a, '---', 'test2.js')
}, 100)
// main.js import './test1.js' import './test2.js'
運(yùn)行main.js,輸出結(jié)果如下:

分析
通過
a值的變化可以看出,在test1.js中的修改會(huì)影響到test2.js中a的值,驗(yàn)證我們說的導(dǎo)出句柄這個(gè)觀點(diǎn)。通過
b的運(yùn)行結(jié)果可以驗(yàn)證export default導(dǎo)出變量的值的觀點(diǎn)。通過
objA.a的運(yùn)行結(jié)果可以驗(yàn)證淺層保護(hù)的觀點(diǎn),其實(shí)和const obj = {},我們可以修改obj的屬性,只要不對(duì)obj重新賦值都是允許的是同一個(gè)邏輯。
如果看到這里你完全理解上面的內(nèi)容,那么下面的內(nèi)容就建議你跳過了,因?yàn)橄旅媸且恍┘?xì)節(jié)的展開和補(bǔ)充,對(duì)你來說可能會(huì)有些啰嗦和浪費(fèi)時(shí)間。如果上面的內(nèi)容你還不是很理解,那么可以再看看下面的內(nèi)容,看看是否對(duì)你有幫助。
那我們就按照以下幾個(gè)方面具體來講講這個(gè)問題,順便再做一些擴(kuò)展和補(bǔ)充。
1、句柄和值
2、ES module 和 commonJs
3、關(guān)于 Tree Shaking 的思考
句柄和值
其實(shí)句柄這個(gè)詞我個(gè)人理解為權(quán)限,獲得句柄就是獲得某種東西的操作權(quán)限,比如拿到文件句柄就可以對(duì)文件進(jìn)行讀寫操作。其實(shí)怎么理解都可以,只不過我引用了句柄這個(gè)詞語。我想說明的是 export 導(dǎo)出的是一個(gè)變量的句柄(或者說是引用),這個(gè)概念類似于 C 語言里面的指針,C++里面的變量別名。也就是說,導(dǎo)入模塊在拿到這個(gè)變量時(shí),對(duì)這個(gè)變量的操作實(shí)際上是在操作原來的導(dǎo)出變量本身。
而值其實(shí)就是一份數(shù)據(jù),也可以理解成 export default 導(dǎo)出的是一份數(shù)據(jù)拷貝。
擴(kuò)展
一、js 中聲明變量的幾種方式
- var、let、const
- function
- class
- import(準(zhǔn)確來講并沒有創(chuàng)建新的變量,但是這個(gè)關(guān)鍵字導(dǎo)入了被導(dǎo)入模塊的變量的引用,而在 js 引擎層面并沒有聲明新的變量)
注意:
// main.js
export { default as a } from 'xxx/a.xxx'
這種情況下,a 這個(gè)變量在 main.js 這個(gè)模塊中是訪問不到的。如果想要在 main.js 這個(gè)模塊中訪問到 a 模塊,需要使用 import 語句進(jìn)行導(dǎo)入,再使用 export 暴露給外界。
// main.js import a from 'xxx/a.xxx' export a
二、堆棧內(nèi)存
堆內(nèi)存:存放引用類型的數(shù)據(jù),例如對(duì)象、數(shù)組等
棧內(nèi)存:存放基本數(shù)據(jù)類型和引用類型的地址(存放占用空間固定的數(shù)據(jù))
ES module 和 CommonJS
1、實(shí)現(xiàn)層面
ES module 和 CommonJS 比較大的一個(gè)區(qū)別就是一個(gè)是官方規(guī)范,一個(gè)是社區(qū)規(guī)范。官方規(guī)范自然就能的到 js 語法層面的實(shí)現(xiàn)支持,而社區(qū)規(guī)范只能通過在現(xiàn)有的語法基礎(chǔ)上進(jìn)行擴(kuò)展來實(shí)現(xiàn)。
2、單獨(dú)導(dǎo)出和默認(rèn)導(dǎo)出
其實(shí) CommonJS 的實(shí)現(xiàn)也特別簡(jiǎn)單,看一眼 webpack 的打包結(jié)果就知道了。核心原理就是將一個(gè)個(gè)模塊放到函數(shù)中運(yùn)行,這樣利用函數(shù)作用域的特點(diǎn),就可以實(shí)現(xiàn)模塊之間的環(huán)境隔離。所以在 CommonJS 中,module.exports 和 exports 本質(zhì)上就是同一個(gè)對(duì)象,這個(gè)對(duì)象就是這個(gè)模塊(函數(shù))運(yùn)行時(shí) return 的對(duì)象。
而 ES module 則不然,export 和 export default 有著本質(zhì)的差別,那就是一個(gè)導(dǎo)出變量的句柄,一個(gè)導(dǎo)出變量的值。
擴(kuò)展(關(guān)于 export 導(dǎo)出的細(xì)節(jié))
關(guān)于 export 導(dǎo)出,出了這種下面常用的方式:
// a.js export let a = 1
還有一種方式:
// b.js
let b = 1
export { b }
而這兩種模塊的導(dǎo)入方式都是一樣:
import { a } from 'xx/a.js'
import { b } from 'xx/b.js'
既然前面說了,export 導(dǎo)出的是變量的句柄,那么顯然下面這種方式是要報(bào)錯(cuò)的:
// b.js
export { b: 1 } // SyntaxError: Unexpected token ':'
因?yàn)閷?dǎo)入方式一樣,那么很自然的我就想測(cè)試一下,我按照下面這種方式來測(cè)試一下看會(huì)不會(huì)產(chǎn)生沖突
let b = 1
export { b }
export let b = 2 // SyntaxError: Identifier 'b' has already been declared
很顯然使用 let、const 這樣的關(guān)鍵字會(huì)產(chǎn)生一個(gè)重復(fù)定義的沖突,那么我們?cè)僭囈幌铝硗庖粋€(gè)可以讓我們多次重復(fù)聲明同一個(gè)變量的 var 關(guān)鍵字。
var b = 1
export { b }
export var b = 2 // SyntaxError: Duplicate export of 'b'
改成 var 之后,不會(huì)在一開始編輯器就提示我們錯(cuò)誤了,而是在運(yùn)行時(shí),報(bào)一個(gè)重復(fù)導(dǎo)出的錯(cuò)誤。所以通過測(cè)試,這兩種 export 導(dǎo)出方式還是不會(huì)產(chǎn)生沖突的。
3、動(dòng)態(tài)導(dǎo)入
CommonJS 動(dòng)態(tài)導(dǎo)入就很簡(jiǎn)單,其實(shí)就是運(yùn)行函數(shù)。其實(shí) CommonJS 導(dǎo)入本身就是在運(yùn)行函數(shù),所以動(dòng)態(tài)或者靜態(tài)其實(shí)都一樣。
const a = require('xxx/a.js')
ES module 動(dòng)態(tài)導(dǎo)入,那就需要語法的支持,使用下面這種語法:
const a = await import('xxx/a.js')
關(guān)于 Tree Shaking 的思考
我們知道,ES module 是支持 Tree Shaking 的,但是 CommonJS 是不支持的。
其實(shí) Tree Shaking 面臨的核心困難就是怎么確定一個(gè)函數(shù)或者模塊它是否包含副作用。如果寫的都是純函數(shù),那么 Tree Shaking 其實(shí)是很實(shí)現(xiàn)的。那么像有些函數(shù),在編譯時(shí)直接可以運(yùn)行函數(shù)得到調(diào)用結(jié)果,進(jìn)而在生產(chǎn)運(yùn)行時(shí),直接省去求值的耗時(shí)。
所以 Tree Shaking 的核心是在于副作用的檢測(cè),特別是在復(fù)雜的模塊引用關(guān)系里面,確定每個(gè)模塊里的某些內(nèi)容是否存在副作用。另外為了更好的 Tree Shaking,比較推薦的方案是使用 ES module,并且使用 export 導(dǎo)出,這方式可以更好的進(jìn)行 Tree Shaking。
以上就是探索export導(dǎo)出一個(gè)字面量會(huì)報(bào)錯(cuò)export default不會(huì)報(bào)錯(cuò)的詳細(xì)內(nèi)容,更多關(guān)于export導(dǎo)出字面量的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- vue報(bào)錯(cuò)之exports is not defined問題的解決
- 解決React報(bào)錯(cuò)Unexpected default export of anonymous function
- 關(guān)于JavaScript使用export和import的兩個(gè)報(bào)錯(cuò)解決
- 關(guān)于IDEA中的.VUE文件報(bào)錯(cuò) Export declarations are not supported by current JavaScript version
- 解決使用export_graphviz可視化樹報(bào)錯(cuò)的問題
相關(guān)文章
js 連接數(shù)據(jù)庫如何操作數(shù)據(jù)庫中的數(shù)據(jù)
JS中怎么連接數(shù)據(jù)庫,和提取數(shù)據(jù)庫中的數(shù)據(jù),本文將以此問題詳細(xì)介紹,需要的朋友可以了解下2012-11-11
原生js通過一行代碼實(shí)現(xiàn)簡(jiǎn)易輪播圖
這篇文章主要介紹了原生js一行代碼實(shí)現(xiàn)簡(jiǎn)易輪播圖功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2019-06-06
javascript 三種方法實(shí)現(xiàn)獲得和設(shè)置以及移除元素屬性
獲得和設(shè)置以及移除元素屬性在操作dom的過程中會(huì)經(jīng)常遇到吧,為了提高工作的效率本文整理了一些快捷操作方法和大家一起分享,感興趣的朋友可以參考下哈2013-03-03
Google的跟蹤代碼 動(dòng)態(tài)加載js代碼方法應(yīng)用
Google的跟蹤代碼 動(dòng)態(tài)加載js代碼,需要的朋友可以參考下2012-11-11
JavaScript+html5 canvas繪制的小人效果
這篇文章主要介紹了JavaScript+html5 canvas繪制的小人效果,涉及JavaScript結(jié)合html5 canvas圖形繪制及顏色隨機(jī)填充的技巧,需要的朋友可以參考下2016-01-01
JavaScript中計(jì)算網(wǎng)頁中某個(gè)元素的位置
這篇文章主要介紹了JavaScript中計(jì)算網(wǎng)頁中某個(gè)元素的位置,本文先是講解了一些必要的知識(shí)和實(shí)現(xiàn)難點(diǎn),然后給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-06-06
在Javascript里訪問SharePoint列表數(shù)據(jù)的實(shí)現(xiàn)方法
在進(jìn)行SharePoint訂制的時(shí)候經(jīng)常會(huì)遇到開發(fā)手段受限制的問題,比如通常公司都會(huì)限制服務(wù)器的訪問以及部署,很多開發(fā)都只能夠在客戶端來進(jìn)行2011-05-05
Openlayers實(shí)現(xiàn)根據(jù)半徑繪制圓形
這篇文章主要介紹了利用Openlayers實(shí)現(xiàn)繪制三個(gè)圓形,繪制完成之后,三個(gè)圓心連接起來,然后標(biāo)記出每?jī)蓚€(gè)圓心之間的距離,感興趣的可以了解一下2022-08-08

