🚀手撕大厂常见手写题——柯里化
前言
提到柯里化,还记得当初是小白的时候,看一块的内容真的非常晕,今天再来整理的时候发现现在在基础上来了,实现一个柯里化函数比手写深拷贝和数组扁平化还要简单不少~
总的一句话,就是简单~
定义
先把它的定义过一下吧
柯里化
:其实是函数式编程的一个过程,在这个过程中我们能把一个带有多个参数的函数转换成一系列的嵌套函数。它返回一个新函数,这个新函数期望传入下一个参数。
就比如面试的时候,面试官经常让我们实现的
function sum(x, y, z) {
console.log(x + y + z);
}
var foo = curry(sum) // 将sum函数柯里化
foo(10)(20)(30) // 60
foo(10,20)(30) // 60
foo(10,20,30) // 60
定义这个不是重点,重点还是我们柯里化实现的过程~
手写
首先我们要了解,柯里化大概做了一个什么过程?
- 原本可以直接通过sum(10,20,30) 直接传递三个实参,结果经过
curry
封装后变成了可以foo(10)(20,30) foo(10)(20)(30) 等,将其之前直接传递的三个实参(10,20,30)
直接分解了 sum
函数经过curry
函数的封装,将结果赋给了foo
,最后调用foo
所以我们可以分析出,这里curry
的作用,一定有传入的参数是函数,返回的结果也是一个函数
所以我们不难写出这第一步
// 这里的fn可以暂时理解为sum函数
function curry(fn) {
// curryFn函数可以看做返回出来的foo函数 ...args代表foo函数传入的剩余参数
function curryFn(...args) {
}
return curryFn
}
再看,既然返回出了curryFn函数,那么它的功能肯定是要执行fn,但它什么时候才会执行呢?
很简单,就是只有当curryFn中的参数等于fn中参数的个数就将fn执行
这里指的是curryFn(10)(20)(30)中的三个参数
关于剩余参数(...args)和展开运算符
这里很多小白刚开始都会被它们绕晕,其实还是只需要记住
- 展开运算符:...[1,2,3] => 1,2,3 这里
...
是将数组展开 - 剩余参数:...args中,
...
只是我们理解的省略号的形式,代表剩余参数的意思,而args才是数组形式,并不违背es6的语法
具体可以看看官方文档
剩余参数 - JavaScript | MDN (mozilla.org)
展开语法 - JavaScript | MDN (mozilla.org)
第二步就该收集每次currFn函数的形参了
function curry(fn) {
// curryFn函数可以看做返回出来的foo函数 ...args代表foo函数传入的剩余参数
function curryFn(...args) {
return function (...newArgs) {
// 利用每次currFn的递归去收集参数args.concat(newArgs)
return curryFn(...args.concat(newArgs))
}
}
return curryFn
}
最后一步,当收集到的参数和fn中要传入的参数数量相同时,就可以执行fn函数了
function curry(fn) {
function curryFn(...args) {
// fn.length 代表的是获取函数行参的长度
if (args.length >= fn.length) {
// 这里用call改变this指向
fn.call(this, ...args)
} else {
return function (...newArgs) {
return curryFn(...args.concat(newArgs))
}
}
}
return curryFn
}
这里使用fn.call(this,..args)
,将fn
中的this指向curryFn
的this,所以最后curryFn
在哪里调用的,fn
中的this也就指向哪里
完整版
function sum(x, y, z) {
console.log(x + y + z);
console.log(this)
}
function curry(fn) {
function curryFn(...args) {
if (args.length >= fn.length) {
fn.call(this, ...args)
} else {
return function (...newArgs) {
return curryFn(...args.concat(newArgs))
}
}
}
return curryFn
}
var foo = curry(sum)
foo(10)(20)(30) // 60
foo(10, 20)(30) // 60
foo(10, 20, 30) // 60
小结
其实这一块的东西还是不难的吧,考来考去就是我们常见的es6语法的掌握程度,这就是我这一次的分享了,最后还是希望能帮助屏幕前面的你~
转载自:https://juejin.cn/post/7210596158933942333