你應該知道的柯里化

函數是一等公民

在JS裏函數是一等公民,它跟其餘類型(字符,數字,數組,對象)等同樣,都是能夠直接當成參數傳遞或者當成返回值返回的。活用函數是一個前端開發必備的基礎技能。javascript

舉個簡單的例子,假設咱們要打印出一個數組的全部元素的話,大部分人可能會這樣作:前端

function printWithLoop(arr) {
    for (let i = 0, len = arr.length; i < len; i++) {
        console.dir(arr[i]);
    }
}複製代碼

當你對高階函數(higher-order function)有一點了解以後,你可能會習慣用forEach:java

function printWithIterator(arr) {
    (arr || []).forEach(it => {
        console.dir(it);
    });
}複製代碼

上面的例子又能夠進一步優化爲:git

function simplePrint(arr) {
    (arr || []).forEach(console.dir);
}複製代碼

此處能夠有道面試題:若是上面的console.dir替換成console.log的話上面3種作法仍是等價的麼?github

函數柯里化

柯里化,又稱部分求值,簡單的說就是在函數運行時把參數吃進來,並同時返回一個新的函數(該函數經過閉包的特性能夠訪問到前面調用時吃進來的參數),供後續調用。web

形參 vs 實參

柯里化跟參數息息相關。參數有2個概念:面試

  • 形參(parameters): 函數定義時的佔位符。可經過function.length獲得形參個數
function A(a, b) {}
// a跟b就是形參
console.log(A.length); //2複製代碼
  • 實參(arguments): 函數調用時傳進來的參數。可經過arguments得到
function B(a, b) {
    console.log(arguments);
}

B(1,2,3); // 1,2,3複製代碼

形參就是這個函數指望的參數,實參就是這個函數調用時實際獲得的參數。有了這2個數據咱們就能夠作不少事情了。數組

簡單的柯里化小例子

假設咱們有個求3個數字之和的函數:閉包

function sum(x, y, z) {
    console.log(x + y + z);
}

sum(1,2,3); //6複製代碼

若是我想實現下面這樣的效果:app

sum(1,2,3); //6
sum(1)(2,3); //6
sum(1,2)(3); //6複製代碼

思考一下規律,其實就是當sum函數獲得了它指望的參數(i.e. 3個參數)時,它就返回結果。要否則就返回一個新的函數(e.g. sum(1)跟sum(1,2))持續吃進新參數。這時候就用到柯里化的思想。

function curry(fn) { //暫時不考慮上下文this的狀況
    return function f(...args) {
        //傳進來的參數個數很多於形參個數,調用並返回結果
        if(args.length >= fn.length) { 
            return fn.apply(this, args);
        } else {
            //傳進來的參數個數少於形參個數,返回一個閉包
            return function(...arr) { 
                return f.apply(this, args.concat(arr));
            }
        }
    }
}

let sumWithCurry = curry(sum);
sumWithCurry(1,2,3); //6
sumWithCurry(1)(2,3); //6
sumWithCurry(1,2)(3); //6複製代碼

bind

Function.prototype.bind方法除了有綁定執行語境this的功能外,還有柯里化的功能。

function sayHi(greeting, ending) {
    console.log(`My name is ${this.name}, ${greeting}. ${ending}!`);
}

//這裏已經把greeting吃進去了
let fn = sayHi.bind({name: 'mike'}, 'Love you'); 
fn('Thanks!'); // My name is mike, Love you. Thanks!!複製代碼

實際工做中能夠巧用柯里化去寫更優雅的代碼。

function print(arr) {
    console.log(arr.join('|'));
}

let arr = [1,2,3];
setTimeout(function(){
    print([1,2,3]);
}, 1000);
// 1|2|3複製代碼

等價於

function print(arr) {
    console.log(arr.join('|'));
}

let arr = [1,2,3];
setTimeout(print.bind(null, arr), 1000);
// 1|2|3複製代碼

Reference

Notice

  • 若是您以爲該Repo讓您有所收穫,請「Star 」支持樓主。
  • 若是您想持續關注樓主的最新系列文章,請「Watch」訂閱
相關文章
相關標籤/搜索