概念
在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
嗯.... 看不懂,听不懂💥 那就看例子。看例子肯定能看出来点什么
理解
2个数求和
function add(a, b) {
return a + b;
}
console.log(add(1, 2));
function curryAdd(fn, a) {
return function (b) {
return fn(a, b);
};
}
console.log(curryAdd(add, 1)(2)); // 3
3个数求和
function addThree(a, b, c) {
return a + b + c;
}
function curryAddThree(fn, a) {
return function (b) {
return function (c) {
return fn(a, b, c);
};
};
}
console.log(curryAddThree(addThree, 1)(2)(3)); // 6
4个数求和
function addFour(a, b, c, d) {
return a + b + c + d;
}
console.log(addFour.length);
function curryAddFour(fn, a) {
return function (b) {
return function (c) {
return function (d) {
return fn(a, b, c, d);
};
};
};
}
console.log(curryAddFour(addFour, 1)(2)(3)(4)); // 10
enen。。。 经过上面的锻炼,我总算看出来的点什么了
闭包中:利用闭包收集参数,参数够了,运行fn,参数不够,递归,继续收集
手撕curry
/**
* @Author: Kongjingjing
* @Date: 2022-09-19 15:40:59
* @Description: 柯理化
*/
function curry(fn, ...args) {
return function (...restArgs) {
let allArgs = [...args, ...restArgs]; // 所有参数
if (fn.length <= allArgs.length) {
// 参数达标
return fn.apply(this, allArgs);
} else {
return curry(fn, ...allArgs); // 参数不达标-递归
}
};
}
function add(a, b) {
return a + b;
}
let addCurry = curry(add);
console.log(addCurry(1)(2));
手撕2,只是参数的处理有点区别,思路一模一样
function curry2(fn, args) {
let len = fn.length; // 参数个数
args = args || []; // 没有参数,就是空数组初始化
return function () {
let _args = args.slice(0); // 拷贝参数
for (let index = 0; index < arguments.length; index++) {
_args.push(arguments[index]);
}
if (len <= _args.length) {
return fn.apply(this, _args);
} else {
return curry2(fn, _args);
}
};
}
function add(a, b) {
return a + b;
}
let addCurry2 = curry2(add);
console.log(addCurry2(1)(2));
手撕3, es6一句话搞定
function curry3(fn, ...args) {
return fn.length <= args.length
? fn(...args)
: curry3.bind(null, fn, ...args); // 这里为什么是bind,值得思考
}
function add(a, b, c) {
return a + b + c;
}
let addCurry3 = curry3(add);
console.log(addCurry3(1)(2)(4));
字节面试
算法题4:JS实现add(1)(2)(3)(4)的调用方式
var add = function (m) {
var _temp = function (n) {
return add(m + n);
};
_temp.toString = function () {
return m;
};
return _temp;
};
console.log(add(3)(4)(5)+1); // 13
应用场景
我还没有彻底理解柯理化。嗯,觉得网上那些说的应用把,很一般把,体会不出来好处
自己比较能接受这个使用
补充给个案例 这里使用了柯里化保存参数,并且使用了promise来封装,方便后续使用
这是一个操作mysql数据库的方法
// db.js 只是负责连接数据库, 向外暴露一个连接信息
const mysql = require('mysql')
// 创建连接池
const db = mysql.createPool({
host: 'localhost',
port: 3306,
user: 'root',
password: 'root',
database: 'root'
})
exports.db = db
函数柯理化
const { db } = require('./db')
const select = function (sql) {
return function (params = []) {
return new Promise((resolve, reject) => {
db.query(sql, params, (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
}
}
使用
const db = require('./db_crud')
const selectUser = db.select('SELECT * FROM `student` LIMIT ?, 10')
const deleteById = db.delete('DELETE FROM `users` WHERE `id`=?')
module.exports = {
selectUser: selectUser,
deleteById: deleteById
}
使用时,直接导入该模块
const abc=require(...)
acc.selectUser([参数]).then(res=>{console.log(res}) 即可
小知识点
在学习函数柯理化的时候,我意识到了fn还有length,我以为这是什么反人类行为
现在我才知道是我知识的欠缺
fn的length属性,返回的是参数个数
function a(x, y) {}
a.length; // 2
function b(x, y = 2, z) {}
b.length; // 1
function c(x, ...args) {}
c.length; //1
length 是JS函数对象的一个属性值,该值是指 “该函数有多少个必须要传入的参数”,即形参的个数
形参的数量不包括剩余参数个数,仅包括 “第一个具有默认值之前的参数个数”