1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        寫好一個(gè)函數(shù)的個(gè)人見解

        共 9274字,需瀏覽 19分鐘

         ·

        2021-07-09 14:34


        點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

        回復(fù)1,加入高級(jí)Node交流群

        前言

        在 JS 中,除了變量,用的最多的應(yīng)該就是函數(shù)了,函數(shù)是 Javascript 的第一公民。

        要寫好一個(gè)函數(shù),個(gè)人認(rèn)為,可以從以下幾點(diǎn)來(lái)編寫:

        1. 命名準(zhǔn)確
        2. 函數(shù)注釋
        3. 函數(shù)參數(shù)
        4. 函數(shù)的返回

        本文對(duì)以上幾點(diǎn)做了梳理和總結(jié),希望能對(duì)大家有所幫助。

        正文

        1. 命名準(zhǔn)確

        1. 函數(shù)名稱

        這應(yīng)該是最基本的要求了,函數(shù)的命名需要明確,語(yǔ)義清晰,簡(jiǎn)單概括函數(shù)的功能。我們不要想著代碼簡(jiǎn)短而縮短函數(shù)名稱,這并不會(huì)提高什么性能或效率,相反,一個(gè)函數(shù)名稱若不夠清晰,往往其他人無(wú)法理解。

        除了一些都所有人知道的名次(我們這邊的 SKU )縮寫外,一些相對(duì)來(lái)講比較少人知道的專業(yè)名次就盡量不要使用縮寫。

        盡量使用動(dòng)詞,比如:getXxxxxsetXxxxx,動(dòng)詞在前面,語(yǔ)義就能更加清晰。

        1. 參數(shù)命名

        參數(shù)的命名同樣重要,我們都強(qiáng)調(diào)語(yǔ)義化,參數(shù)命名讓調(diào)用者更清晰的知道該傳入什么,對(duì)應(yīng)什么參數(shù)。當(dāng)然,像一些通用命名還是可接受的,像 callbackfn,即使不看注釋,往往我也知道這里的參數(shù)要做什么,傳什么。

        2. 函數(shù)注釋

        當(dāng)我們的命名準(zhǔn)確后,我們也不可能讓每一個(gè)看代碼的人都通過名稱就知道這個(gè)函數(shù)在做什么,這個(gè)參數(shù)代表什么。因此,函數(shù)一定要寫注釋,具體的交互代碼不寫,但函數(shù)的功能,參數(shù)至少是不可避免的。

        /**
         * 時(shí)間格式化工具函數(shù)
         * 
         * @param { (Date | number) } date - 時(shí)間
         * @param { string } unit - 轉(zhuǎn)換格式
         */

        export const timeFormat = (date: Date | number | string, unit: string) => {
          if (!date) {
            return ''
          }
          if (typeof date === 'string'return date;
          if (typeof date === 'number') {
            date = new Date(date);
          }
          const year = date.getFullYear();
          const month = date.getMonth() + 1;
          const day = date.getDate();
          const hour = date.getHours();
          const minute = date.getMinutes();
          const second = date.getSeconds();
          if (unit === 'year'return `${year}`;
          if (unit === 'month'return `${year}-${month}`;
          if (unit === 'day'return `${year}-${month}-${day}`;
          if (unit === 'hour'return `${year}-${month}-${day} ${hour}`;
          if (unit === 'minute'return `${year}-${month}-${day} ${hour}:${minute}`;
          if (unit === 'second'return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
        }
        1. 參數(shù)注釋

        像上面這個(gè)例子,參數(shù)前面都加了一個(gè) @param,表明這個(gè)是參數(shù)的注釋。

        一般的格式為 @param { type } 參數(shù) - 參數(shù)解釋。

        type 表明的是參數(shù)的類型,比如 string,number,當(dāng)有多個(gè)參數(shù)類型的時(shí)候,可以這么來(lái)標(biāo)識(shí) { (string|string[]) },表示這個(gè)參數(shù)可以是字符串或者字符串?dāng)?shù)組。

        還有其他的參數(shù)注釋可以這么來(lái)寫

        • 對(duì)象屬性:需要解釋對(duì)象的每一個(gè)屬性
        /**
         * Assign the project to an employee.
         * @param {Object} employee - The employee who is responsible for the project.
         * @param {string} employee.name - The name of the employee.
         * @param {string} employee.department - The employee's department.
         */

         Project.prototype.assign = function(employee{
           // ...
         };
        • 可選參數(shù):

        有兩種語(yǔ)法 JSDocGoogle Closure Compiler

        JSDoc 語(yǔ)法

        /**
         * 時(shí)間格式化工具函數(shù)
         * 
         * @param { (Date | number) } date - 時(shí)間
         * @param { string } [unit] - 轉(zhuǎn)換格式
         */

        export const timeFormat = (date: Date | number | string, unit: string) => {
          // ...
        }

        Google Closure Compiler 語(yǔ)法

        /**
         * 時(shí)間格式化工具函數(shù)
         * 
         * @param { (Date | number) } date - 時(shí)間
         * @param { string= } unit - 轉(zhuǎn)換格式
         */

        export const timeFormat = (date: Date | number | string, unit: string) => {
          // ...
        }
        • 默認(rèn)值:
        /**
         * 時(shí)間格式化工具函數(shù)
         * 
         * @param { (Date | number) } date - 時(shí)間
         * @param { string } [unit = 'second'] - 轉(zhuǎn)換格式
         */

        export const timeFormat = (date: Date | number | string, unit: string) => {
          // ...
        }
        1. 函數(shù)注釋

        函數(shù)的功能點(diǎn)需要表明,一個(gè)函數(shù)一個(gè)功能,這就是我們說的 單一功能,一個(gè)函數(shù)就做一件事,因此注釋也只會(huì)說明函數(shù)做了哪一件事。

        1. 其他注釋

        除了 @param 之外,還有其他的類型

        3. 函數(shù)參數(shù)

        1. 參數(shù)默認(rèn)值

        有時(shí)候,當(dāng)一個(gè)函數(shù)的參數(shù)不那么必要,或者某一個(gè)值相對(duì)應(yīng)用較多,就應(yīng)該考慮加上一個(gè)默認(rèn)值,比如上面的時(shí)間轉(zhuǎn)換工具,參數(shù)就應(yīng)該這么寫。

        export const timeFormat = (date: Date, unit = 'second') => {
          // ...
        }

        當(dāng)我們的業(yè)務(wù)中需要 YYYY-MM-DD hh:mm:ss 這樣的格式較多的時(shí)候,unit 默認(rèn)就是 second, 這樣,當(dāng)我們調(diào)用函數(shù)的時(shí)候,可以只傳一個(gè) date 參數(shù),而不需要在每一處調(diào)用的代碼都寫上 timeFormat(new Date(), 'second')。

        1. 對(duì)象參數(shù)

        在一段打印代碼中,參數(shù)多達(dá)十幾個(gè)。像下面這個(gè) 打印函數(shù)。

        async function printer_proxy_print(
          html_str: string,
          file_path: string,
          device: string | undefined,
          orientation: number,
          printer_mode: string,
          width: number,
          height: number,
          scale: number,
          from: number,
          to: number,
          left_offset: number,
          top_offset: number,
          pdf_tools: string | undefined,
          begin_page = 1,
          end_page = 1,
          repeat_times = 1,
          print_type: string
        {
            // ...
        }

        這個(gè)時(shí)候,我們可以給參數(shù)默認(rèn)值,這樣可以只傳前面幾個(gè)必要的參數(shù),像這樣調(diào)用。

        async function printer_proxy_print(
          html_str: string,
          file_path: string,
          device = 'pc',
          orientation = 'xxx',
          printer_mode = 'xxx',
          width = 123,
          height = 123,
          scale = 123,
          from = 123,
          to = 123,
          left_offset = 123,
          top_offset = 123,
          pdf_tools = 123,
          begin_page = 1,
          end_page = 1,
          repeat_times = 1,
          print_type = 'base64'
        {
            // ...
        }

        await printer_proxy_print(html_str, file_path);

        上面的方法看似可行,實(shí)際上,當(dāng)我中間某個(gè)參數(shù)不一樣的時(shí)候,我就需要把這個(gè)參數(shù)前面的參數(shù)都傳一遍。這樣顯然不可行。所以當(dāng)參數(shù)多的時(shí)候,我們需要用對(duì)象解構(gòu)的方式傳參。

        async function printer_proxy_print({
          html_str,
          file_path,
          device = 'pc',
          orientation = 'xxx',
          printer_mode = 'xxx',
          width = 123,
          height = 123,
          scale = 123,
          from = 123,
          to = 123,
          left_offset = 123,
          top_offset = 123,
          pdf_tools = 123,
          begin_page = 1,
          end_page = 1,
          repeat_times = 1,
          print_type = 'base64'
        }
        {
            // ...
        }

        await printer_proxy_print({html_str, file_path});

        解構(gòu)的好處便是我可以隨便傳我想要的某幾個(gè)參數(shù),而不用在意順序問題。不過像這么多參數(shù)的函數(shù)往往存在問題(具體問題具體分析)。也就是下面提到的參數(shù)數(shù)量問題。

        1. 參數(shù)數(shù)量

        一個(gè)函數(shù)的參數(shù)越少越好,最多不應(yīng)該超過3個(gè),參數(shù)多往往意味著關(guān)系多,邏輯交叉相對(duì)也就多了起來(lái)。在進(jìn)行測(cè)試的時(shí)候,往往也就很難覆蓋到所有條件,出問題概率也就加大了。

        參數(shù)多的時(shí)候,有時(shí)候也意味著功能多,就違背了 單一功能 的原則。

        1. 參數(shù)類型防御

        在 TS 開發(fā)前,我們不知道用戶會(huì)傳什么東西進(jìn)來(lái),這時(shí)候往往容易產(chǎn)生類型錯(cuò)誤,又或者,我們想實(shí)現(xiàn)兼容,像前面的 timeFormat 函數(shù),我們希望用戶調(diào)用的時(shí)候,可以是想對(duì) 時(shí)間對(duì)象 格式化,也可以是對(duì) 時(shí)間戳 格式化,那我們就需要做一個(gè)防御處理。

          if (!date) {
            return ''
          }
          if (typeof date === 'string'return date;
          if (typeof date === 'number') {
            date = new Date(date);
          }

        不過值得注意的是,即使我們用上了 TS,在大多數(shù)情況下,我們確實(shí)可以避免參數(shù)類型問題,但是這并不絕對(duì),因?yàn)槲覀冇袝r(shí)候會(huì)直接接受 接口 返回的數(shù)據(jù)。

        我們常說,永遠(yuǎn)不要相信用戶的輸入,同樣,接口返回的數(shù)據(jù)我也不信,我們不能保證,后端不會(huì)出錯(cuò),約定好的參數(shù)是數(shù)組類型,怎么空的時(shí)候,你給我個(gè) null 呢?

        當(dāng)然這些情況有時(shí)候需要去試錯(cuò),有時(shí)候我們能想到的可能,不要偷懶,給寫上類型判斷吧。

        4. 函數(shù)的返回

        1. 冪等

        什么叫冪等,簡(jiǎn)單來(lái)說,輸入什么輸出什么是固定的,入?yún)Q定了出參,不管調(diào)用多少次,只要輸入一樣,結(jié)果應(yīng)該保持一樣。

        簡(jiǎn)單的例子:

          function sum(a: number, b: number{
            return a + b;
          }

        冪等函數(shù)具有可維護(hù)性,相對(duì)容易進(jìn)行單元測(cè)試。

        1. 純函數(shù)

        純函數(shù)在冪等的條件下,還要求沒有副作用。

        舉個(gè)例子:

          const dog = {
            name'puppy',
            age2,
            weight30,
          }

          if (!dog.color) {
            console.log('has no color');
          }

          function addColor(dog{
            dog.color = 'white';
          }

          addColor(dog);
          console.log(dog); // {name: "puppy", age: 2, weight: 30, color: "white"}

        可以看到,addColor 函數(shù)修改了 dog 對(duì)象的屬性,也就是產(chǎn)生了副作用,我們應(yīng)該怎么做修改會(huì)合理點(diǎn)呢?可以像下面這樣:

          function addColor(dog{
            let copyDog = Object.assign({}, dog);
            copyDog.color = 'white';
            return copyDog;
          }

        這樣一來(lái),dog 對(duì)象的屬性就不會(huì)修改,addColor 函數(shù)是純函數(shù)。

        1. return null

        null 在進(jìn)行處理的時(shí)候相對(duì)麻煩,需要進(jìn)行判斷,導(dǎo)致了額外的代碼,應(yīng)當(dāng)返回空對(duì)象,或者是空數(shù)組,或者拋出異常。

        總結(jié)

        良好的代碼,自帶注釋。

        希望大家都能養(yǎng)成好的習(xí)慣。

        謝謝。

        如果覺得這篇文章還不錯(cuò)
        點(diǎn)擊下面卡片關(guān)注我
        來(lái)個(gè)【分享、點(diǎn)贊、在看】三連支持一下吧

           “分享、點(diǎn)贊、在看” 支持一波 

        瀏覽 48
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            好紧好爽浪货工人h | 中国性爱在线观看 | 亚洲久草 | 日韩欧美精品无码视频 | 波多野成人无码精品视频 | 女人卖婬全过片毛片免费观看 | va婷婷在线观看免费 | 成人免费视频播放成人影院 | 欧美一級黃色A片免費看野花 | 久久久久久久98 |