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

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

