詳解如何通過JavaScript實現(xiàn)函數(shù)重載
有的同學(xué)在開發(fā)中可能遇到過一個困擾,但是很少有人去解決這個問題,我這用一個例子展現(xiàn)出來
const searcher = {}; searcher.findAll = () => { console.log("查詢所有用戶"); }; searcher.findByName = (name) => { console.log("按照用戶名稱查詢"); }; searcher.findByFirstNameAndLastName = (firstName, lastName) => { console.log("按照姓和名用戶查詢"); };
可以看到上方的searcher
對象有三個方法,但是他的查詢邏輯是不一樣。 findAll
查詢所有用戶;findByName
按照用戶名查;findByFirstNameAndLastName
是按照姓和名查詢用戶,結(jié)構(gòu)上沒任何問題,那問題在哪?,惡心因為都是在做查詢,但又不得不給每一個函數(shù)取不同的名字,因為一旦重名就覆蓋了,如果說他們能取一樣的名字那該有多好
searcher.find = () => { console.log("查詢所有用戶"); }; searcher.find = (name) => { console.log("按照用戶名稱查詢"); }; searcher.find = (firstName, lastName) => { console.log("按照姓和名用戶查詢"); };
不傳參數(shù)就是查所有用戶
searcher.find()
給一個參數(shù)就是按照用戶名來查詢
searcher.find("aa")
給兩個參數(shù)就是按照用戶的姓跟名來查詢
searcher.find("aa", "bb")
到用得時候也是非常的簡單,也符合邏邏輯,這個就叫做函數(shù)重載
函數(shù)重載:就是給函數(shù)取同一樣的一個函數(shù)名,根據(jù)你傳遞不同的參數(shù)數(shù)量,分別去調(diào)用不同的函數(shù)
好處:就在于使用不同的邏輯產(chǎn)生的函數(shù),給他們?nèi)∫粋€相同的名字,這樣在使用上我只需要記住這個一樣的名字就可以了,而不用去記這三個不同的名字,他有效的降低調(diào)用函數(shù)時產(chǎn)生的心智負擔(dān)。
但是JS不支持函數(shù)重載,所以說如果你寫成已上的形式,無論你怎么調(diào)用,一定是調(diào)用最后一個函數(shù),因為最后一個函數(shù)把前面的全部覆蓋了
不傳參數(shù)試一下,你看永遠都是走最后一個函數(shù)的log
searcher.find() // 按照姓和名用戶查詢
那有什么辦法呢?在很早的時候jQuery之父John Resig 他就已經(jīng)提出了一個想法,我們能不能實現(xiàn)一個方法來幫助我們在js中完成函數(shù)重載?
于是他想出了一個addMethod
方法,就是當我要重載的時,我不直接去定義函數(shù),因為直接定義函數(shù)就會出現(xiàn)一個永遠只調(diào)用最后一個函數(shù)的問題,而調(diào)用addMethod
來定義函數(shù),把對象傳進去,把函數(shù)的名字傳進去,把函數(shù)的實現(xiàn)傳進去,后面依次同理
addMethod(searcher, 'find', () => { console.log('查詢所有用戶') }) addMethod(searcher, 'find', (name) => { console.log('按照用戶名稱查詢') }) addMethod(searcher, 'find', (firstName, lastName) => { console.log('按照姓和名用戶查詢') })
寫成這種格式之后,后面調(diào)用searcher.find()
就能夠完成函數(shù)重載,問題是這個方法我們得要自己實現(xiàn),那么如何來實現(xiàn)? 這個方法他接受三個參數(shù),如果你不加處理的話你可能寫成下面函數(shù)一樣,給對象加一個屬性,這個屬性等于一個函數(shù),調(diào)用這個函數(shù)實際上就是在運行定義的實現(xiàn)函數(shù)fn
,把this
綁定帶過去 然后把傳遞過來的arguments
帶過去
function addMethod(object, name, fn) { object[name] = function () { fn.apply(this, arguments) } }
僅僅這么些還是搞不定,因為每次調(diào)用addMethod
最后一次調(diào)用一定會把object里面同一個屬性給覆蓋掉,那么如何處理?看下方代碼
function addMethod(object, name, fn) { const old = object[name]; object[name] = function () { if (arguments.length === fn.length) { fn.apply(this, arguments); } else if (typeof old === "function") { old.apply(this, arguments); } }; }
首先我不傳參數(shù)走查詢所有用戶,傳一個參數(shù)走按照用戶名查詢,傳兩個參數(shù)按照姓和名查詢
直接看方法體有的同學(xué)可能不理解其中的巧妙,我來研究一下這個方法并記錄一下執(zhí)行規(guī)則
第一次調(diào)用: 通過 old
變量首先保存了之前成員的值,當然這一次保存由于是第一次調(diào)用,所以他是一個undefined
然后給object[name]
賦值了一個新的函數(shù),這個函數(shù)在運行的時候做了一個判斷,當你傳遞的實參數(shù)量與你定義函數(shù)形參數(shù)量一致的時候就執(zhí)行該函數(shù)由此可得:
第二次調(diào)用:關(guān)鍵是否則,判斷一下old
是否是函數(shù),如果是那調(diào)用old
就會執(zhí)行上面第一次得出的邏輯,同理可得:
第三次調(diào)用:同理可得:
以上是一個注冊的順序,當我們調(diào)用時傳遞0個參數(shù),他會從最后一個開始執(zhí)行,當形參數(shù)量相等就會直接執(zhí)行當前的方法,如果不相等就會執(zhí)行old
也就是上一個find
的邏輯,類似于冒泡執(zhí)行,等到執(zhí)行到第一次注冊的邏輯判斷時形參數(shù)量相等了,就直接執(zhí)行第一次注冊的方法,執(zhí)行打印 "查詢所有用戶"
searcher.find() // 查詢所有用戶
總結(jié)
其實就是用到了閉包,將閉包形成了閉包鏈把我們傳遞的方法依次注冊。在調(diào)用的時候從最后一個有序的去找,用這種非常巧妙的方式,用極少的代碼就實現(xiàn)了一個函數(shù)重載的效果,函數(shù)重載雖然說你不一定能用到,但是通過去解析這個addMethod
,我們可以感受到有這么智慧的實現(xiàn)方案,肯定對你將來實現(xiàn)某一些東西的時候,有所啟發(fā)。
到此這篇關(guān)于詳解如何通過JavaScript實現(xiàn)函數(shù)重載的文章就介紹到這了,更多相關(guān)JavaScript函數(shù)重載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解JavaScript數(shù)組和字符串中去除重復(fù)值的方法
這篇文章主要介紹了詳解JavaScript數(shù)組和字符串中去除重復(fù)值的方法,及利用各種限制條件對數(shù)組和字符串進行過濾,需要的朋友可以參考下2016-03-03JavaScript高級程序設(shè)計 客戶端存儲學(xué)習(xí)筆記
JavaScript高級程序設(shè)計 客戶端存儲學(xué)習(xí)筆記,在客戶端用于存儲會話信息2011-09-09JavaScript中數(shù)組的排序、亂序和搜索實現(xiàn)代碼
JavaScript中實現(xiàn)數(shù)組的排序、亂序和搜索,其實所有這些功能,用一個sort()就可以完成了2011-11-11