為什么 JavaScript 模塊中的默認(rèn)導(dǎo)出很糟糕
我們知道,JavaScript 模塊有兩種方法來(lái)定義導(dǎo)出:默認(rèn)導(dǎo)出和命名導(dǎo)出。在本節(jié)中,我們來(lái)看下為什么默認(rèn)導(dǎo)出是一種糟糕的做法,會(huì)導(dǎo)致不好的開發(fā)體驗(yàn)。
下面,我們看下例子,假設(shè),我們有一個(gè)模塊,它同時(shí)包含命名導(dǎo)出和默認(rèn)導(dǎo)出,如下所示:
export const add = (a, b) => a + b;
export default subtract = (a, b) => a - b;
在導(dǎo)入使用之前,這里有一個(gè)問(wèn)題,它可能會(huì)影響到我們的開發(fā)體驗(yàn)。為什么 subtract 是默認(rèn)的,而 add 是一個(gè)命名的導(dǎo)出?
ps:我舉的例子,可能有點(diǎn)刻意,但隨著模塊的復(fù)雜,類似這種情況有常有的
考慮到開發(fā)人員使用一個(gè)他們不熟悉且復(fù)雜的模塊。他們可能不知道默認(rèn)導(dǎo)出的是什么方法,甚至可能也不確定是否有默認(rèn)導(dǎo)出。這導(dǎo)致開發(fā)者需要花更多的時(shí)間來(lái)閱讀文檔或源碼。如果模塊只有命名導(dǎo)出,那么使用起來(lái)就更加的方便,可讀性也會(huì)更好。
有了命名導(dǎo)出,使用IDE,我們可以很方便的知道一個(gè)模塊有哪些方法。那么,這個(gè)下面的列表中沒(méi)有展示什么呢?沒(méi)錯(cuò),就是默認(rèn)導(dǎo)出。記住,默認(rèn)導(dǎo)出不是命名的導(dǎo)出,所以 IDE 不知道改默認(rèn)導(dǎo)出是干嘛的,也就不會(huì)在提示的列表中顯示出來(lái):
默認(rèn)導(dǎo)出的開發(fā)體驗(yàn)類似于 Node 中的 CommonJS,它的開發(fā)體驗(yàn)也不太友好。判斷代碼是否使用 CommonJS 的一個(gè)簡(jiǎn)單方法,就是看有沒(méi)有使用 require 和 module.exports 。
下面我們?cè)俳榻B一下,默認(rèn)導(dǎo)出的一些用法(槽點(diǎn)):
- 默認(rèn)導(dǎo)出的名稱可以隨便我們?nèi)∶?。也就是說(shuō),減法函數(shù)你可以命名成乘法。這會(huì)導(dǎo)致混亂,特別是隨著代碼復(fù)雜度的增加。
import multiply from './math.js';
const result = multiply(2, 2); // results is now 0
- 由于默認(rèn)導(dǎo)出可以用任何名字,并且每個(gè)開發(fā)者的命名習(xí)慣不一樣,名稱就不一樣,這樣就沒(méi)有一致性了。
- 默認(rèn)導(dǎo)出也不利于重構(gòu)。在命名導(dǎo)出中,如果哪天我們的方法名改了,那么IDE 會(huì)提示我們對(duì)應(yīng)的方法不存在,我們可以更好的重構(gòu)。對(duì)于默認(rèn)導(dǎo)出,IDE 是沒(méi)有反饋的。
到這里,大家可能有一個(gè)問(wèn)題,如果來(lái)自不同模塊的兩個(gè)命名導(dǎo)出具有相同的名稱,該怎么辦?
我們可以使用重命名的方式來(lái)解決這個(gè)問(wèn)題:
import { Article } from './types';
import { Article as ArticleComponent } from 'my-design-system';
雖然這種方式仍然需要為別名想一個(gè)名稱,但這比為默認(rèn)導(dǎo)出想一個(gè)名稱要好得多,因?yàn)橛忻麑?dǎo)出作為參考。
最后,你可能也在想,"我使用的框架或工具幾乎要求我們默認(rèn)導(dǎo)出一個(gè)函數(shù)或組件"。如果組件很多,我們可以通過(guò)使用 "index.js" 來(lái)解決這個(gè)問(wèn)題。就是在目錄的根部創(chuàng)建一個(gè)index.js或index.ts文件,然后使用命名導(dǎo)出這些組件。
比如我們有一個(gè)文件 components,該文件主要放置我們封裝的組件:
src/
components/
com1/
index.vue
com2/
index.vue
那么我們可以在 components 創(chuàng)建一個(gè) index.js 文件,內(nèi)容如下:
export { default as Com1 } from './com1'
xport { default as Com2 } from './com2'
這樣我們?cè)谄渌募惺褂妹麑?dǎo)出的方式引入使用:
import { Com1, Com2 } from '@/components'
如果在寫一個(gè)模塊,無(wú)論是代碼庫(kù)還是開源庫(kù),盡量少使用默認(rèn)導(dǎo)出。