JS函数柯里化

90 阅读2分钟

函数柯里化

概念

  • 向一个函数里面传入若干参数,然后返回一个没有副作用的纯函数,从而达到参数复用的效果

使用场景

参数复用
  • 当在多次调用同一个函数,并且传递的参数绝大多数是相同的,那么就可以用柯里化进行函数的复用
// 例子
function getHtml(http) {
    return function (hostname, pathname) {
        return `${http}${hostname}${pathname}`
    }
}
const htp = getHtml('https://');
console.log(htp('baidu', '.com'));
延时执行
  • 避免提前去执行程序,当真正需要的时候再去执行
const addEvent = (function () {
    if (window.addEventListener) {
        return function (element, type, listener, useCapture) {
            element.addEventListener(type, function (e) {
                listener.call(element, e)
            }, useCapture)
        }
    } else if (window.attachEvent) {
        return function (element, type, listener) {
            element.attachEvent('on' + type, function (e) {
                listener.call(element, e)
            })
        }
    }
})()
let button = document.querySelector('button');
addEvent(button, 'click', (e) => { console.log('点击了按钮') }, true)
提前确认
  • 当多次调用内部判断,可以提前返回第一次判断结果给外部接受

示例

// 经典面试题
const add = function () {
    // 第一次执行时,定义一个数组专门用来存储所有的参数
    let args = Array.prototype.slice.call(arguments);

    // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
    let next = function () {
        args.push(...arguments);
        return next;
    }

    // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
    next.toString = function () {
        return args.reduce(function (a, b) {
            return a + b
        })
    }

    return next;
}
console.log( add(1)(2, 5)(3)(4) ) // ƒ () { args.push( ...arguments ) return next } 
console.log( typeof add(1)(2, 5)(3)(4) ) // function 
console.log( +add(1)(2, 5)(3)(4) ) // 15
add(1) // 1
add(1)(2) // 3
add(1)(2)(3) // 6
add(1)(2)(3)(4) // 10
add(1)(2,3) // 6
add(1,2)(3) // 6
add(1,2,3) // 6

currying实现

// currying原理
// 返回一个函数
// 收集参数
// 判断fn.length原函数长度与args.length的长度
// args.length >= fn.length 返回
// args.length < fn.length 递归执行next

function currying(fn) {
    return function next() {
        let args = Array.prototype.slice.call(arguments);

        if (args.length >= fn.length) {
            return fn.call(this, args);
        }
        return function (...arg) {
            return next(...args, ...arg);
        }
    }
}

// 测试
function addNum(a, b, c) {
    return a + b + c;
}
const addCurry = currying(addNum);
console.log(addCurry(1)(2)(3));  // 6
console.log(addCurry(1));     // ƒ (...arg) { return next(...args, ...arg) }
console.log(addCurry(1)(2));  // ƒ (...arg) { return next(...args, ...arg) }
console.log(addCurry(1)(2, 3)); // 6
console.log(addCurry(1, 2)(3)); // 6
console.log(addCurry(1, 2, 3)); // 6

参考文献

函数柯里化 - 清水渡白吟堤你如风 - 博客园 (cnblogs.com)