摘要:背景在下前端小白,近日在刷各種算法編程題,今天碰到一編程題,考點是,雖說簡單,但在解題時發(fā)現(xiàn)了一個挺有意思的東東,特來分享一下。分析及結(jié)論如下原理其實很簡單,其實就是一個函數(shù),將視為一個整體,記作。
背景
在下前端小白,近日在刷各種算法/編程題,今天碰到一編程題,考點是apply,雖說簡單,但在解題時發(fā)現(xiàn)了一個挺有意思的東東,特來分享一下。歡迎各位大佬指點~
正文話不多說,直接上題目:二次封裝函數(shù)。
已知函數(shù) fn 執(zhí)行需要 3 個參數(shù)。請實現(xiàn)函數(shù) partial,調(diào)用之后滿足如下條件: 1、返回一個函數(shù) result,該函數(shù)接受一個參數(shù) 2、執(zhí)行 result(str3) ,返回的結(jié)果與 fn(str1, str2, str3) 一致
哈哈,這題簡單!稍微學(xué)過js的朋友就能寫出來:
function partial(fn,str1,str2) { var result = function(str3) { return fn(str1,str2,str3); } return result; }
這里用個call可能會顯得有點逼格(笑),當(dāng)然apply,bind也能達到一樣的效果。
function partial(fn,str1,str2) { var result = function(str3) { return fn.call(null,str1,str2,str3); } return result; }
不多停留,我們來看下一題,同樣是二次封裝函數(shù):
實現(xiàn)函數(shù) partialUsingArguments,調(diào)用之后滿足如下條件: 1、返回一個函數(shù) result 2、調(diào)用 result 之后,返回的結(jié)果與調(diào)用函數(shù) fn 的結(jié)果一致 3、fn 的調(diào)用參數(shù)為 partialUsingArguments 的第一個參數(shù)之后的全部參數(shù)以及 result 的調(diào)用參數(shù)
emmmmm,傳入的參數(shù)不固定? 有了! 用arguments~
function partialUsingArguments(fn) { var _arguments = Array.prototype.slice.call(arguments,1) var result = function() { var newArguments = _arguments.concat(Array.prototype.slice.call(arguments,0)); return fn.apply(null,newArguments) } return result; }
唔,好像也沒什么難的,_arguments就是partialUsingArguments第一個參數(shù)后的所有參數(shù)組成的數(shù)組,將它和result的所有參數(shù)合并起來,利用apply傳入fn,ok~解決了!
誒誒?有意思的東西呢?這特么一點意思都沒啊。
說出來你們可能不信,其實我看到這題的時候,雖然我想到了用apply,但我并沒有想到fn.apply(null,newArguments)。那我想到的是什么呢?
Function.prototype.call.apply
什么鬼?我也不知道是在哪看過這東西(也許沒看過),又好像是
Function.prototype.call.call?
還是
Function.prototype.apply.apply?
還是
Function.prototype.apply.call?
好像都差不多,媽個雞,試試就知道了!
return Function.prototype.call.apply(fn,newArguments)
瀏覽器一跑,好像對了?不對!我傳入的第一個參數(shù)怎么不見了?
Google之~ 噢~ 原來第一個參數(shù)被吃了。
原來Function.prototype.call.apply(fn,newArguments)同等于fn.call(a,b,c,...z) // newArguments = [a,b,c,...z],這里的...z不是ES6中的...rest哦,只是表示省略了中間的參數(shù)。
知道了原理(并不知道),那就好辦了,我給newArguments數(shù)組的頭部補一個元素上去不就好了~
newArguments.unshift(0); Function.prototype.call.apply(fn,newArguments)
瀏覽器一跑——沒毛病老鐵!
完了嗎?
并沒有!既然.call.apply可以用,那其他3個按理來說也能用,況且這里多了一步對數(shù)組的操作,能不能更優(yōu)雅一點呢?(另外3個怎么用,觀眾老爺們心里有答案嗎?)
本著 求知 以及 code less,do more 的精神,我對剩下的3種組合進行了深♂入的研究。
原理其實很簡單,Function.prototype.apply(call)其實就是一個函數(shù),將視為一個整體,記作A。原式就可以轉(zhuǎn)換成:A.apply(參數(shù))或A.call(參數(shù)),然后進一步轉(zhuǎn)換,參數(shù)1.A(參數(shù)2),什么參數(shù)、參數(shù)1、參數(shù)2的?
相信大家也看出來了,這里唯一的難點(?)就是參數(shù)。參數(shù)怎么寫呢?
其實很簡單,apply就傳數(shù)組,call就傳一個序列。
apply和call的區(qū)別大家肯定知道,我就不多說了。第一個參數(shù)肯定是fn,這個沒跑了。關(guān)鍵就在第二個參數(shù)上。
第二個參數(shù),首先它形式上要看后一個apply/call,如果是apply,我們就傳數(shù)組進去,如果是call,就傳一個序列。然后它的內(nèi)容就要看A了,也就是前一個apply/call,同理,如果是apply,就傳數(shù)組參數(shù),如果是call,就傳序列參數(shù)。
所以我們可以得出以下結(jié)果:
Function.prototype.apply.apply(fn,[null,newArguments]) Function.prototype.call.call(fn,null,...newArguments]) Function.prototype.apply.call(fn,null,newArguments]) //上面3式可以實際上等于 fn.apply(null,newArguments) fn.call(null,...newArguments) //...為擴展運算符,...[arr] = arr[0],arr[1],...arr[n] fn.apply(null,newArguments)
繞了一大圈,又回來了~ :)
而上面的Function.prototype.call.apply也可以改寫成:
Function.prototype.call.apply(fn,[null,...newArguments])
從而減少了對數(shù)組newArguments的操作。
寫在最后第一次寫文章(水貼),十分緊張,刪了改,改完了刪,總覺得寫的不好、十分啰嗦。
可能會有人覺得毫無意義,但我覺得這個倒是可以作為一道面試題。
請在填寫空白內(nèi)容使等式成立: fn.apply(null,args) = Function.prototype.apply.apply(_____)
如果真的有人遇到,請回來點贊^ ^
也希望此文能多少幫助到前端新人,大家一起學(xué)習(xí),進步!
哪里要是寫不好可以直說!幫助我進步。謝謝!
不廢話了,
完。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/84119.html