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