從一道坑人的面試題說函數語言程式設計

發表於2017-03-29

一道著名的坑人題,可能一些同學見過:


說出上面程式碼的執行結果。

如果不過腦子的說是 [2, 3, 4],那麼肯定是錯了。實際上,真正的執行結果是 [2, NaN, NaN]。為什麼會這樣呢?是因為 map 的運算元是有兩個引數的,第一個引數是被迭代陣列的元素,第二個引數是該元素的下標。所以 ['2', '3', '4'].map(parseInt) 實際上相當於執行了 [parseInt('2', 0), parseInt('3', 1), parseInt('4', 2)],結果就變成了 [2, NaN, NaN] 了。

今天我們在這裡主要不是討論為什麼 parseInt('2', 0) 是 2,而 parseInt('3', 1) 是 NaN,實際上我們期望的結果應該是 parseInt('2', 10)parseInt('3', 10),把字串 ‘2’、’3′ 轉成十進位制 number。

所以,正確的寫法應該是:

上面這個寫法對於這個問題來說是簡單的,和函數語言程式設計關係不大。但是,這個問題如果用過程抽象的思路通用化思考,應該是這樣的:

其中 bindRight 和 bind 方法是相反的,bindRight 相當於從右往左 bind:

要實現 bindRight,考慮各種情況,稍稍有些複雜,但也並不太麻煩:

這樣就實現了我們需要的 bindRight,完整的結果如下:

Function.prototype.bindRight

bindRight 程式碼並不複雜,如果 bindRight 的引數個數比函式形參多,那麼簡單將引數次序 reverse 之後傳給原來的函式,否則將函式前面的引數補齊。

除了這樣實現 bindRight 之外,還可以有利用更基礎的高階函式操作組合的方式:

上面的這段程式碼裡我們通過 reverseArgs 和 fixArgsLength 以及 bind 來組合出 bindRight。reverseArgs 是將函式引數順序倒序的高階函式,fixArgsLength 是將函式引數個數固定的高階函式,我們可以看到 bindRight 就是先 reverseArgs 再 bind,最後 fixArgsLength(大家可以思考下為什麼要 fixArgsLength)。這樣就可以了。

不過話說,就上面這個問題直接用 fixArgsLength 也可以——

最後是完整程式碼:

bindRight functional

如有任何問題,歡迎討論。

相關文章