JavaScript實(shí)現(xiàn)函數(shù)重載的代碼示例
前言
今天開(kāi)發(fā)一個(gè)需求的時(shí)候,遇到了一個(gè)類(lèi)似函數(shù)重載
的場(chǎng)景。
這個(gè)需求可以接收一個(gè)下標(biāo)。
當(dāng)下標(biāo)存在時(shí),執(zhí)行邏輯A。
當(dāng)下標(biāo)不存在時(shí),執(zhí)行邏輯B。
看著很簡(jiǎn)單對(duì)吧。
if(index === undefined) { A() } else { B() }
直接一個(gè)if else
解決,但是我們可以換種思路,通過(guò)函數(shù)重載的方式去實(shí)現(xiàn)它,后續(xù)如果參數(shù)格式繼續(xù)變化,其拓展性也會(huì)更好。
因此就打算實(shí)現(xiàn)一個(gè)函數(shù),通過(guò)js實(shí)現(xiàn)函數(shù)重載的能力。
知識(shí)鋪墊
在實(shí)現(xiàn)函數(shù)重載之前,先回顧下什么是函數(shù)重載?
學(xué)過(guò)java的朋友當(dāng)然很熟悉,但學(xué)習(xí)前端的同學(xué)可能就不太熟悉了,因?yàn)?code>js并不支持函數(shù)重載。
什么是函數(shù)重載呢?
簡(jiǎn)單來(lái)說(shuō)就是 同一個(gè)作用域內(nèi)定義多個(gè)同名函數(shù)但參數(shù)個(gè)數(shù)或類(lèi)型不同的情況。
針對(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ù)是存在同名的,但是二者類(lèi)型不同,會(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ù),通過(guò)不同的參數(shù)類(lèi)型或組合執(zhí)行不同的代碼。
思路如下:
1.可以維護(hù)一個(gè)類(lèi),在類(lèi)中???一個(gè)對(duì)象,對(duì)象中函數(shù)名做key,value是一個(gè)新的對(duì)象。2.其中新的對(duì)象中 又以不同參數(shù)類(lèi)型組合而成字符串作為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ù)類(lèi)型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ù)類(lèi)型來(lái)自動(dòng)調(diào)用對(duì)應(yīng)的函數(shù)版本。
步驟一
代碼先定義了一個(gè) isAssignmentValid
標(biāo)識(shí),表示當(dāng)前能否對(duì)重載實(shí)例或類(lèi)進(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)行封裝,禁止非法賦值,防止開(kāi)發(fā)時(shí)開(kāi)發(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ù)類(lèi)型數(shù)組。
首先,代碼使用 typeof
運(yùn)算符判斷傳入的 fn
是否為一個(gè)函數(shù),如果不是,則拋出一個(gè)錯(cuò)誤,提示參數(shù)錯(cuò)誤。
接下來(lái),將 isAssignmentValid
標(biāo)志設(shè)置為 true
,表示當(dāng)前處于合法賦值狀態(tài)。這是為了在注冊(cè)函數(shù)時(shí)允許對(duì) fnMap
進(jìn)行賦值操作。
然后,通過(guò)將參數(shù)數(shù)組 arr
使用 _
連接起來(lái),生成一個(gè)用于標(biāo)識(shí)參數(shù)類(lèi)型的 key,賦值給變量 typesKey
。
接著,通過(guò)檢查 fnMap
中是否存在以 fn.name
為鍵的屬性,來(lái)判斷是否已經(jīng)注冊(cè)過(guò)該函數(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ù)類(lèi)型映射存儲(chǔ)起來(lái),以便后續(xù)根據(jù)傳入的參數(shù)類(lèi)型選擇正確的函數(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)入條件語(yǔ)句塊。
在條件語(yǔ)句塊中,代碼定義了一個(gè)箭頭函數(shù),并將其賦值給實(shí)例對(duì)象的同名屬性 this[fn.name]
。這個(gè)箭頭函數(shù)接受任意數(shù)量的參數(shù) ...args
。
在箭頭函數(shù)內(nèi)部,首先調(diào)用 getParameterTypesKey
函數(shù),傳入?yún)?shù) ...args
,獲取參數(shù)類(lèi)型的 key,并將其賦值給變量 typesKey
。
接下來(lái),通過(guò)訪問(wèn) 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ù)類(lèi)型選擇對(duì)應(yīng)的函數(shù)版本進(jìn)行調(diào)用。這樣,在調(diào)用重載函數(shù)時(shí),可以直接通過(guò)實(shí)例對(duì)象的同名屬性來(lái)調(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)
代碼用例
簡(jiǎn)單用例:
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ù)的類(lèi)型判斷太簡(jiǎn)單。2.重載實(shí)例取空值異常處理缺失
總結(jié)
這段代碼實(shí)現(xiàn)了一個(gè)重載函數(shù)庫(kù),它允許你定義同名函數(shù)但參數(shù)不同的多個(gè)版本,并根據(jù)傳入的參數(shù)類(lèi)型自動(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)頁(yè)數(shù)字鍵盤(pán)
這篇文章主要為大家詳細(xì)介紹了Jquery+javascript實(shí)現(xiàn)支付網(wǎng)頁(yè)數(shù)字鍵盤(pán),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12基于js實(shí)現(xiàn)的限制文本框只可以輸入數(shù)字
本文主要介紹了js限制文本框只可以輸入數(shù)字的實(shí)例代碼,可復(fù)制直接調(diào)用函數(shù)實(shí)現(xiàn)其功能。需要的朋友可以看下2016-12-12JS打斷點(diǎn)的六種常用姿勢(shì)你用過(guò)幾種
JS斷點(diǎn)調(diào)試,即是在瀏覽器開(kāi)發(fā)者工具中為JS代碼添加斷點(diǎn),讓JS執(zhí)行到某一特定位置停住,方便開(kāi)發(fā)者對(duì)該處代碼段的分析,這篇文章主要介紹了JS打斷點(diǎn)的六種常用姿勢(shì)的相關(guān)資料,需要的朋友可以參考下2025-04-04html5 canvas js(數(shù)字時(shí)鐘)實(shí)例代碼
這篇文章主要介紹了html5 canvas js(數(shù)字時(shí)鐘)實(shí)例代碼,有需要的朋友可以參考一下2013-12-12JS生成登錄驗(yàn)證碼的實(shí)現(xiàn)示例
本文主要介紹了JS生成登錄驗(yàn)證碼的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12IE8 下的Js錯(cuò)誤HTML Parsing Error...
今天調(diào)試一段JS代碼出現(xiàn)這個(gè)狀況..在火狐 IE7 和IE6下都正常...郁悶,在網(wǎng)上搜索了一下相關(guān)資料 一般錯(cuò)誤都是指所指定的標(biāo)簽沒(méi)有加載完就是用該對(duì)象....2009-08-08