一個關於柯里化函數的實現解析

本篇內容主要參考瞭如下文章:
從 sum(2)(3) == sum(2, 3) 到實現柯里化函數
JavaScript專題之函數柯里化

柯里化定義

在數學和計算機科學中,柯里化是一種將使用多個參數的一個函數轉換成一系列使用一個參數的函數的技術。

一個柯里化函數的實現

在上面兩篇文章中,兩位做者都比較詳細的分析了柯里化函數的實現方式,特別是冴羽的文章中給出了詳細的從零開始實現柯里化函數的方法,在這裏我就再也不贅述了。segmentfault

在這裏我主要針對上面第一個文章中的實現方法,進行一下執行過程的分析。主要是針對其中的具體的一些執行過程單獨看代碼仍是不甚明瞭,特此詳細執行分析一下以做理解,加深記憶。app

實現方式

這個方式是我感受最容易接受的函數

function curry(fn, argLen, currArgs) {
    return function() {
        console.log("arguments:", arguments, arguments.length)
        var args = [].slice.call(arguments);
        console.log("args:", args)
        // 首次調用時未提供最後一個參數
        if (currArgs !== undefined) {
            args = args.concat(currArgs);
        }
        // 遞歸出口
        if (args.length == argLen) {
            return fn.apply(this, args);
        } else {
            return curry(fn, argLen, args);
        }
    }
}

function sumOf(a, b, c, d) {
    return a + b + c + d;
}

// 改造普通函數,返回柯里函數
var sum = curry(sumOf, 4);

下面咱們分別來看一下幾種不一樣的傳參方式的執行過程是怎麼樣的優化

sum(1,2,3,4)

>sum(1,2,3,4)
arguments: Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ] 4
args: (4) [1, 2, 3, 4]

sum(1,2,3)(4)

>sum(1,2,3)(4)
arguments: Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ] 3
args: (3) [1, 2, 3]
arguments: Arguments [4, callee: ƒ, Symbol(Symbol.iterator): ƒ] 1
args: [4]

sum(1,2)(3,4)

>sum(1,2)(3,4)
arguments: Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ] 2
args: (2) [1, 2]
arguments: Arguments(2) [3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ] 2
args: (2) [3, 4]

經過上面針對幾種傳參方式的執行過程的分析,咱們能夠清楚地看出其中一些關鍵變量的內容,這樣就讓咱們可以清楚地理解了柯里化函數的執行過程this

我的優化

針對上面的執行方式,咱們能夠看出除了須要被柯里化的函數外,還須要根據這個函數的參數數量傳入對應的數量值,這個並非那麼的方便。不妨改進一下code

function curry(fn, currArgs) {
    return function() {
        console.log("arguments:", arguments, arguments.length)
        var args = [].slice.call(arguments);
        console.log("args:", args)
        // 首次調用時未提供最後一個參數
        if (currArgs !== undefined) {
            args = args.concat(currArgs);
        }
        // 遞歸出口
        if (args.length == fn.length) {
            return fn.apply(this, args);
        } else {
            return curry(fn, args);
        }
    }
}

這裏咱們經過利用length 屬性指明函數的形參個數,來獲取被柯里化函數的參數數量,這樣就不須要咱們在額外傳入了。可是此時須要注意的是,被柯里化的函數的參數不能有默認值,否則的話,length屬性就沒有意義了。因此這個方式也不是完美的。遞歸

小結

簡單來講,實現柯里化函數的方式基本都會須要根據參數以及遞歸方式來實現,這樣才能讓咱們經過拆分參數的方式來調用一個多參數的函數方法。這樣的好處是減小重複傳遞不變的部分參數,將柯里化後的callback參數傳遞給map, filter等函數ip

var persons = [{name: 'kevin', age: 11}, {name: 'daisy', age: 24}]

let getProp = _.curry(function (key, obj) {
    return obj[key]
});
let names2 = persons.map(getProp('name'))
console.log(names2); //['kevin', 'daisy']

let ages2 = persons.map(getProp('age'))
console.log(ages2); //[11,24]

可是也不得不認可,這是個很是高階的用法,普通的開發場景中不多會被使用,畢竟理解並非那麼的簡單。開發

相關文章
相關標籤/搜索