在下前端小白,近日在刷各類算法/編程題,今天碰到一編程題,考點是apply
,雖然說簡單,但在解題時發現了一個挺有意思的東東,特來分享一下。歡迎各位大佬指點~javascript
話很少說,直接上題目:二次封裝函數。前端
已知函數 fn 執行須要 3 個參數。請實現函數 partial,調用以後知足以下條件: 一、返回一個函數 result,該函數接受一個參數 二、執行 result(str3) ,返回的結果與 fn(str1, str2, str3) 一致
哈哈,這題簡單!稍微學過js的朋友就能寫出來:java
function partial(fn,str1,str2) { var result = function(str3) { return fn(str1,str2,str3); } return result; }
這裏用個call
可能會顯得有點逼格(笑),固然apply
,bind
也能達到同樣的效果。面試
function partial(fn,str1,str2) { var result = function(str3) { return fn.call(null,str1,str2,str3); } return result; }
很少停留,咱們來看下一題,一樣是二次封裝函數:算法
實現函數 partialUsingArguments,調用以後知足以下條件: 一、返回一個函數 result 二、調用 result 以後,返回的結果與調用函數 fn 的結果一致 三、fn 的調用參數爲 partialUsingArguments 的第一個參數以後的所有參數以及 result 的調用參數
emmmmm,傳入的參數不固定? 有了! 用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第一個參數後的全部參數組成的數組,將它和result的全部參數合併起來,利用apply
傳入fn,ok~解決了!數組
誒誒?有意思的東西呢?這特麼一點意思都沒啊。
說出來大家可能不信,其實我看到這題的時候,雖然我想到了用apply
,但我並無想到fn.apply(null,newArguments)
。那我想到的是什麼呢?瀏覽器
Function.prototype.call.apply
app
什麼鬼?我也不知道是在哪看過這東西(也許沒看過),又好像是less
Function.prototype.call.call
?
仍是
Function.prototype.apply.apply
?
仍是
Function.prototype.apply.call
?
好像都差很少,媽個雞,試試就知道了!
return Function.prototype.call.apply(fn,newArguments)
瀏覽器一跑,好像對了?不對!我傳入的第一個參數怎麼不見了?
Google之~ 噢~ 原來第一個參數被吃了。
原來Function.prototype.call.apply(fn,newArguments)
同等於fn.call(a,b,c,...z)
// newArguments = [a,b,c,...z],這裏的...z不是ES6中的...rest
哦,只是表示省略了中間的參數。
知道了原理(並不知道),那就好辦了,我給newArguments數組的頭部補一個元素上去不就行了~
newArguments.unshift(0); Function.prototype.call.apply(fn,newArguments)
瀏覽器一跑——沒毛病老鐵!
完了嗎?
既然.call.apply
能夠用,那其餘3個按理來講也能用,何況這裏多了一步對數組的操做,能不能更優雅一點呢?(另外3個怎麼用,觀衆老爺們內心有答案嗎?)
本着 求知 以及 code less,do more 的精神,我對剩下的3種組合進行了深♂入的研究。
原理其實很簡單,Function.prototype.apply(call)
其實就是一個函數,將視爲一個總體,記做A。原式就能夠轉換成:A.apply(參數)
或A.call(參數)
,而後進一步轉換,參數1.A(參數2)
,什麼參數、參數一、參數2的?
相信你們也看出來了,這裏惟一的難點(?)就是參數。參數怎麼寫呢?
其實很簡單,apply就傳數組,call就傳一個序列。
apply
和call
的區別你們確定知道,我就很少說了。第一個參數確定是fn,這個沒跑了。關鍵就在第二個參數上。
第二個參數,首先它形式上要看後一個apply/call
,若是是apply,咱們就傳數組進去,若是是call,就傳一個序列。而後它的內容就要看A了,也就是前一個apply/call
,同理,若是是apply,就傳數組參數,若是是call,就傳序列參數。
因此咱們能夠得出如下結果:
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])
從而減小了對數組newArguments的操做。
第一次寫文章(水貼),十分緊張,刪了改,改完了刪,總以爲寫的很差、十分囉嗦。
可能會有人以爲毫無心義,但我以爲這個卻是能夠做爲一道面試題。
請在填寫空白內容使等式成立: fn.apply(null,args) = Function.prototype.apply.apply(_____)
若是真的有人遇到,請回來點贊^ ^也但願此文能多少幫助到前端新人,你們一塊兒學習,進步!哪裏要是寫很差能夠直說!幫助我進步。謝謝!不廢話了,完。