Open serendipityApe opened 2 years ago
题目
implement curry() 柯里化是js中一个常用的概念,接下来我们来尝试写出一个 curry 函数,接收一个函数然后返回该函数的柯里化
例子 const join = (a, b, c) => { return `${a}_${b}_${c}` }
例子
const join = (a, b, c) => { return `${a}_${b}_${c}` }
const curriedJoin = curry(join)
curriedJoin(1, 2, 3) // '1_2_3'
curriedJoin(1)(2, 3) // '1_2_3'
curriedJoin(1, 2)(3) // '1_2_3'
> 答题
//答案1 function curry(func) { return function innerFunc(...args) { //func为原函数,innerFunc为新函数 //如果新函数的参数比原函数多或相等则执行原函数 if(args.length >= func.length){ return func(...args) }else{ //否则一直累加新函数的参数 return function(...next){ return innerFunc(...args,...next) } } } }
或者
//答案2 function curry(func) { return function innerFunc(...args) { if(args.length >= func.length){ return func(...args) //return func.apply(this,args) }else{ //这里的bind作用是参数继承而不是改变this(我们应该清楚function内this都为window) return innerFunc.bind(this,...args) } } }
> 补充 我觉得执行curry函数后,我们理应可以通过.length来判断剩余的参数数量,比如下面这样
const join = (a, b, c) => { return ${a}_${b}_${c} }
${a}_${b}_${c}
curriedJoin(1, 2, 3).length // 0
curriedJoin(1).length // 2
curriedJoin(1, 2).length // 1
但是事实却是无论是答案1还是答案2都恒定返回0 至于原因是什么,让我们先来了解一下Function.length
//length 是函数对象的一个属性值,指该函数有多少个必须要传入的参数,即形参的个数。 console.log(Function.length); //1
console.log((function() {}).length); //0 console.log((function(a) {}).length); //1 console.log((function(a, b) {}).length); //2
//形参的数量不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数。 console.log((function(...args) {}).length); // 0, //剩余参数(...args)为0
console.log((function(a, b = 1, c) {}).length); // 1 //b=1声明了默认值,第一个具有默认值之前的参数个数为1
看到这里,我想大家都明白了: 在答案1的 `return function(...next){ return innerFunc(...args,...next) }`我们使用了剩余参数(...next),因此恒定为0。 而在答案2中原因却是第二行的 `return function innerFunc(...args) {`
//看下面例子
const join = (a, b, c) => { return ${a}_${b}_${c} } console.log(join.bind(this,1).length) //2
function join2(...args){ return ${args[0]}_${args[1]}_${args[2]} } console.log(join2.bind(this,1).length) //0 //上面的两个函数区别就在与bind的原函数,如果原函数使用了剩余参数(...args),那么使用bind后length也为 //而在答案2里,我们的原函数innerFunc.length显然为0
${args[0]}_${args[1]}_${args[2]}
最后,怎么让curry能够通过.length查看剩余参数呢
function curry(func) { return function innerFunc(...args) { if(args.length >= func.length){ return func(...args) }else{ var boundLength = func.length-args.length var boundArgs = []; for (var i = 0; i < boundLength; i++) { boundArgs.push('$' + i); } var binder= function(...next){ return innerFunc(...args,...next) } var bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); return bound } } }
> 参考链接: [https://github.com/Raynos/function-bind/blob/master/implementation.js](https://github.com/Raynos/function-bind/blob/master/implementation.js) [https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/length](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/length)
implement curry() 柯里化是js中一个常用的概念,接下来我们来尝试写出一个 curry 函数,接收一个函数然后返回该函数的柯里化
const curriedJoin = curry(join)
curriedJoin(1, 2, 3) // '1_2_3'
curriedJoin(1)(2, 3) // '1_2_3'
curriedJoin(1, 2)(3) // '1_2_3'
//答案1 function curry(func) { return function innerFunc(...args) { //func为原函数,innerFunc为新函数 //如果新函数的参数比原函数多或相等则执行原函数 if(args.length >= func.length){ return func(...args) }else{ //否则一直累加新函数的参数 return function(...next){ return innerFunc(...args,...next) } } } }
或者
//答案2 function curry(func) { return function innerFunc(...args) { if(args.length >= func.length){ return func(...args) //return func.apply(this,args) }else{ //这里的bind作用是参数继承而不是改变this(我们应该清楚function内this都为window) return innerFunc.bind(this,...args) } } }
const join = (a, b, c) => { return
${a}_${b}_${c}
}const curriedJoin = curry(join)
curriedJoin(1, 2, 3).length // 0
curriedJoin(1).length // 2
curriedJoin(1, 2).length // 1
//length 是函数对象的一个属性值,指该函数有多少个必须要传入的参数,即形参的个数。 console.log(Function.length); //1
console.log((function() {}).length); //0 console.log((function(a) {}).length); //1 console.log((function(a, b) {}).length); //2
//形参的数量不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数。 console.log((function(...args) {}).length); // 0, //剩余参数(...args)为0
console.log((function(a, b = 1, c) {}).length); // 1 //b=1声明了默认值,第一个具有默认值之前的参数个数为1
//看下面例子
const join = (a, b, c) => { return
${a}_${b}_${c}
} console.log(join.bind(this,1).length) //2function join2(...args){ return
${args[0]}_${args[1]}_${args[2]}
} console.log(join2.bind(this,1).length) //0 //上面的两个函数区别就在与bind的原函数,如果原函数使用了剩余参数(...args),那么使用bind后length也为 //而在答案2里,我们的原函数innerFunc.length显然为0function curry(func) { return function innerFunc(...args) { if(args.length >= func.length){ return func(...args) }else{ var boundLength = func.length-args.length var boundArgs = []; for (var i = 0; i < boundLength; i++) { boundArgs.push('$' + i); } var binder= function(...next){ return innerFunc(...args,...next) } var bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); return bound
} } }