• 函数柯里化的简单实现和应用


    一. 柯里化函数实现:

    1. 使用函数的length+arguments+apply的相关知识

    1. var slice = Array.prototype.slice
    2. var curry = function (fn) {
    3. // 拿到fn参数之后的参数
    4. var args = slice.call(arguments, 1)
    5. return _curry.apply(this, [fn, fn.length].concat(args))
    6. }
    7. function _curry(fn, len) {
    8. // 获取fn, len之外的其他参数
    9. var oArgs = slice.call(arguments, 2);
    10. return function () {
    11. var args = oArgs.concat(slice.call(arguments))
    12. if (args.length >= len) {
    13. return fn.apply(this, args)
    14. }
    15. else {
    16. return _curry.apply(this, [fn, len].concat(args))
    17. }
    18. }
    19. }

    2. 使用函数的length + 扩展运算符...  + apply的知识:

    1. var curry = function (fn, ...arg1) {
    2. const len = fn.length
    3. return _curry.apply(this, [fn, len, ...arg1])
    4. }
    5. function _curry(fn, len, ...rest1) {
    6. return function (...rest2) {
    7. var args = [...rest1, ...rest2]
    8. if (args.length >= len) {
    9. return fn.apply(this, args)
    10. }
    11. else {
    12. return _curry.apply(this, [fn, len].concat(args))
    13. }
    14. }
    15. }

    实例运用:

    测试计算总和的功能:

    1. function calcSum(num1, num2, num3) {
    2. return num1 + num2 + num3
    3. }
    4. var calcSum2 = function (...args) {
    5. // const arr = Array.from(arguments);
    6. const arr = Array.prototype.slice.call(arguments, 0);
    7. // const arr = Array.of(...args);
    8. let sum = 0;
    9. return arr.reduce((obj, cur) => {
    10. sum = obj + cur
    11. return sum
    12. }, sum)
    13. }
    14. const log = console.log
    15. var len1 = 1
    16. var calcSumCurry = _curry(calcSum2, 4)
    17. log(calcSumCurry(3, 4, 5, 6))// 18
    18. log(calcSumCurry(3)(4)(5)(6))//18
    19. log(calcSumCurry(3)(4, 5)(6))//18
    20. var calcSumCurry = curry(calcSum, 3)
    21. log(calcSumCurry(4, 5))//12
    22. log(calcSumCurry(4)(5))//12

    每次只要在最后执行空参函数, 就开始计算, 下一次重新开始

    1. function _curry(fn, len) {
    2. var oArgs = slice.call(arguments, 2);
    3. return function () {
    4. var args = oArgs.concat(slice.call(arguments));
    5. if (arguments.length === 0) {
    6. if (args.length >= len) {
    7. return fn.apply(this, args);
    8. }
    9. return console.warn('curry: 参数长度不足')
    10. }
    11. return _curry.apply(this, [fn, len].concat(args))
    12. }
    13. }
    14. var calcSum2 = function (...args) {
    15. // const arr = Array.from(arguments);
    16. const arr = Array.prototype.slice.call(arguments, 0);
    17. // const arr = Array.of(...args);
    18. let sum = 0;
    19. return arr.reduce((obj, cur) => {
    20. sum = obj + cur
    21. return sum
    22. }, sum)
    23. }
    24. const log = console.log
    25. var calcSumCurry = _curry(calcSum2, 4)
    26. // 每次都从头开始算
    27. log(calcSumCurry(3, 4, 5, 6)())// 18
    28. log(calcSumCurry(3)(4)(5)(6)())//18
    29. log(calcSumCurry(3)(4, 5)(6)())//18
    30. log(calcSumCurry(3)(4, 5)()) // curry: 参数长度不足

    想要一直累加:

    1. var slice = Array.prototype.slice
    2. function curry(fn, len0) {
    3. const curArgs = []
    4. const len = len0 || fn.length
    5. return function () {
    6. if (arguments.length === 0) {
    7. if (curArgs.length >= len) return fn.apply(this, curArgs)
    8. return console.warn('curry: 参数长度不足')
    9. }
    10. Array.prototype.push.apply(curArgs, [].slice.call(arguments));
    11. return arguments.callee;
    12. }
    13. }
    14. var calcSum2 = function (...args) {
    15. // const arr = Array.from(arguments);
    16. const arr = Array.prototype.slice.call(arguments, 0);
    17. // const arr = Array.of(...args);
    18. let sum = 0;
    19. return arr.reduce((obj, cur) => {
    20. sum = obj + cur
    21. return sum
    22. }, sum)
    23. }
    24. const log = console.log
    25. var calcSumCurry = curry(calcSum2, 4)
    26. log(calcSumCurry(3, 4, 5)())// curry: 参数长度不足
    27. log(calcSumCurry(4)(5)())// 21

    严格模式下callee会报错, 可以改成:

    1. 'use strict'
    2. var slice = Array.prototype.slice
    3. function curry(fn, len0) {
    4. const curArgs = []
    5. const arg2 = []
    6. const len = len0 || fn.length
    7. let tag = 'start'
    8. return function start () {
    9. if (arguments.length === 0) {
    10. if (curArgs.length >= len) {
    11. if(tag === 'end') return console.warn('curry: 参数长度不足, 请核对参数后重试')
    12. return fn.apply(this, curArgs)
    13. }
    14. tag = 'end'
    15. // 只有第一次执行计算的时候才会判断参数长度是否足够
    16. return console.warn('curry: 参数长度不足')
    17. }
    18. Array.prototype.push.apply(curArgs, [].slice.call(arguments));
    19. return start;
    20. }
    21. }
    22. var calcSum2 = function (...args) {
    23. const arr = Array.prototype.slice.call(arguments, 0);
    24. let sum = 0;
    25. return arr.reduce((obj, cur) => {
    26. sum = obj + cur
    27. return sum
    28. }, sum)
    29. }
    30. const log = console.log
    31. var calcSumCurry = curry(calcSum2, 4)
    32. log(calcSumCurry(3, 4, 5)()) // curry: 参数长度不足
    33. log(calcSumCurry(4)(5)()) // 参数长度不足, 请核对参数后重试

    柯里化log方法:

    1. var slice = Array.prototype.slice;
    2. var curry = function (fn, length) {
    3. var args = slice.call(arguments, 2)
    4. return _curry.apply(this, [fn, length || fn.length].concat(args))
    5. };
    6. function _curry(fn, len) {
    7. var oArgs = slice.call(arguments, 2);
    8. return function () {
    9. var args = oArgs.concat(slice.call(arguments));
    10. if (args.length >= len) {
    11. return fn.apply(this, args);
    12. } else {
    13. return _curry.apply(this, [fn, len].concat(args))
    14. }
    15. }
    16. }
    17. function log(logLevel, msg) {
    18. console.log(`${logLevel}:${msg}:::${Date.now()}`)
    19. }
    20. //柯里化log 方法
    21. const curryLog = curry(log);
    22. const debugLog = curryLog("debug");
    23. const errLog = curryLog("error");
    24. //复用参数debug
    25. debugLog("testDebug1");//debug:testDebug1:::1696145622354
    26. debugLog("testDebug2");//debug:testDebug2:::1696145622360
    27. //复用参数error
    28. errLog("testError1");//error:testError1:::1696145622360
    29. errLog("testError2");//error:testError2:::1696145622360

    二. 非柯里化的实现方式:

    1. 偏函数

    偏函数求和:

    1. // 偏函数
    2. function partial(fn) {
    3. // 接受fn之外的参数
    4. const args = [].slice.call(arguments, 1)
    5. return function () {
    6. // 接收剩余参数
    7. const newArgs = args.concat([].slice.call(arguments));
    8. return fn.apply(this, newArgs)
    9. }
    10. }
    11. function calcSum(...args) {
    12. const arr = [...args]
    13. let sum = 0;
    14. return arr.reduce((obj, cur) => {
    15. sum = obj + cur
    16. return sum
    17. }, sum)
    18. }
    19. // 偏函数是固定一部分参数(一个或者多个参数), 将一个N元函数转换为一个N-X函数
    20. const pCalcSum = partial(calcSum, 10);
    21. console.log(pCalcSum(11, 12))//33

    2. 反柯里化

    1. 反柯里化方法的几种写法:

    1. Function.prototype.unCurry=function() {
    2. var self = this
    3. return function() {
    4. return Function.prototype.call.apply(self, arguments)
    5. }
    6. }
    7. Function.prototype.unCurry=function() {
    8. return this.call.bind(this)
    9. }
    10. Function.prototype.unCurry=function() {
    11. return (...args) => this.call(...args)
    12. }

    2. 反柯里化实例运用:

    1) 克隆数组
    1. function unCurry1(fn) {
    2. return function(context) {
    3. // this换成传入的参数context, context之外的参数作为apply的剩余参数
    4. return fn.apply(context, Array.prototype.slice.call(arguments, 1));
    5. }
    6. }
    7. Function.prototype.unCurry = function () {
    8. const self = this
    9. return function() {
    10. return Function.prototype.call.apply(self, arguments)
    11. }
    12. }
    13. // 复制数组
    14. var clone = Array.prototype.slice.unCurry()
    15. var a = [1, 2, 3]
    16. var b = clone(a);
    17. console.log('a == b', a === b); // 除非引用一样, 否则都是false
    18. console.log(a, b);//[ 1, 2, 3 ] [ 1, 2, 3 ]
    19. var slice = [].slice
    20. var clone = unCurry1(slice)
    21. var a = [1, 2, 3]
    22. var b = clone(a);
    23. console.log('a == b', a === b); // 除非引用一样, 否则都是false
    24. console.log(a, b);//[ 1, 2, 3 ] [ 1, 2, 3 ]
    2) 生成类数组
    1. function unCurry1(fn) {
    2. return function(context) {
    3. // this换成传入的参数context, context之外的参数作为apply的剩余参数
    4. return fn.apply(context, Array.prototype.slice.call(arguments, 1));
    5. }
    6. }
    7. Function.prototype.unCurry = function () {
    8. const self = this
    9. return function() {
    10. return Function.prototype.call.apply(self, arguments)
    11. }
    12. }
    13. var push = Array.prototype.push.unCurry();
    14. var obj = {}
    15. // console.log(Array.prototype.slice.call({0:1, length: 1}, 0))//[1]
    16. push(obj, 4, 5, 6); // 对象变成了类数组
    17. console.log(obj)//{ '0': 4, '1': 5, '2': 6, length: 3 }
    18. var obj = {}
    19. unCurry1([].push)(obj, 7, 8, 9, 10)
    20. console.log(obj)//{ '0': 7, '1': 8, '2': 9, '3': 10, length: 4 }

  • 相关阅读:
    Docker快速安装Oracle 12c
    内网渗透面试问题
    哈希表长度为素数的试证明
    Element UI table 修改定位
    性能优化:Redis使用优化(1)
    SpringBoot集成Redis主从架构实现读写分离(哨兵模式)
    javascript字符串对象之字符串
    第5周学习:ShuffleNet & EfficientNet & 迁移学习
    【23真题】很少见!第6题有点新颖!
    【Vue+element_ui】生成Ubuntu自定义壁纸幻灯片的核心xml文本
  • 原文地址:https://blog.csdn.net/qq_42750608/article/details/133446241