柯里化(currying)是把接受多个参数的函数变换成接受一个参数的函数,并且返回接受剩余参数且返回结果的新函数的技术。
柯里化后的函数接收参数的数量与原函数的形参数量相等时,执行原函数;当接收的参数数量小于原函数形参数量时,返回一个用于接收剩余参数的函数。
// 1 只能传被柯里化函数形参的个数,多少都不行 function currying(fn, ...args) { const length = fn.length; return function(...newArgs) { const allArgs = [...args, ...newArgs]; if (allArgs.length < length) { return currying.call(this, fn, ...allArgs); } else { return fn.apply(this, allArgs); } } } const add = (a, b, c) => a + b + c; const addCurrying = currying(add); console.log(addCurrying(1)(2)(3)); console.log(addCurrying(1,2)(3)); console.log(addCurrying(1)(2,3)); console.log(addCurrying(1,2,3)); // 2 参数长度不固定,最后需要手动调用一次 function currying(fn, ...args) { let allArgs = [...args]; return function temp(...newArgs) { if (newArgs.length) { allArgs = [...allArgs, ...newArgs]; return temp; } else { const res = fn.apply(this, allArgs); allArgs = [...args]; return res; } } } const add = (...args) => args.reduce((a, b) => a + b); const addCurrying = currying(add); console.log(addCurrying(1)(2)(3)(4,5)()); console.log(addCurrying(1)(2)(3,4,5)()); console.log(addCurrying(1)(2,3,4,5)());
柯里化用途
// 1 校验规则 // 原函数 function checkByRegExp(regExp, string) { return regExp.test(string); } // 普通使用 checkByRegExp(/^1d{10}$/, '18642838455'); // 校验电话号码 checkByRegExp(/^(w)+(.w+)*@(w)+((.w+)+)$/, 'test@163.com'); // 校验邮箱 // 柯里化后使用 let check = currying(checkByRegExp); let checkCellPhone = check(/^1d{10}$/); let checkEmail = check(/^(w)+(.w+)*@(w)+((.w+)+)$/); checkCellPhone('18642838455'); // 校验电话号码 checkCellPhone('13109840560'); // 校验电话号码 checkCellPhone('13204061212'); // 校验电话号码 checkEmail('test@163.com'); // 校验邮箱 checkEmail('test@qq.com'); // 校验邮箱 checkEmail('test@gmail.com'); // 校验邮箱 // 2 提取对象数组的某一属性 const list = [ {name:'lucy'}, {name:'jack'} ]; // 普通使用 const names = list.map(item => item.name); // 柯里化使用 const prop = currying((key, obj) => obj[key]); const names = list.map(prop('name'));