摘要:所以編輯器就會使用一個(gè)在中經(jīng)常出現(xiàn)用來標(biāo)識任意類型的關(guān)鍵字來描述函數(shù)的參數(shù)以及返回值。描述類型的返回值處理現(xiàn)在這個(gè)年代,基本上已經(jīng)普及開來,所以很多函數(shù)的返回值可能并不是結(jié)果,而是一個(gè)。
工作了四年多,基本上都在圍繞著 JavaScript 做事情。作用
寫的代碼多了,看的代碼也多了,由衷的覺得,寫出別人看不懂的代碼并不是什么能力,寫出所有人都能讀懂的代碼,才是真的牛X。
眾所周知, JavaScript 是一個(gè)弱類型的腳本語言,這就意味著,從編輯器中并不能直觀的看出這段代碼的作用是什么,有些事情只有等到代碼真正的運(yùn)行起來才能夠確定。
所以為了解決大型項(xiàng)目中 JavaScript 維護(hù)成本高的問題,前段時(shí)間我們團(tuán)隊(duì)開始使用 TypeScript,但是由前幾年所積累下來的代碼,并不是說改立馬都能全部改完的,所以這個(gè)重構(gòu)將是一個(gè)漫長的過程。
在重構(gòu)同時(shí)我們還是需要繼續(xù)維護(hù)原有的 JavaScript 項(xiàng)目的,而 JSDoc 恰好是一個(gè)中間過渡的方案,可以讓我們以注釋的形式來降低 JavaScript 項(xiàng)目的維護(hù)難度,提升可讀性。
本人使用的是 vs code 編輯器,內(nèi)置了對 jsdoc 的各種支持,同時(shí)還會根據(jù)部分常量,語法來推測出對應(yīng)的類型
可以很方便的在編輯器中看到效果,所以下面所有示例都是基于 vscode 來做的。
首先,JSDoc 并不會對源碼產(chǎn)生任何的影響,所有的內(nèi)容都是寫在注釋里邊的。
所以并不需要擔(dān)心 JSDoc 會對你的程序造成什么負(fù)面影響。
可以先來看一個(gè)普通的 JavaScript 文件在編輯器中的展示效果:
很顯而易見的,編輯器也不能夠確定這個(gè)函數(shù)究竟是什么含義,因?yàn)槿魏晤愋偷膬蓚€(gè)參數(shù)都可以進(jìn)行相加。
所以編輯器就會使用一個(gè)在 TypeScript 中經(jīng)常出現(xiàn)用來標(biāo)識任意類型的 any 關(guān)鍵字來描述函數(shù)的參數(shù)以及返回值。
而這種情況下我們可以很簡單的使用 JSDoc 來手動描述這個(gè)函數(shù)的作用:
實(shí)際上有些函數(shù)是需要手動指定@return {TYPE}來確定函數(shù)返回值類型的,但因?yàn)槲覀兒瘮?shù)的作用就是通過兩個(gè)參數(shù)相加并返回,所以編輯器推算出了函數(shù)返回值的類型。
對比上下兩段代碼,代碼上并沒有什么區(qū)別,也許有人會嗤之以鼻,認(rèn)為代碼已經(jīng)足夠清晰,并不需要額外的添加注釋來說明。
這種盲目自信一般會在接手了其他人更爛的代碼后被打破,然后再反思自己究竟做錯(cuò)了什么,需要去維護(hù)這樣的代碼。
亦或者我們來放出一個(gè)稍微復(fù)雜一些的例子:
看似清晰、簡潔的一個(gè)示例,完全看不出什么毛病 _除了兩個(gè)異步await可以合并成一個(gè)_。
確實(shí),如果這段代碼就這么一直躺在項(xiàng)目中,也不去改需求,那么這段代碼可以說是很完美的存在了。
如果這段代碼一直是寫下這段代碼的作者在維護(hù),那么這段代碼在維護(hù)上也不會有什么風(fēng)險(xiǎn)。
不過如果哪天這段代碼被交接了出去,換其他的小伙伴來維護(hù)。
那么他可能會有這么幾個(gè)疑問:
getUserInfo的返回值是什么結(jié)構(gòu)
createOrder的返回值又是什么結(jié)構(gòu)
notify中傳入的兩個(gè)變量又都是用來做什么的
我們也只能夠從notify函數(shù)中找到一些線索,查看到前兩個(gè)函數(shù)所返回對象的部分屬性, _但是仍然不能知道這些屬性的類型是什么_。
而想要維護(hù)這樣的一段代碼,就需要占用很多腦容量去記憶,這實(shí)際上是一個(gè)性價(jià)比非常低的事情,當(dāng)這段代碼再轉(zhuǎn)給第三個(gè)人時(shí),第三個(gè)人還需要再經(jīng)歷完整的流程,一個(gè)個(gè)函數(shù)、一行行代碼去閱讀,去記憶。
如果你把這個(gè)當(dāng)作是對程序的深入了解程度、對業(yè)務(wù)的嫻熟掌握,那么我覺得我也幫不了你了。
就像是現(xiàn)在超市結(jié)賬時(shí),沒有柜員會以能夠記憶N多商品價(jià)格而感到驕傲,掃碼槍能做到的事情,為什么要占用你的大腦呢。
如上文所說的,JSDoc 是寫在注釋中的一些特定格式內(nèi)容。
在 JavaScript 文件中大部分的標(biāo)記都是塊級形式的,也就是使用 /** XXX */ 來進(jìn)行定義,不過如果你愿意的話,也可以寫到代碼里邊去。
JSDoc 提供了很多種標(biāo)記,用于各種場景。
但并不是所有的都是常用的(而且使用了 vscode 以后,很多需要手動指定的標(biāo)記,編輯器都能夠代替你完成),常用的無外乎以下幾個(gè):
@type 標(biāo)識變量類型
@param 標(biāo)識函數(shù)參數(shù)類型及描述
@return 標(biāo)識函數(shù)返回值類型及描述
完整的列表可以在這里找到 Block tags
基本上使用以上三種標(biāo)記以后,已經(jīng)能夠解決絕大部分的問題。
JSDoc 在寫法上有著特定的要求,比如說行內(nèi)也必須要是這樣的結(jié)構(gòu) /** XXX */,如果是 /* XXX */ 則會被忽略。
而多行的寫法是比較常用的,在 vscode 中可以直接在函數(shù)上方鍵入 /** 然后回車,編輯器會自動填充很多的內(nèi)容,包括參數(shù)類型、參數(shù)描述以及函數(shù)描述的預(yù)留位置,使用TAB鍵即可快速切換。
實(shí)際上@type的使用頻率相較于其他兩個(gè)是很低的,因?yàn)榇蠖鄶?shù)情況下@type用于標(biāo)識變量的類型。
而變量的來源基本上只有兩個(gè) 1. 基本類型賦值 2. 函數(shù)返回值
首先是第一個(gè)基本類型的賦值,這個(gè)基本上 vscode 就幫你做了,而不需要自己手動的去指定。
而另外一個(gè)函數(shù)的返回值,如果我們在函數(shù)上添加了@return后,那么調(diào)用該函數(shù)并獲取返回值的變量類型也會被設(shè)置為@return對應(yīng)的類型。
不過因?yàn)槠渌麅蓚€(gè)標(biāo)記中都有類型相關(guān)的指定,所以就拿 @type 來說明一下
首先,在 JSDoc 中是支持所有的基本類型的,包括數(shù)字、字符串、布爾值之類的。
/** @type {number} */ /** @type {string} */ /** @type {boolean} */ /** @type {RegExp} */ // 或者是一個(gè)函數(shù) /** @type {function} */ // 一個(gè)包含參數(shù)的函數(shù) /** @type {function(number, string)} */ // Object結(jié)構(gòu)的參數(shù) /** @type {function({ arg1: number, arg2: string })} */ // 一個(gè)包涵參數(shù)和返回值的函數(shù) /** @type {function(number, string): boolean} */
在 vscode 中鍵入以上的注釋,都可以很方便的得到動態(tài)提示。擴(kuò)展復(fù)雜類型
當(dāng)然了,關(guān)于函數(shù)的,還是推薦使用 @param 和 @return 來實(shí)現(xiàn),效果更好一些
上邊的示例大多是基于基本類型的描述,但實(shí)際開發(fā)過程中不會說只有這么些基本類型供你使用的。
必然會存在著大量的復(fù)雜結(jié)構(gòu)類型的變量、參數(shù)或返回值。
關(guān)于函數(shù)參數(shù),在 JSDoc 中兩種方式可以描述復(fù)雜類型:
不過這個(gè)只能應(yīng)用在@param中,而且復(fù)用性并不高,如果有好幾處同樣結(jié)構(gòu)的定義,那我們就需要把這樣的注釋拷貝多份,顯然不是一個(gè)優(yōu)雅的寫法。
又或者我們可以使用另外兩個(gè)標(biāo)記,@typedef和@property,格式都與上邊提到的標(biāo)記類似,可以應(yīng)用在所有需要指定類型的地方:
使用@typedef定義的類型可以很輕松的復(fù)用,在需要的地方直接指定我們定義好的類型即可。
同理,這樣的自定義類型可以直接應(yīng)用在@return中。
這個(gè)算是比較重要的一個(gè)標(biāo)記了,用來標(biāo)記函數(shù)參數(shù)的相關(guān)信息。
具體的格式是這樣的(切換到 TypeScript 后一般會移除類型的定義,改用代碼中的類型定義):
/** * @param {number} param 描述 */ function test (param) { } // 或者可以結(jié)合著 @type 來寫(雖說很少會這么寫) /** * @param param 描述 */ function test (/** @type number */ param) { }可選參數(shù)
如果我們想要表示一個(gè)參數(shù)為可選的參數(shù),可以的在參數(shù)名上包一個(gè)[]即可。
/** * @param {number} [param] 描述 */ function test (param) { }
同事在文檔中還提到了關(guān)于默認(rèn)值的寫法,實(shí)際上如果你的可選參數(shù)在參數(shù)位已經(jīng)有了默認(rèn)值的處理,那么就不再需要額外的添加[]來表示了,vscode 會幫助你標(biāo)記。
// 文檔中提到的默認(rèn)值寫法 /** * @param {number} [param=123] 描述 */ function test (param = 123) { } // 而實(shí)際上使用 vscode 以后就可以簡化為 /** * @param param 描述 */ function test (param = 123) { }
兩者效果是一樣的,并且由于我們手動指定了一個(gè)基礎(chǔ)類型的值,那么我們連類型的指定都可以省去了,簡單的定義一下參數(shù)的描述即可。
return該標(biāo)記就是用來指定函數(shù)的返回值,用法與@param類型,并且基本上這兩個(gè)都會同時(shí)出現(xiàn),與@param的區(qū)別在于,因?yàn)?b>@return只會有一個(gè),所以不會像前者一樣還需要指定參數(shù)名。
/** * @return {number} 描述 */ function test () { }Promise 類型的返回值處理
現(xiàn)在這個(gè)年代,基本上Promise已經(jīng)普及開來,所以很多函數(shù)的返回值可能并不是結(jié)果,而是一個(gè)Promise。
所以在vscode中,基于Promise去使用@return,有兩種寫法可以使用:
// 函數(shù)返回 Promise 實(shí)例的情況可以這么指定類型 /** * @return {Promise小結(jié)} */ function test () { return new Promise((res) => { res(1) }) } // 或者使用 async 函數(shù)定義的情況下可以省略 @return 的聲明 async function test () { return 1 } // 如果返回值是一個(gè)其他定義了類型的函數(shù) or 變量,那么效果一樣 async function test () { return returnVal() } /** @return {string} */ function returnVal () {}
再回到我們最初的那個(gè)代碼片段上,將其修改為添加了 JSDoc 版本的樣子:
/** * @typedef {Object} UserInfo * @property {number} uid 用戶UID * @property {string} name 昵稱 * * @typedef {Object} Order * @property {number} orderId 訂單ID * @property {number} price 訂單價(jià)格 */ async function main () { const uid = 1 const orders = await createOrder(uid) const userInfo = await getUserInfo(uid) await notify(userInfo, orders) } /** * 獲取用戶信息 * @param {number} uid 用戶UID * @return {Promise} */ async function getUserInfo (uid) { } /** * 創(chuàng)建訂單 * @param {number} uid 用戶UID * @return {Promise } */ async function createOrder (uid) { } /** * 發(fā)送通知 * @param {UserInfo} userInfo * @param {Order} orders */ async function notify (userInfo, orders) { }
實(shí)際上并沒有添加幾行文本,在切換到 TypeScript 之前,使用 JSDoc 能夠在一定程度上降低維護(hù)成本,尤其是使用 vscode 以后,要手動編寫的注釋實(shí)際上是沒有多少的。
但是帶來的好處就是,維護(hù)者能夠很清晰的看出函數(shù)的作用,變量的類型。代碼即文檔。
并且在進(jìn)行日常開發(fā)時(shí),結(jié)合編輯器的自動補(bǔ)全、動態(tài)提示功能,想必一定是能夠提高開發(fā)體驗(yàn)的。
上邊介紹的只是 JSDoc 常用的幾個(gè)標(biāo)記,實(shí)際上還有更多的功能沒有提到,具體的文檔地址:jsdoc
參考資料jsdoc | @return
jsdoc | @param
jsdoc | @typedef
jsdoc | @property
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/103756.html
摘要:本文比較了種較為主流的注釋文檔生成工具。應(yīng)該說是非常適合開源項(xiàng)目多個(gè)作者共同維護(hù)的一個(gè)文檔工具。最后我選擇了作為文檔生成的工具。為了支持多種語言,它僅對注釋塊內(nèi)部的內(nèi)容進(jìn)行解析。 最近隨著寫Node以及獨(dú)立的CommonJS模塊越來越多,我發(fā)現(xiàn)有一份好的文檔不僅可以幫助自己在應(yīng)用這些接口的時(shí)候不至于迷糊,而且對于共同開發(fā)的情況下,能夠省去大量團(tuán)隊(duì)的交流和Debug的時(shí)間。 本文比較了...
摘要:優(yōu)秀的代碼注釋可以提高代碼可讀性,當(dāng)然優(yōu)秀的命名規(guī)范也可以啦。表示函數(shù)是異步的。行注釋行注釋的話,應(yīng)該不用做太多的解釋,直接用注釋相關(guān)信息就啦。 showImg(http://ws1.sinaimg.cn/large/005NRne3gy1g34cu772u0j30s00v4wko.jpg); 前言 可能現(xiàn)在不管大家去面試還是在公司上班都會涉及到代碼可讀性,或者是代碼規(guī)范。優(yōu)秀的代碼注...
摘要:我們在對現(xiàn)在較主流的五個(gè)文檔工具分別作了調(diào)研和嘗試,得到結(jié)論如下工具優(yōu)點(diǎn)缺點(diǎn)提供了完整的模板開發(fā)事件觸發(fā)等接口,使用非常靈活。至此,的環(huán)境部署已經(jīng)全部完成了。 字?jǐn)?shù):981 閱讀時(shí)間:5分鐘 選型依據(jù) ? 在經(jīng)歷了數(shù)個(gè)上線的項(xiàng)目之后,筆者所在的團(tuán)隊(duì)已經(jīng)沉淀了一個(gè)相對穩(wěn)定版本的前端框架。因此,我們需要出具一套框架API文檔,以便公司其他成員的使用和框架的后期維護(hù)。我們在對...
摘要:的出現(xiàn)大有統(tǒng)一輕量級領(lǐng)域之勢,在其新版本中自帶了的解析功能,幫助開發(fā)者通過書寫注釋的形式向提供必要信息,完善提示功能。如果因?yàn)檫@種需求就額外的,就會破壞了代碼正常的依賴關(guān)系。 弱類型腳本語言的代碼提示功能一直是開發(fā)者一個(gè)隱隱的痛點(diǎn),沒有它也不是不能干活,但是經(jīng)常因?yàn)槌霈F(xiàn)拼寫錯(cuò)誤或不經(jīng)意的修改導(dǎo)致的變量丟失而耗費(fèi)無畏的時(shí)間在與業(yè)務(wù)邏輯無關(guān)的地方。VSCode的出現(xiàn)大有統(tǒng)一輕量級IDE領(lǐng)域...
閱讀 3696·2021-09-22 15:28
閱讀 1310·2021-09-03 10:35
閱讀 890·2021-09-02 15:21
閱讀 3495·2019-08-30 15:53
閱讀 3505·2019-08-29 17:25
閱讀 583·2019-08-29 13:22
閱讀 1570·2019-08-28 18:15
閱讀 2299·2019-08-26 13:57