日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

函數柯里化的簡單實現和應用

作者:qq_42750608 更新時間: 2023-10-10 編程語言

一. 柯里化函數實現:

1. 使用函數的length+arguments+apply的相關知識

var slice = Array.prototype.slice
var curry = function (fn) {
    // 拿到fn參數之后的參數
    var args = slice.call(arguments, 1)
    return _curry.apply(this, [fn, fn.length].concat(args))
}

function _curry(fn, len) {
    // 獲取fn, len之外的其他參數
    var oArgs = slice.call(arguments, 2);
    return function () {
        var args = oArgs.concat(slice.call(arguments))
        if (args.length >= len) {
            return fn.apply(this, args)
        }
        else {
            return _curry.apply(this, [fn, len].concat(args))
        }
    }
}

2. 使用函數的length + 擴展運算符...? + apply的知識:

var curry = function (fn, ...arg1) {
    const len = fn.length
    return _curry.apply(this, [fn, len, ...arg1])
}

function _curry(fn, len, ...rest1) {
    return function (...rest2) {
        var args = [...rest1, ...rest2]
        if (args.length >= len) {
            return fn.apply(this, args)
        }
        else {
            return _curry.apply(this, [fn, len].concat(args))
        }
    }
}

實例運用:

測試計算總和的功能:

function calcSum(num1, num2, num3) {
    return num1 + num2 + num3
}

var calcSum2 = function (...args) {
    // const arr = Array.from(arguments);
    const arr = Array.prototype.slice.call(arguments, 0);
    // const arr = Array.of(...args);
    let sum = 0;
    return arr.reduce((obj, cur) => {
        sum = obj + cur
        return sum
    }, sum)
}

const log = console.log
var len1 = 1
var calcSumCurry = _curry(calcSum2, 4)
log(calcSumCurry(3, 4, 5, 6))// 18
log(calcSumCurry(3)(4)(5)(6))//18
log(calcSumCurry(3)(4, 5)(6))//18

var calcSumCurry = curry(calcSum, 3)
log(calcSumCurry(4, 5))//12 
log(calcSumCurry(4)(5))//12

每次只要在最后執行空參函數, 就開始計算, 下一次重新開始

function _curry(fn, len) {
    var oArgs = slice.call(arguments, 2);
    return function () {
        var args = oArgs.concat(slice.call(arguments));
        if (arguments.length === 0) {
            if (args.length >= len) {
                return fn.apply(this, args);
            }
            return console.warn('curry: 參數長度不足')
        }

        return _curry.apply(this, [fn, len].concat(args))
    }
}

var calcSum2 = function (...args) {
    // const arr = Array.from(arguments);
    const arr = Array.prototype.slice.call(arguments, 0);
    // const arr = Array.of(...args);
    let sum = 0;
    return arr.reduce((obj, cur) => {
        sum = obj + cur
        return sum
    }, sum)
}

const log = console.log
var calcSumCurry = _curry(calcSum2, 4)
// 每次都從頭開始算
log(calcSumCurry(3, 4, 5, 6)())// 18
log(calcSumCurry(3)(4)(5)(6)())//18
log(calcSumCurry(3)(4, 5)(6)())//18
log(calcSumCurry(3)(4, 5)()) // curry: 參數長度不足

想要一直累加:

var slice = Array.prototype.slice
function curry(fn, len0) {
    const curArgs = []
    const len = len0 || fn.length
    return function () {
        if (arguments.length === 0) {
            if (curArgs.length >= len) return fn.apply(this, curArgs)

            return console.warn('curry: 參數長度不足')
        }
        Array.prototype.push.apply(curArgs, [].slice.call(arguments));
        return arguments.callee;
    }
}

var calcSum2 = function (...args) {
    // const arr = Array.from(arguments);
    const arr = Array.prototype.slice.call(arguments, 0);
    // const arr = Array.of(...args);
    let sum = 0;
    return arr.reduce((obj, cur) => {
        sum = obj + cur
        return sum
    }, sum)
}

const log = console.log

var calcSumCurry = curry(calcSum2, 4)
log(calcSumCurry(3, 4, 5)())// curry: 參數長度不足
log(calcSumCurry(4)(5)())// 21



嚴格模式下callee會報錯, 可以改成:

'use strict'

var slice = Array.prototype.slice
function curry(fn, len0) {
    const curArgs = []
    const arg2 = []
    const len = len0 || fn.length
    let tag = 'start'
    return function start () {
        if (arguments.length === 0) {
            if (curArgs.length >= len) {
                if(tag === 'end') return console.warn('curry: 參數長度不足, 請核對參數后重試')
                return fn.apply(this, curArgs)
            }
            
            tag = 'end'
            // 只有第一次執行計算的時候才會判斷參數長度是否足夠
            return console.warn('curry: 參數長度不足')
        }
        Array.prototype.push.apply(curArgs, [].slice.call(arguments));
        return start;
    }
}

var calcSum2 = function (...args) {
    const arr = Array.prototype.slice.call(arguments, 0);
    let sum = 0;
    return arr.reduce((obj, cur) => {
        sum = obj + cur
        return sum
    }, sum)
}

const log = console.log

var calcSumCurry = curry(calcSum2, 4)
log(calcSumCurry(3, 4, 5)()) // curry: 參數長度不足
log(calcSumCurry(4)(5)()) // 參數長度不足, 請核對參數后重試

柯里化log方法:

var slice = Array.prototype.slice;
var curry = function (fn, length) {
    var args = slice.call(arguments, 2)
    return _curry.apply(this, [fn, length || fn.length].concat(args))
};

function _curry(fn, len) {
    var oArgs = slice.call(arguments, 2);
    return function () {
        var args = oArgs.concat(slice.call(arguments));
        if (args.length >= len) {
            return fn.apply(this, args);
        } else {
            return _curry.apply(this, [fn, len].concat(args))
        }
    }
}


function log(logLevel, msg) {
    console.log(`${logLevel}:${msg}:::${Date.now()}`)
}

//柯里化log 方法
const curryLog = curry(log);

const debugLog = curryLog("debug");

const errLog = curryLog("error");

//復用參數debug
debugLog("testDebug1");//debug:testDebug1:::1696145622354
debugLog("testDebug2");//debug:testDebug2:::1696145622360

//復用參數error
errLog("testError1");//error:testError1:::1696145622360
errLog("testError2");//error:testError2:::1696145622360

二. 非柯里化的實現方式:

1. 偏函數

偏函數求和:

// 偏函數
function partial(fn) {
    // 接受fn之外的參數
    const args = [].slice.call(arguments, 1)
    return function () {
        // 接收剩余參數
        const newArgs = args.concat([].slice.call(arguments));
        return fn.apply(this, newArgs)
    }
}

function calcSum(...args) {
    const arr = [...args]
    let sum = 0;
    return arr.reduce((obj, cur) => {
        sum = obj + cur
        return sum
    }, sum)
}

// 偏函數是固定一部分參數(一個或者多個參數), 將一個N元函數轉換為一個N-X函數
const pCalcSum = partial(calcSum, 10);
console.log(pCalcSum(11, 12))//33

2. 反柯里化

1.?反柯里化方法的幾種寫法:

Function.prototype.unCurry=function() {
    var self = this
    return function() {
        return Function.prototype.call.apply(self, arguments)
    }
}

Function.prototype.unCurry=function() {
    return this.call.bind(this)
}

Function.prototype.unCurry=function() {
    return (...args) => this.call(...args)
}


2. 反柯里化實例運用:

1) 克隆數組
function unCurry1(fn) {
    return function(context) {
        // this換成傳入的參數context, context之外的參數作為apply的剩余參數
        return fn.apply(context, Array.prototype.slice.call(arguments, 1));
    }
}

Function.prototype.unCurry = function () {
    const self = this
    return function() {
        return Function.prototype.call.apply(self, arguments)
    }
}


// 復制數組
var clone = Array.prototype.slice.unCurry()
var a = [1, 2, 3]
var b = clone(a);

console.log('a == b', a === b); // 除非引用一樣, 否則都是false
console.log(a, b);//[ 1, 2, 3 ] [ 1, 2, 3 ]

var slice = [].slice
var clone = unCurry1(slice)
var a = [1, 2, 3]
var b = clone(a);
console.log('a == b', a === b); // 除非引用一樣, 否則都是false
console.log(a, b);//[ 1, 2, 3 ] [ 1, 2, 3 ]
2) 生成類數組
function unCurry1(fn) {
    return function(context) {
        // this換成傳入的參數context, context之外的參數作為apply的剩余參數
        return fn.apply(context, Array.prototype.slice.call(arguments, 1));
    }
}

Function.prototype.unCurry = function () {
    const self = this
    return function() {
        return Function.prototype.call.apply(self, arguments)
    }
}
var push = Array.prototype.push.unCurry();
var obj = {}
// console.log(Array.prototype.slice.call({0:1, length: 1}, 0))//[1]
push(obj, 4, 5, 6); // 對象變成了類數組
console.log(obj)//{ '0': 4, '1': 5, '2': 6, length: 3 }

var obj = {}
unCurry1([].push)(obj, 7, 8, 9, 10)
console.log(obj)//{ '0': 7, '1': 8, '2': 9, '3': 10, length: 4 }

原文鏈接:https://blog.csdn.net/qq_42750608/article/details/133446241

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新