JavaScript實現(xiàn)函數(shù)重載的代碼示例
前言
今天開發(fā)一個需求的時候,遇到了一個類似函數(shù)重載的場景。
這個需求可以接收一個下標。
當下標存在時,執(zhí)行邏輯A。
當下標不存在時,執(zhí)行邏輯B。
看著很簡單對吧。
if(index === undefined) {
A()
} else {
B()
}直接一個if else解決,但是我們可以換種思路,通過函數(shù)重載的方式去實現(xiàn)它,后續(xù)如果參數(shù)格式繼續(xù)變化,其拓展性也會更好。
因此就打算實現(xiàn)一個函數(shù),通過js實現(xiàn)函數(shù)重載的能力。
知識鋪墊
在實現(xiàn)函數(shù)重載之前,先回顧下什么是函數(shù)重載?
學過java的朋友當然很熟悉,但學習前端的同學可能就不太熟悉了,因為js并不支持函數(shù)重載。
什么是函數(shù)重載呢?
簡單來說就是 同一個作用域內(nèi)定義多個同名函數(shù)但參數(shù)個數(shù)或類型不同的情況。針對不同的參數(shù)可以定義不同的函數(shù)邏輯,比如:
public class OverloadingExample {
// 函數(shù)重載:整數(shù)相加
public int add(int a, int b) {
return a + b + 1;
}
// 函數(shù)重載:浮點數(shù)相加
public double add(double a, double b) {
return a + b;
}
public static void main(String[] args) {
OverloadingExample example = new OverloadingExample();
System.out.println("Sum of integers: " + example.add(2, 3));
System.out.println("Sum of doubles: " + example.add(2.5, 3.5));
}
}這里的add函數(shù)是存在同名的,但是二者類型不同,會去執(zhí)行不同的代碼。
那對于我們常用的js而言,函數(shù)重載是不支持的。
所以我們一般會采用條件判斷或者對象參數(shù)這種方式實現(xiàn):
// 條件判斷
function exampleFunction(param1, param2 = null) {
if (param2 === null) {
// 處理只有一個參數(shù)的情況
} else {
// 處理兩個參數(shù)的情況
}
}// 參數(shù)對象
function exampleFunction(options) {
if (object.keys(options).length == 1) {
// 處理只有一個參數(shù)的情況
} else {
// 處理多個參數(shù)的情況
}
}// 函數(shù)名稱區(qū)分
function exampleFunctionOneParams(param) {
// 處理只有一個參數(shù)的情況
}
function exampleFunctionTwoParams(param1, param2) {
// 處理只有兩個參數(shù)的情況
}代碼思路
首先在上面的知識鋪墊中,我們知道函數(shù)重載的核心是定義多個同名函數(shù),通過不同的參數(shù)類型或組合執(zhí)行不同的代碼。
思路如下:
1.可以維護一個類,在類中???一個對象,對象中函數(shù)名做key,value是一個新的對象。2.其中新的對象中 又以不同參數(shù)類型組合而成字符串作為key,而對應函數(shù)為value。3.使用時先實例化class。4.將目標函數(shù)和這個目標函數(shù)的參數(shù)集合傳入,實例化對象中新增和目標函數(shù)同名的函數(shù),并將目標函數(shù)和參數(shù)集合注冊到映射對象中。4.使用時,直接調(diào)用實例對象下的目標函數(shù),由目標函數(shù)提供的同名函數(shù)去映射到對應的map中注冊的真實函數(shù)并執(zhí)行。
代碼實現(xiàn)
// 非法賦值標識
let isAssignmentValid = false
class Overload {
constructor() {
this.fnMap = new Proxy({}, {
set: setProxyValid
});
return new Proxy(this, {
set: setProxyValid
});
}
// 重載函數(shù)注冊
reg(fn, arr = []) {
// 注冊函數(shù)映射map
if(typeof fn !== 'function') throw new Error(`params err`);
isAssignmentValid = true
const typesKey = arr.join('_');
if (!this.fnMap[fn.name]) {
this.fnMap[fn.name] = new Proxy({}, {
set: setProxyValid
});
}
this.fnMap[fn.name][typesKey] = fn;
// 注冊重載實例同名函數(shù)
if (!this[fn.name]) {
this[fn.name] = (...args) => {
const typesKey = getParameterTypesKey(...args);
const targetFn = this.fnMap[fn.name][typesKey];
return targetFn(...args);
}
}
isAssignmentValid = false
}
}
// proxy 禁止非法賦值 封裝
function setProxyValid(target, property, value) {
if(isAssignmentValid) {
target[property] = value
return true
} else {
throw new Error(`Cannot set attribute`);
}
}
// 獲取參數(shù)類型key
function getParameterTypesKey(...args) {
const parameterTypes = args.map(arg => typeof arg);
const parameterTypesKey = parameterTypes.join('_');
return parameterTypesKey;
}
// 導出工廠函數(shù)
export function OverloadFactory() {
return new OverloadJS()
}代碼解釋
這段代碼是一個 JavaScript 的重載函數(shù)。
它允許你定義同名函數(shù)但參數(shù)不同的多個版本,然后根據(jù)傳入的參數(shù)類型來自動調(diào)用對應的函數(shù)版本。
步驟一
代碼先定義了一個 isAssignmentValid 標識,表示當前能否對重載實例或類進行賦值。
步驟二
代碼的構造函數(shù)中會創(chuàng)建一個proxy對象 fnMap,這個對象的作用是存儲函數(shù)和參數(shù)集合間的映射關系。
構造函數(shù)最后會返回一個指向this對proxy對象,后續(xù)的注冊和函數(shù)調(diào)用都會在這個proxy實例上進行。注:(代碼中所有的proxy對象,會使用 setProxyValid 函數(shù)對set操作進行封裝,禁止非法賦值,防止開發(fā)時開發(fā)人員誤賦值,導致重載實例異常。)
步驟三
代碼中的reg是重載函數(shù)的注冊函數(shù)也是核心方法。
主要分成兩部分
PART1: (注冊函數(shù)映射map)
注冊函數(shù)接受兩個參數(shù)一個是需要重載的目標函數(shù),一個是目標函數(shù)接受的參數(shù)類型數(shù)組。
首先,代碼使用 typeof 運算符判斷傳入的 fn 是否為一個函數(shù),如果不是,則拋出一個錯誤,提示參數(shù)錯誤。
接下來,將 isAssignmentValid 標志設置為 true ,表示當前處于合法賦值狀態(tài)。這是為了在注冊函數(shù)時允許對 fnMap 進行賦值操作。
然后,通過將參數(shù)數(shù)組 arr 使用 _ 連接起來,生成一個用于標識參數(shù)類型的 key,賦值給變量 typesKey 。
接著,通過檢查 fnMap 中是否存在以 fn.name 為鍵的屬性,來判斷是否已經(jīng)注冊過該函數(shù)。如果不存在,則創(chuàng)建一個新的 Proxy 對象,并將其賦值給 fnMap 中以 fn.name 為鍵的屬性。這個 Proxy 對象的作用是攔截對屬性的賦值操作,以控制賦值的合法性。
最后,將函數(shù) fn 存儲到 fnMap[fn.name][typesKey] 的位置,以完成函數(shù)的注冊和存儲。
這段代碼的作用是在注冊函數(shù)時,將函數(shù)和對應的參數(shù)類型映射存儲起來,以便后續(xù)根據(jù)傳入的參數(shù)類型選擇正確的函數(shù)版本進行調(diào)用。
PART2:(注冊重載實例同名函數(shù))
這段代碼的作用是在注冊函數(shù)時,為重載實例創(chuàng)建同名函數(shù)。
首先,代碼判斷當前實例對象中是否已經(jīng)存在同名函數(shù) fn.name 。如果不存在,則進入條件語句塊。
在條件語句塊中,代碼定義了一個箭頭函數(shù),并將其賦值給實例對象的同名屬性 this[fn.name] 。這個箭頭函數(shù)接受任意數(shù)量的參數(shù) ...args 。
在箭頭函數(shù)內(nèi)部,首先調(diào)用 getParameterTypesKey 函數(shù),傳入?yún)?shù) ...args ,獲取參數(shù)類型的 key,并將其賦值給變量 typesKey 。
接下來,通過訪問 fnMap 屬性,獲取存儲在 fnMap[fn.name][typesKey] 位置的目標函數(shù),并將其賦值給變量 targetFn 。
最后,箭頭函數(shù)調(diào)用 targetFn ,并傳入?yún)?shù) ...args ,返回函數(shù)調(diào)用的結果。 最后一行代碼將 isAssignmentValid 標志設置為 false ,表示結束合法賦值狀態(tài)。
這段代碼的作用是為重載實例創(chuàng)建同名函數(shù),這些同名函數(shù)會根據(jù)傳入的參數(shù)類型選擇對應的函數(shù)版本進行調(diào)用。這樣,在調(diào)用重載函數(shù)時,可以直接通過實例對象的同名屬性來調(diào)用對應的函數(shù)版本。
步驟四
最后導出工廠函數(shù),提供業(yè)務側使用。
基礎使用
創(chuàng)建重載實例
const OverloadInstance = OverloadFactory() // 創(chuàng)建重載實例
注冊同名函數(shù)
OverloadInstance.reg(function exampleFn(param1, param2) { //注冊同名函數(shù)
// 函數(shù)邏輯
}, ['number', 'string'])
OverloadInstance.reg(function exampleFn(param1) {
// 函數(shù)邏輯
}, ['number'])調(diào)用重載函數(shù)
OverloadInstance.exampleFn(20, 'hello world') // 調(diào)用重載函數(shù) OverloadInstance.exampleFn(20)
代碼用例
簡單用例:
let x = OverloadFactory() // 創(chuàng)建重載實例
x.reg(function name(a) { // 注冊同名函數(shù)
console.log(a)
}, ['number'])
x.reg(function name(a, b) {
console.log(a + b)
}, ['number', 'number'])
x.reg(function text(a) {
console.log(a)
}, ['string'])
x.reg(function text(a, b) {
console.log(a + b)
}, ['string', 'number'])
x.name(20, 10) // 函數(shù)調(diào)用
x.name(20)
x.text('hello', 10)
x.text('hello')運行結果:

代碼缺陷
1.getParameterTypesKey 函數(shù)的類型判斷太簡單。2.重載實例取空值異常處理缺失
總結
這段代碼實現(xiàn)了一個重載函數(shù)庫,它允許你定義同名函數(shù)但參數(shù)不同的多個版本,并根據(jù)傳入的參數(shù)類型自動選擇調(diào)用對應的函數(shù)版本。
以上就是JavaScript實現(xiàn)函數(shù)重載的代碼示例的詳細內(nèi)容,更多關于JavaScript實現(xiàn)函數(shù)重載的資料請關注腳本之家其它相關文章!
相關文章
Jquery+javascript實現(xiàn)支付網(wǎng)頁數(shù)字鍵盤
這篇文章主要為大家詳細介紹了Jquery+javascript實現(xiàn)支付網(wǎng)頁數(shù)字鍵盤,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-12-12
基于js實現(xiàn)的限制文本框只可以輸入數(shù)字
本文主要介紹了js限制文本框只可以輸入數(shù)字的實例代碼,可復制直接調(diào)用函數(shù)實現(xiàn)其功能。需要的朋友可以看下2016-12-12
html5 canvas js(數(shù)字時鐘)實例代碼
這篇文章主要介紹了html5 canvas js(數(shù)字時鐘)實例代碼,有需要的朋友可以參考一下2013-12-12
IE8 下的Js錯誤HTML Parsing Error...
今天調(diào)試一段JS代碼出現(xiàn)這個狀況..在火狐 IE7 和IE6下都正常...郁悶,在網(wǎng)上搜索了一下相關資料 一般錯誤都是指所指定的標簽沒有加載完就是用該對象....2009-08-08

