柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
主要应用:
1. 参数复用
// 拼接URL,复用“protocol”参数
function url(protocol){
return function(host){
return `${protocol}${host}`
}
}
const httpUrl = url("http://")
const httpsUrl = url("https://")
console.log(httpUrl("192.168.0.2")) // http://192.168.0.2
console.log(httpsUrl("192.168.0.2")) // https://192.168.0.2
2. 提前确认(避免每次都重复调用)
// dom事件的兼容性处理
// 提前执行这个函数,不用每次执行都会去进行判断
const addEvent = (function () {
// 高版本浏览器
if (document.addEventListener) {
return function (element, event, handler) {
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
}
} else { // ie浏览器
return function (element, event, handler) {
if (element && event && handler) {
element.attachEvent('on' + event, handler);
}
};
}
})()
3. 延迟运行
- 封装函数的bind方法
// context是_bind想要改变的this指向
Function.prototype._bind = function (context) {
let fn = this // 调用_bind的对象
// 返回一个新函数,延迟执行 apply方法
return function (...args) {
fn.apply(context, args)
}
}
经典面试题:add(1)(2)(3)
```javascript function add() { let args = […arguments] return function childAdd() { if (arguments.length != 0) { // 判断传入的参数是否是空,不为空就递归
} return args.reduce((pre, item) => pre + item, 0) 参数为空就返回所有参数的值 } } console.log(add(1, 2)(4)(5)())args.push(...arguments)
return childAdd
// 此题可以网上大多数解法是修改函数的toString方法,但node执行没有效果,浏览器也并非所有都兼容 // 附:toString解法 function add() { let args = […arguments] return function childAdd() { args.push(…arguments) childAdd.toString = function () { return args.reduce((pre, item) => pre + item, 0) } return childAdd } } console.log(add(1, 2)(4)(5))
<a name="iItRO"></a>
## 封装让函数柯里化的方法
```javascript
// 封装柯里化函数
function curring(fn, ...args) {
let that = this // 保存调用curring函数的this
return function cur() {
// 收集参数,将首次调用curring传入的参数和这次的参数合并
let _arg = args.concat(Array.from(arguments))
if (_arg.length < fn.length) { // 没有集齐参数,继续收集
let a = Array.from(arguments) // 保存本次传入的参数
return function () {
// 把上一次传入的参数和这一次的合并
return cur.apply(that, a.concat(Array.from(arguments)))
}
}
return fn.apply(that, _arg) // 集齐参数,执行该函数
}
}
// 测试代码
function sum(a, b, c) {
return a + b + c
}
let fn1 = curring(sum, "jj")
let fn2 = curring(sum)("kkk")
let fn3 = curring(sum)("ccc")('ff')
console.log(fn1(2, 3)) // jj23
console.log(fn1(5)(4)) // jj54
console.log(fn2(2, 3)) // kkk23
console.log(fn2(3)(4)) //kkk34
console.log(fn3(3)) //cccff3
console.log(fn3(4)) // cccff4