看以下代码
function curry(fn, ...args) {
const length = fn.length
let lists = args || []
return function (..._args) {
lists = [...lists, ..._args]
let listLen = lists.length
if (listLen < length) {
const that = lists
lists = [] // 初始化
return curry(fn, ...that)
} else if (listLen === length) {
const that = lists
lists = [] // 初始化
return fn.apply(this, that)
}
}
}
var add = (a, b, c) => a+b+c
var curryAdd = curry(add)
console.log(curryAdd(1, 2, 3)) // 6
console.log(curryAdd(1, 2)(3)) // 6
console.log(curryAdd(1)(2)(3)) // 6
为什么 需要 重新初始化 lists ?
原因:
因为 curryAdd 存在,以下有三个打印 ( console.log() ) :
第一个打印调用一次
curryAdd
,我们记作 curryAdd1第二个打印调用两次
curryAdd
,第一次调用我们记作 curryAdd1 (因为这次调用的函数是和第一个打印调用的函数一样,都是从同一个 curry 返回的), 这一次调用会再次调用curry
,返回第二个函数(匿名函数,虽然不是 curryAdd 但是为了方便),我们记作 curryAdd2同理,第三次打印调用三次
curryAdd
,我们分别记作 curryAdd1, curryAdd2, curryAdd3
我们知道,三次调用的 curryAdd1 有相同的 上下文,curryAdd2 有和 curryAdd1 不一样的上下文, curryAdd3 有和 curryAdd1, curryAdd2 不一样的上下文
- 即,内存中有 三种 不同的 lists ,我们也可以记作 lists1, lists2, lists3
但是 curry 中 有 let lists = args || []
保证 lists1 == lists2 == lists3,于是我们记他们为 lists
那么,若没有 that
,lists
也不会更新,然后直接传入 lists
显然:<b>lists
会不断增加</b>
虽然如此,但是以上 curry
代码当 lists.length >== 3
就不再返回函数,所以下方打印调用会报错,我们可以举个例子验证一下以上 猜想
function fn(x = []){
let a = x
return () => {
a.push(0)
console.log(a.length)
if (a.length === 3) {
return;
} else {
return fn(a)
}
}
}
var ffn = fn()
ffn()()()
ffn()()
ffn()
/**
* 猜测将会打印如下:
* 1
* 2
* 3
* 4
* 5
* 6
*/
猜测正确
其他
- 那么,我们怎么验证 curryAdd1, curryAdd2, curryAdd3 有不一样上下文的猜测呢?
看以下例子:
- 我们将 a 声明为局部变量,且不是按引用传参,而是按值传参的形式
function fn(x = 0){
let a = x
return () => {
a++
console.log(a)
if (a === 3) {
return;
} else {
return fn(a)
}
}
}
var ffn = fn()
ffn()()()
ffn()()
ffn()
/**
* 猜测将会打印如下:
* 1 // ffn()()()
* 2
* 3
* 2 // ffn()()
* 3
* 3 // ffn()
*/
猜测正确