[探索]怎麼樣的參數能讓 JS - API 更靈活

外在決定是否需要了解內在,內在決定是否會一票否決外在。內外結合,好上加好。

1.前言

開發 API 的時候,把參數的名字和位置確定下來,函數定義就可以說是完成了。因爲 API 使用者來說,只需要知道如何傳遞參數,以及函數將返回什麼樣的值就夠了,無需瞭解內部。所以參數多多少少影響了 API 的一個靈活程度和使用複雜程度。在設計 API 的時候,應該怎麼設計參數,下面就簡單的寫下,如果大家有不同的想法,歡迎在評論區留言。

下面使用的例子,除了原生了 JQuery 的 API。其他的例子都是取自自己封裝的一個常用函數庫 ecDo 。歡迎提建議和 star。

2.什麼時候該設置參數

其實什麼時候設置參數並沒什麼什麼說法,規範。只要覺得用參數會使得 API 的使用會更加的簡單和靈活就用了。

設置參數,可能一開始不會有很好的靈感,但是在使用過程中,用得難受了,自然會像辦法優化。

比如 有 ecDo.count(array|string,item) 這個 API 就是統計一個數組的每個元素的出現次數或者字符串每一個字符的個數。

這很容易實現,代碼也貼下

count(arr) {
    let obj = {}, k, arr1 = []
    //記錄每一元素出現的次數
    for (let i = 0, len = arr.length; i < len; i++) {
        k = arr[i];
        if (obj[k]) {
            obj[k]++;
        } else {
            obj[k] = 1;
        }
    }
    //保存結果{el-'元素',count-出現次數}
    for (let o in obj) {
        arr1.push({el: o, count: obj[o]});
    }
    return arr1;
},



let strTest1='abbccc'
console.log(ecDo.count(strTest1));
//result:[{el: "a", count: 1},{el: "b", count: 2},el: "c", count: 3}]

但是有些時候,開發者並不需要知道所有元素的個數,比如就需要知道 'a' 的出現次數,這個情況直接返回 'a' 的個數就行了,不需要像上面例子一樣,返回一個數組。這樣用起來會舒服一些,改起來也很簡單,只要增加一個參數,一個判斷即可。

count(arr,item) {
    //重複代碼略
    return item?obj[item]:arr1;
},



let strTest1='abbccc'
console.log(ecDo.count(strTest1),'a');
//result:1

還有一個常用的 API 是ecDo.clearKeys(obj)--清除對象中值爲‘空’(null, undefined和'')的屬性。

這個也很容易實現,

clearKeys(obj) {
    let _newPar = {};
    for (let key in obj) {
        if (obj[key]===0||obj[key]===false||obj[key]) {
            _newPar[key] = obj[key];
        }
    }
    return _newPar;
},


ecDo.clearKeys({1:0,2:2,3:''})
//result:{1: 0, 2: 2}

想必大家也發現這樣寫法太不靈活了,如果下次要把 0false 的屬性也清空呢?如果下次要把值爲 '--' 的屬性也清空呢?這樣就做不到了,所以還要改一下,增加一個參數 clearValues - 待清空的值。

要使用的一個函數

clearKeys(obj, clearValues = [null, undefined, '']) {
    clearValues.forEach((item, index) => {
        clearValues[index] = Number.isNaN(item) ? 'NaN' : item
    });
    let _newPar = {};
    for (let key in obj) {
        //checkValue 看下面定義
        if (!checkValue(obj[key], clearValues)) {
            _newPar[key] = obj[key];
        }
    }
    return _newPar;
},


ecDo.clearKeys({a:'',b:0,c:11})
//result:{b: 0,c: 11}
ecDo.clearKeys({a:'',b:0,c:'--'},['--',''])
//result:{b: 0}
ecDo.clearKeys({a:'',b:0,c:11,d:false},[0,''])
//result:{c: 11,d: false}
ecDo.clearKeys({a:NaN,b:2,c:undefined},[NaN,undefined])
//result:{b: 2}

checkValue 函數

function checkValue(val, vals) {
    let _val = val;
    if (Number.isNaN(val)) {
        _val = 'NaN'
    }
    return vals.indexOf(_val) !== -1;
}

這樣以來,想清除任何值的屬性,這裏都可以實現。

3.參數數量和前置

這兩個注意點可以說是平常接觸最頻繁的,也是最無可辯解的。

首先參數的數量,在不影響 API 使用的情況下肯定是能少就少,越少越好。因爲參數的越少,API 的記憶成本越低,調用也更加便利。

參數能少就少,越少越好,是有前提的--不影響 API 的使用。如果多個參數, API 使用能更方便,靈活,簡單。多個參數就多個參。

然後參數的前置性,就是參數相關性越高,越不能省略的,就越要放在前面。雖然可以把可省略參數放後面,但是這樣問題可能會很多。

4.使用對象作爲參數

什麼時候該使用對象作爲函數的參數,暫時發現是兩種情況。

1.參數過多的時候

2.參數不固定的時候

比如 ajax 的參數,至少至少也有 5 個。url-請求鏈接,method-請求方式,data-請求參數,success-成功回調,fail-失敗回調。如果不使用對象作爲參數,完整的寫法,是下面這樣

ajax(url,method,data,success,fail)

但這5個參數裏面,除了 url ,其他參數都可以省略或者默認。如果只需要傳 url 和 success,需要像下面這樣寫

ajax(url,'','',success)

因爲參數的順序不能亂,所以就要這樣寫。這樣多難受就不說了,如果參數過多,參數看着會很長,容易搞錯參數順序,就會出現問題了。

如果使用對象傳參,就舒服很多了。

ajax({url:url,success:function(){}})

這樣寫的會多一點,但是好處也有。首先用戶還是需要記住參數名,但不用關心參數順序,不用擔心參數過多。然後就是開發者想增加多少參數都比較方便,也不用關心參數後置的問題。

是否使用對象作爲參數,判斷的指標應該只有一個:是否方便使用,靈活。

5.參數默認值

什麼時候應該設計默認值?也分幾種情況討論

首先是,一個參數值出現頻率比其他情況大的時候。比如有一個 ecDo.encrypt(str,regIndex,repText) 的 API,作用很簡單,就是對字符串的特定位置進行加密。比如經常會遇到隱藏用戶的手機號碼的需求。

電話號碼隨便編造的

ecDo.encrypt('18819233362','3,7')
//result:188*****362

ecDo.encrypt('18819233362','3,7','+')
//result:188+++++362

ecDo.encrypt('18819233362','4')
//result:*****233362

ecDo.encrypt('18819233362','-4')
//result:188192*****

在這個 API 裏面 ,第三個參數 repText 可能大多數情況都是使用 。如果不對 repText 設置默認值,如果每一次都傳一個 ,不但寫的多,看得也難受。

還有一種情況,從特定位置執行到結尾結束的時候。比如原生的 substr(start,length) ,第一個參數是開始字符的下標,第二個參數是截取的長度。如果省略,就從開始位置截取到結尾。這樣就算是一種方便。

5.參數多態

這裏說的參數多態跟繼承方面的多態有點區別

參數多態這個很常見,目的很簡單,就是通過不同的傳參方式讓一個函數進行不同的操作。看到這裏,可能大家一下子就想到 splice。因爲一個 splice 可以實現數組的增加,刪除,替換

//刪除
let arr=[1,2,3,4,5,6]
arr.splice(0,1)
//result:arr:[2, 3, 4, 5, 6]

//替換
arr=[1,2,3,4,5,6]
arr.splice(2,1,0)
//result:arr:[1, 2, 0, 4, 5, 6]

//增加
arr=[1,2,3,4,5,6]
arr.splice(2,0,0)
//result:arr:[1, 2, 0, 3, 4, 5, 6]

但是 splice 應該並不算是參數多態,只能算是一些技巧的一個寫法。

表現出參數多態的,比如 JQuery 的 attr 。既可以獲取屬性的值,也可以設置屬性的值。

//獲取 dom 元素 id 的值
$(dom).attr('id')
//設置 dom 元素 id 的值
$(dom).attr('id','domId')

JQuery 把多態表現得更好的應該是 $() 。JQuery 火的原因,跟這個 $() 有很大的關係,只要是合法的選擇器,頁面存在這個元素,就能找到。讓選擇元素變得非常簡單。

關於 $() 的強大特性,可參考 jQuery 選擇器

在自己封裝 API 的時候,也會遇到操作 cookie 的一系列操作(設置,獲取,刪除)。之前是這樣

ecDo.setCookie(cookieName,value,day)//設置(cookie名稱,cookie值,有效的天數)
ecDo.getCookie(cookieName)//獲取
ecDo.removeCookie(cookieName)//刪除

現在是這樣

ecDo.cookie(cookieName,value,day)//設置(cookie名稱,cookie值,有效的天數)
ecDo.cookie(cookieName)//獲取
ecDo.cookie(cookieName,value,-1)//刪除

這樣使用起來,就比之前簡單一點,相當於只是記住一個 API 就可以了。

參數的多態,就是讓 API 的指責會根據參數的情況進行改變。相當於把相似職責的 API 給合併成一個。不需要給用戶提供出太多 API,方便用戶的使用。即使這樣可能違法了單一指責原則,但是呼應了最少知識原則。能讓 API 的使用儘可能簡單化了。

5-1.什麼時候不該設置參數多態

參數多態就是把相似職責的 API 給合併成一個。但是有時候並不適合使用。更適合把合併的 API 拆分成幾個。

比如之前封裝常用 API 的時候。有一個去除字符串空格的 API : ecDo.trim(str,type) (str-待處理的字符串,type-去除空格的類型----1-左右空格,2-所有空格,3-左空格,4-右空格) 。

使用形式

ecDo 是我封裝的一個常用函數庫。
let str=' 守 候 ';
console.log(ecDo.trim(str,1));//'守 候'
console.log(ecDo.trim(str,2));//'守候'
console.log(ecDo.trim(str,3));//'守候 '
console.log(ecDo.trim(str,4));//' 守候'

這樣使用的話,想必大家都看到問題了。1 2 3 4 是什麼鬼?就算知道是什麼鬼,也要把這幾個鬼記住。記憶成本大,調用也不方便。後來就拆分成四個函數了。

let str=' 守 候 ';
console.log(ecDo.trim(str));//'守 候'
console.log(ecDo.trimAll(str));//'守候'
console.log(ecDo.trimLeft(str));//'守候 '
console.log(ecDo.trimRright(str));//' 守候'

這樣雖然多了幾個 API 但是使用起來簡單了。記憶成本也比之前少。是否設置參數多態,還是要看調用的情況而言。

6.小結

好了,關於 API 參數方面的東西就暫時寫到這裏了,這部分的內容不多,所以篇幅不是很長,也容易理解。但是參數這個話題也相對開放,如果大家有什麼好的想法。歡迎在評論區留言。

-------------------------華麗的分割線--------------------

想了解更多,和我交流,內推職位,請添加我微信。或者關注我的微信公衆號:守候書閣

圖片描述圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章