第 84 题:请实现一个 add 函数,满足以下功能。
yygmind opened this issue · 91 comments
add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
之前写过 2 篇文章,可以参考一二。
1、【进阶 6-1 期】JavaScript 高阶函数浅析
2、【进阶 6-2 期】深入高阶函数应用之柯里化
其中第一篇文章给出了前三个功能的实现,并没有覆盖到后面三种。
第二篇文章实现了一个通用的柯里化函数,覆盖实现了所有功能。
实现 1:
function currying(fn, length) {
length = length || fn.length; // 注释 1
return function (...args) { // 注释 2
return args.length >= length // 注释 3
? fn.apply(this, args) // 注释 4
: currying(fn.bind(this, ...args), length - args.length) // 注释 5
}
}
实现 2:
const currying = fn =>
judge = (...args) =>
args.length >= fn.length
? fn(...args)
: (...arg) => judge(...args, ...arg)
其中注释部分
-
注释 1:第一次调用获取函数 fn 参数的长度,后续调用获取 fn 剩余参数的长度
-
注释 2:currying 包裹之后返回一个新函数,接收参数为 ...args
-
注释 3:新函数接收的参数长度是否大于等于 fn 剩余参数需要接收的长度
-
注释 4:满足要求,执行 fn 函数,传入新函数的参数
-
注释 5:不满足要求,递归 currying 函数,新的 fn 为 bind 返回的新函数(bind 绑定了 ...args 参数,未执行),新的 length 为 fn 剩余参数的长度
const curry = (fn, arity = fn.length, ...args) =>
arity <= args.length ? fn(...args) : curry.bind(void 0, fn, arity, ...args);
function add() {
let args = [].slice.call(arguments);
let fn = function(){
let fn_args = [].slice.call(arguments)
return add.apply(null,args.concat(fn_args))
}
fn.toString = function(){
return args.reduce((a,b)=>a+b)
}
return fn
}
function add(){
let args = [...arguments];
let addfun = function(){
args.push(...arguments);
return addfun;
}
addfun.toString = function(){
return args.reduce((a,b)=>{
return a + b;
});
}
return addfun;
}
还有一种方法
function add(){
if(arguments.length === 0){
let num = 0;
add.args.forEach(v=>{
num += v;
});
add.args = null;
return num;
}else{
add.args = add.args ? add.args : [];
add.args = add.args.concat([...arguments]);
return add;
}
}
add(1)(2)(3)();
add(1, 2)(3)(8)();
function curry (fn) {
const finalLen = fn.length
let args = [].slice.call(this,1)
return function currying () {
args = args.concat(Array.from(arguments))
const len = args.length
return len >= fn.length ? fn.apply(this, args) : currying
}
}
function add (a,b,c) {
return a+b+c
}
const add1 = curry(add)
console.log(add1(1, 2)(3))
function add(...args) {
let sum = 0;
const innerAdd = (...args) => {
args.forEach(i => (sum += i));
return innerAdd;
};
innerAdd.toString = () => sum;
return innerAdd(...args);
}
如果要做成高阶函数以便支持任意迭代器,累加器的初始值设定要麻烦一点
尤其是考虑到任意长度输入和空输入,要多一些判断逻辑。
写了一个支持以上所有特性的
const curryReducer = (fn) => {
return (...args) => {
let runned = false;
const chain = (...args) => {
if (!args.length) return chain;
chain.acc = (runned ? [chain.acc] : []).concat(args).reduce(fn);
!runned && (runned = true);
return chain;
};
chain.acc = undefined;
chain.toString = () => chain.acc;
return chain(...args);
};
};
// * ---------------- simple add function
const add = curryReducer((a, e) => a + e);
console.log('' + add(1, 2, 3)()(4, 5)(6)(7)(8, 9, 10));
const method = {
add: (a, e) => a + e,
minus: (a, e) => a - e,
times: (a, e) => a * e,
devide: (a, e) => a / e,
};
Object.values(method).forEach((e) => {
console.log('batch test -------------- method is: ', e);
const chainFn = curryReducer(e);
console.log('' + chainFn());
console.log('' + chainFn(6));
console.log('' + chainFn(6, 2));
console.log('' + chainFn(6)(2));
console.log('' + chainFn()(6)(2));
console.log('' + chainFn(6, 2, 3));
console.log('' + chainFn(6, 2)(3));
console.log('' + chainFn(6)(2)(3));
});
function add(...a) {
let sum = a.reduce((p, n) => p + n);
function next(...b) {
let _sum = b.reduce((p, n) => p + n);
sum = sum + _sum;
return next;
}
next.toString = function () {
return sum;
};
return next;
}
function currying(fn, length) { length = length || fn.length; // 注释 1 return function (...args) { // 注释 2 return args.length >= length // 注释 3 ? fn.apply(this, args) // 注释 4 : currying(fn.bind(this, ...args), length - args.length) // 注释 5 } } const sum = function(t,y,u){ let args = [].slice.call(arguments) return args.reduce((a, b) => a + b) } ; const add = currying(sum); console.log(add(1,2)(2)(9)) ; // Uncaught TypeError: add(...)(...) is not a function
请问这个调用这个柯里化函数sum中的形参还要自己手动补吗?
我看这个形参少于实际调用add函数时就会报错,还是我调用的方式错了呢?
@yygmind
@wjryours sum 函数定义的参数长度为 3,调用时参数为 4,所以问题出在这里
柯里化生成的 add 函数若是存储的形参个数达不到定义的参数长度, 则是返回 [Function]
那么如题 add(1) ==>1 , add(1)(2) ==> 3 则不是没有实现吗
@wjryours sum 函数定义的参数长度为 3,调用时参数为 4,所以问题出在这里
柯里化生成的 add 函数若是存储的形参个数达不到定义的参数长度, 则是返回 [Function]
那么如题 add(1) ==>1 , add(1)(2) ==> 3 则不是没有实现吗我想表达的就是这个意思,按照你这个写法那些基本的功能都通过不了,可以解答一下吗@yygmind
我觉得题目出的不好(描述有歧义)。
我的理解里,题目本身和柯里化是有差异的,
题目更像是迭代器而不是柯里化。
如果是柯里化,那么缺少参数的时候是等待所有参数到齐则再开始进行运算,并返回计算结果。
(因为不是所有方法都像 add 一样简单,能支持部分参数计算,不然因为缺少参数,计算逻辑报错了怎么办?)
参数不足的时候返回一个中间 function,以便继续调用。
至于直接能读到(toString),这是一个 trick。
对于柯里化这个高阶方法来说,我觉得不应该一起实现。
就像我说的,是应该等参数到齐再计算(固定参数 function 的 length),
可以参考一下 lodash 或者 ramda 里的 curry
至于如何实现题目本身
(任意长度也能返回计算结果,也就是说,调用一次执行一次)
(像我上面说的,更像是实现一个迭代器,add 只是一个算子)
可以参考一下我的答案
#134 (comment)
Inspired by @CoffeeWorm
#134 (comment)
const curry = fn => {
const len = fn.length;
return function curried(...args) {
if (args.length === len) {
return fn.apply(null, args);
}
return (..._args) => {
return curried.apply(null, [...args, ..._args]);
};
};
};
const sum = (x, y, z) => x + y + z;
const add = curry(sum);
// 6
add(1, 2, 3);
// 6
add(1,2)(3);
// 6
add(1)(2,3);
// 6
add(1)(2)(3);
// 第一步,先实现加和运算
var add = function (a, b) {
return a + b;
}
var currying = function (fn, defineVal = 0) {
return function (...args) { // 第一次调用的是这个函数
// 每次执行前先进行和的初始化
var sum = defineVal;
function func(...argts) { // 第二次之后调用的是这个函数
if (args.length === 0) {
return func.toString();
} else {
argts.unshift(sum);
sum = argts.reduce(fn);
return func;
}
}
func.toString = () => sum;
return func(...args);
}
}
var add = currying(add);
console.info(add(1)); // => 1
console.info(add(1)(2)); // => 3
console.info(add(1)(2)(3)); // => 6
console.info(add(1, 2)(3)); // => 6
console.info(add(1)(2, 3)); // => 6
console.info(add(1, 2, 3)); // => 6
console.info(add(1, 2, 3)(4)); // => 10
function add(...x) {
var sum = x.reduce((a,b)=>a+b,0)
var tmp = function(...y) {
sum =sum+y.reduce((a,b)=>a+b,0)
return tmp;
};
tmp.toString = function() {
return sum;
};
return tmp;
}
console.log(+add(1)(2)(3)) // 6
console.log(+add(1)(2,3)) // 6
console.log(+add(1,2)(3)) // 6
console.log(+add(1)(2)(3,4)) //10
add(1)(2)(3).valueOf
//ƒ valueOf() { [native code] }
add(1)(2)(3).valueOf()
//ƒ 6
+add(1)(2)(3).valueOf()
//6
+""+add(1)(2)(3).valueOf()
//6
</script>
`
function add() {
var sum = function (arr) {
var curSum = 0;
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
if(obj){
curSum = curSum + obj;
}
}
return curSum;
};
var result = function () {
var xx = Array.from(arguments);
xx.push(result._lastSum);
return add.apply({},xx);
};
result.valueOf = function () {
return result._lastSum;
};
result.toString = function () {
return result._lastSum ;
};
result._lastSum = sum(arguments);
return result;
}
`
function add() {
return Array.from(arguments).reduce((pre, item) => pre + item, 0)
}
function curry(fn) {
let params = [];
function result() {
params.push(...arguments)
return result;
}
result.toString = () => {
const tempParams = params;
params = [];
return fn.call(null, ...tempParams)
}
return result;
}
let timer = null
function add(...arg1){
return function(...arg2){
let arg = [...arg1,...arg2]
clearTimeout(timer)
timer = setTimeout(()=>{
console.log(arg.reduce((p,c)=>p+c))
},0)
return add(...arg);
}
}
add(2,3)(4)(5,6)(9)()(1) //30
function add(...args) {
add.params = add.params.concat(args)
return add;
}
add.params = []
add.toString = function() {
var val = add.params.reduce((a,b) => a+b)
add.params = []
return val;
}
function add(...args) {
var f = function(...args1) {
return add.apply(null, [...args, ...args1])
}
f.toString = () => args.reduce((a,b)=>a+b)
return f
}
诸位真的是大佬---膜拜了 我看了半天算是看懂函数柯里化的应用了
function Add(a, b, c) {
return a + b + c;
}
function cuuring(fn) {
let finallen = fn.length;
var args = []
return function digui() {
var innerargs = Array.prototype.slice.call(arguments);
args = args.concat(innerargs);
return args.length >= finallen ? fn.apply(null, args) : digui;
}
}
var add1 = cuuring(Add);
console.log(add1(1)(2)(3))
let timer = null function add(...arg1){ return function(...arg2){ let arg = [...arg1,...arg2] clearTimeout(timer) timer = setTimeout(()=>{ console.log(arg.reduce((p,c)=>p+c)) },0) return add(...arg); } } add(2,3)(4)(5,6)(9)()(1) //30
看来半天 不明白 toString 是怎么调用的...
看你的回答 太真实了
感觉关键点在重写函数toString方法啊,我就一直在想,怎么又返回函数,而最后又输出结果,真棒!
function add(...num) {
let res = 0 //第一次调用函数时生成一个闭包来存储结果
num.forEach(item => res += item) //遍历输入参数加到res上
let ret = function (...num) {
num.forEach(item => res += item)
return ret
}
ret.toString = function () {
return res
}
ret.valueOf = function () {
return res
}
return ret
}
console.log(add(1)); // 1
console.log(add(1)(2)); // 2
console.log(add(1)(2)(3)); // 6
console.log(add(1)(2)(3,7)(4,5,6));// 28
使用了一个闭包完成了这个效果
function add(...num) { let res = 0 //第一次调用函数时生成一个闭包来存储结果 num.forEach(item => res += item) //遍历输入参数加到res上 let ret = function (...num) { num.forEach(item => res += item) return ret } ret.toString = function () { return res } ret.valueOf = function () { return res } return ret } console.log(add(1)); // 1 console.log(add(1)(2)); // 2 console.log(add(1)(2)(3)); // 6 console.log(add(1)(2)(3,7)(4,5,6));// 28使用了一个闭包完成了这个效果
你这里输出的结果其实是 f 1
、f 6
...
function add(...firstArgs) {
const result = firstArgs.reduce((pre, now) => pre + now);
const fn = (...args) => {
return add(...args, result);
};
fn.toString = () => result;
return fn;
}
学到了,fn.toString();
function add(...num) { let res = 0 //第一次调用函数时生成一个闭包来存储结果 num.forEach(item => res += item) //遍历输入参数加到res上 let ret = function (...num) { num.forEach(item => res += item) return ret } ret.toString = function () { return res } ret.valueOf = function () { return res } return ret } console.log(add(1)); // 1 console.log(add(1)(2)); // 2 console.log(add(1)(2)(3)); // 6 console.log(add(1)(2)(3,7)(4,5,6));// 28使用了一个闭包完成了这个效果
你这里输出的结果其实是
f 1
、f 6
...
在不知道会一直调用多少次的情况下, 不返回一个函数, 怎么能够继续调用呀
var add = function() {
this.arr = [];
var print = () => {
if(this.arr.length > 0) {
console.log(arr[arr.length-1]);
this.arr = [];
}
}
this.arr.push([...arguments].reduce((a,b)=>a+b,0));
setTimeout(print,0);
return add.bind(this,...arguments);
}
const Curry = fn => {
return function judge (...firstParma){
if (firstParma.length >= fn.length) {
return fn(...firstParma);
} else {
// 这里的 ...secondParma 函数的第二次或者更多次调用时的参数, ...firstParma 是第一次传入的参数,这里的意思是
// 当函数只有一个的时候就直接返回一个 rest 参数后的函数
// 当函数有多个的时候也就是 fn.length > firstParma.length 的时候
// 这时候就需要把第二个函数的参数和第一个函数参数合起来,然后做递归
// 这里的 ...secondParma, ...firstParma 两个都可以 rest 的原因是这里他们都已经是值了,不再是参数了
return (...secondParma) => judge(...secondParma, ...firstParma);
}
};
};
// Test
const fn = Curry(function (a, b, c){
console.log([a, b, c]);
});
fn(2)(3)(1); // 有三个函数,参数有三个
fn(2,3,1);// 只有一个函数,参数也是三个
我把@yygmind 给的方法做下翻译
function add(...arg) {
let arr = [];
function fn(...arg) {
arr.push(...arg);
return fn;
}
fn.toString = () => {
return arr.reduce((acc, cur) => acc + cur);
};
return fn.call(add, ...arg);
}
如果可以把arr
定义在外部就更简单了
let arr = [];
function add(...arg) {
arr.push(...arg);
add.toString = () => {
return arr.reduce((acc, cur) => acc + cur);
};
return add;
}
function add(...num) { let res = 0 //第一次调用函数时生成一个闭包来存储结果 num.forEach(item => res += item) //遍历输入参数加到res上 let ret = function (...num) { num.forEach(item => res += item) return ret } ret.toString = function () { return res } ret.valueOf = function () { return res } return ret } console.log(add(1)); // 1 console.log(add(1)(2)); // 2 console.log(add(1)(2)(3)); // 6 console.log(add(1)(2)(3,7)(4,5,6));// 28使用了一个闭包完成了这个效果
ret.toString跟ret.valueOf是什么新操作?为什么要这样写呢?
ret.toString = function () {
return res
}
ret.valueOf = function () {
return res
}
function add(...rest){
let result = rest.reduce((prev,cur) => {
return prev + cur
},0)
let f = function(...arg){
var argArr = [...arg,...rest];
return argArr.reduce((p,c) => p + c,0)
}
f.toString = function(){
return result
}
return f
}
const curry = fn => { const len = fn.length; return function curried(...args) { if (args.length === len) { return fn.apply(null, args); } return (..._args) => { return curried.apply(null, [...args, ..._args]); }; }; }; const sum = (x, y, z) => x + y + z; const add = curry(sum); // 6 add(1, 2, 3); // 6 add(1,2)(3); // 6 add(1)(2,3); // 6 add(1)(2)(3);
这个add(1)
add(1)(2)
就不行啊大佬
function add(a,b,c){
return [a,b,c];
}
function curry(fn){
var length = fn.length;
var args = [];
return _curr;
function _curr(){
var len = arguments.length;
length -=len;
args=[...args,...arguments];
if(length){
return _curr;
}else{
return fn(...args);
}
}
}
var _add = curry(add);
var _add2 = curry(add);
var _add3 = curry(add);
console.log(_add(1,2,3));
console.log(_add2(1,2)(3));
console.log(_add3(1)(2)(3));
function add() { let args = [].slice.call(arguments); let fn = function(){ let fn_args = [].slice.call(arguments) return add.apply(null,args.concat(fn_args)) } fn.toString = function(){ return args.reduce((a,b)=>a+b) } return fn }
不行啊你这个 都带了f 都是函数类型
感觉大家的办法都有问题啊。。。这题是不是出的不太好
诸位真的是大佬---膜拜了 我看了半天算是看懂函数柯里化的应用了
function Add(a, b, c) { return a + b + c; } function cuuring(fn) { let finallen = fn.length; var args = [] return function digui() { var innerargs = Array.prototype.slice.call(arguments); args = args.concat(innerargs); return args.length >= finallen ? fn.apply(null, args) : digui; } } var add1 = cuuring(Add); console.log(add1(1)(2)(3))
你这个也不行兄弟。。。
function add(...args1) {
function innerAdd(...args2) {
args1 = [...args1, ...args2];
return innerAdd;
}
innerAdd.toString = function() {
return args1.reduce((sum, cur) => sum + cur, 0);
}
return innerAdd;
}
厉害了,看似柯里化,其实考的是...
会这道的都是大佬吧...
// 定义累加函数
const add = function(a, b) {
return a + b;
};
// 定义累乘函数
const mul = function(a, b) {
return a * b;
};
const currying = function(fn, initVal) {
const fns = function(...args) {
const func = function(...args2) {
return fns.call(this, ...args, ...args2);
};
// 当执行console后才开始计算并输出最终的值
func.toString = () => {
return args.reduce(fn, initVal);
};
return func;
};
return fns;
};
const addC = currying(add, 0);
const mulC = currying(mul, 1);
console.log(addC(1)); // => 1
console.log(addC(1)(2)); // => 3
console.log(addC(1)(2)(3)); // => 6
console.log(addC(1, 2)(3)); // => 6
console.log(addC(1)(2, 3)); // => 6
console.log(addC(1, 2, 3)); // => 6
console.log(mulC(1)); // => 1
console.log(mulC(1)(2)); // => 2
console.log(mulC(1)(2)(3)); // => 6
console.log(mulC(1, 2)(3)); // => 6
console.log(mulC(1)(2, 3)); // => 6
console.log(mulC(1, 2, 3)); // => 6
function add(...args) {
if(args.length === 3) return args.reduce((a,b) => a+b, 0)
return add.bind(null, ...args)
}
function add (...args1) {
let result = args1.reduce((pre, current) => pre + current, 0)
function sum (...args2) {
result = args2.reduce((prev, item) => prev + item, result)
return sum
}
sum.toString = function () {
return result
}
return sum
}
console.log(add(1))
console.log(add(1)(2))
console.log(add(1)(2)(3))
console.log(add(1, 2)(3, 4)(5))
console.log(add(1, 2, 3)(4)(5)(6))
// https://wsvincent.com/javascript-currying/
const curry = (fn, ...args) =>
(fn.length <= args.length) ?
fn(...args) :
(...more) => curry(fn, ...args, ...more);
function redu (a, b, c) {
console.log(Array.from(arguments).reduce((a, b) => a + b))
}
function currying (fn) {
var refn
return function name (...arg) {
refn = (refn || fn).bind(null, ...arg)
if (refn.length == 0) { // 如果传入的length 大于 剩余需要的length
refn()
refn = null
}
return name
}
}
var add = currying(redu)
// 返回的add 实际上是我的 name name 会访问父作用域的 refn refn 就是我已经绑定了 多次传入了参数的fn函数
add(1, 2)(3);
add(1)(2)(3)
add(1, 2, 3)
function sum () {
var arr = Array.from(arguments)
addsum = function() {
arr.push(...arguments)
return addsum
}
addsum.toString = function () {
arr.push(...arguments)
return arr.reduce((a,b)=>a+b)
}
return addsum;
}
看不懂 toString 的建议看看这篇文章 https://www.cnblogs.com/coco1s/p/6509141.html
const add = (...args) => {
const sum = (...args2) => {
args = args.concat(args2)
return sum
}
sum.toString = () => {
return args.reduce((a, b) => a +b, 0)
}
return sum
}
add(1)(2)(3, 4)
闭包的方式也可以实现
function add () {
let eventList = []
for (let i = 0; i < arguments.length; i++) {
eventList.push(arguments[i])
}
function a () {
for (let i = 0; i < arguments.length; i++) {
eventList.push(arguments[i])
}
return a
}
setTimeout(() => {
log(eventList.reduce((a,b) => a + b))
},0)
return a
}
//加() 立即执行的
const curry = (fn, arr = []) =>
(...args) => ((a, b) => b.length === 0 // 判断
? fn(...a)
: curry(fn, a))([...arr, ...args], [...args])
let curryPlus = curry((...x) => x.reduce((a, b) => a + b)) // 函数累加
console.log(curryPlus(1, 2, 3)());
function autoCurry (fn, ...args) {
if (fn.length <= args.length) {
return fn(...args)
} else {
return function (...args2) {
return autoCurry(fn, ...args, ...args2)
}
}
}
function add (x, y, z) {
return x+y+z;
}
var addCurry = autoCurry(add, 1)
console.log(addCurry(2)(3)) // 6
console.log(addCurry(2,3)) // 6
console.log(addCurry(2)()) // f (...args2) { ... }
自动柯里化,通用函数
实现 1:
function currying(fn, length) { length = length || fn.length; // 注释 1 return function (...args) { // 注释 2 return args.length >= length // 注释 3 ? fn.apply(this, args) // 注释 4 : currying(fn.bind(this, ...args), length - args.length) // 注释 5 } }实现 2:
const currying = fn => judge = (...args) => args.length >= fn.length ? fn(...args) : (...arg) => judge(...args, ...arg)其中注释部分
- 注释 1:第一次调用获取函数 fn 参数的长度,后续调用获取 fn 剩余参数的长度
- 注释 2:currying 包裹之后返回一个新函数,接收参数为 ...args
- 注释 3:新函数接收的参数长度是否大于等于 fn 剩余参数需要接收的长度
- 注释 4:满足要求,执行 fn 函数,传入新函数的参数
- 注释 5:不满足要求,递归 currying 函数,新的 fn 为 bind 返回的新函数(bind 绑定了 ...args 参数,未执行),新的 length 为 fn 剩余参数的长度
你这写的必须最后加个()执行,不然得不到结果
function add(...arg) {
let res = 0;
function fn(...arg) {
res += arg.reduce((total, v) => total + v, 0);
return fn;
}
fn.toString = function () {
return res
}
return fn(...arg)
}
console.log(add(1))
console.log(add(1)(2))
console.log(add(1)(2)(3))
console.log(add(1, 2)(3))
console.log(add(1, 2, 3))
我觉得题目不严谨
function add() {
let res = [...arguments].reduce((a, b) => a + b, 0);
const fn = function () {
res = [...arguments].reduce((a, b) => a + b, res);
return fn;
};
fn.toString = fn.valueOf = () => res;
return fn;
}
const add = (...rest) => {
const args = rest
const addFunc = (...nextRest) => {
args.push(...nextRest)
return addFunc
}
addFunc.toString = () => {
return args.reduce((a, b) => a + b)
}
return addFunc
}
const add = (...args) => {
const _add = (...args1) => {
return add(...args, ...args1)
}
_add.toString = () => [...args].reduce((t, c) => t+c, 0)
return _add
}
add(1,2)(3)(4,5)(6)
toString实在过于hacky,这题本质和各种括号加减运算差不多
function add() {
const params = [...arguments]
recur.toString = acc;
return recur()
function acc() {
return params.reduce((acc, item) => {
acc += item;
return acc;
}, 0);
}
function recur() {
params.push(...arguments);
if (params.length >= 3) {
return acc()
} else {
return recur
}
}
}
console.log("debug-", add(1, 2));
console.log("debug-", add(1));
console.log("debug-", add(1, 2)(3));
console.log("debug-", add(1)(2, 3));
console.log("debug-", add(1)(2)(3));
console.log("debug-", add(1, 2, 3));
function add() { let args = [].slice.call(arguments); let fn = function(){ let fn_args = [].slice.call(arguments) return add.apply(null,args.concat(fn_args)) } fn.toString = function(){ return args.reduce((a,b)=>a+b) } return fn }
这返回的是函数啊??
单纯从题意触发,add调用时候必须有toString之类的触发条件;用外部变量保存每次执行累计的参数列表,执行完toString之后清空即可:
// * 柯理化函数
let concatArgs = []
function add(...args) {
concatArgs = concatArgs.concat(args)
return add
}
add.toString = function () {
const res = concatArgs.reduce((pre, cur) => pre + cur, 0)
concatArgs = []
return res
}
console.log(add(1)(2)(3) + "") // 6
console.log(add(1)(2, 3) + "") // 6
console.log(add(1, 2)(3) + "") // 6
console.log(add(1, 2, 3) + "") // 6
console.log(add(1).toString()) // 1
console.log(add(1)(2).toString()) // 3
console.log(add(1)(2)(3).toString()) // 6
console.log(add(1)(2, 3).toString()) // 6
console.log(add(1, 2)(3).toString()) // 6
console.log(add(1, 2, 3).toString()) // 6
题目不严谨,有歧义。
在实际项目中如果有这样的需求,或者用 toString 这种 hack 的方式实现。
感谢同事不杀之恩吧。
const money = add(1)(2)
typeof money // function
// 同事:“... wtf ?”
const money = add(1)(2)
if (money < 100) money(3)
// 同事:“???”
const money = add(1)(2)
console.log(money) // f 3
// 此处省略 100+ 行代码...
console.log(money) // money:“猜猜我变没变”
// ...卒
function add(...args) {
if (Number.prototype.add !== add) Number.prototype.add = add;
return args.reduce(
(pre, now) => pre + now,
this instanceof Number ? this : 0
);
}
修改Number满足吗
let timer = null function add(...arg1){ return function(...arg2){ let arg = [...arg1,...arg2] clearTimeout(timer) timer = setTimeout(()=>{ console.log(arg.reduce((p,c)=>p+c)) },0) return add(...arg); } } add(2,3)(4)(5,6)(9)()(1) //30
但是这个好像不能执行add(1,2,3)这种
做一个可循环调用add
函数,执行时把arg1
和arg2
内外传入的两个参数加到一块。函数的toString
方法在函数被alert
或者console
的时候会被调用,可以用这个方法来确定是否需要输出总结果。
function add (...arg1) {
let t = function (...arg2) {
return add(Array.from(arg1).concat(Array.from(arg2)).reduce((a, b)=> {return a+b}))
}
t.toString = ()=>{
return Array.from(arg1).reduce((a, b)=> {return a+b})
}
return t
}
add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
function add(...args) {
let final = [...args];
setTimeout(() => {
console.log(final.reduce((sum, cur) => sum + cur));
}, 0);
const inner = function (...args) {
final = [...final, ...args];
return inner;
}
return inner;
}
function add() {
var a = 0;
var out = arguments;
function sum() {
for(var i = 0; i < arguments.length; i++) {
a += arguments[i]
}
return sum
}
sum.toString = function() {
for(var i = 0; i < out.length; i++) {
a += out[i]
}
return a;
}
return sum;
}
const add=(a,b,c)=>a+b+c
const currying=(fn,length)=>{
length=length||fn.length
return (...args)=>args.length>=length?fn(...args):currying(fn.bind(this,...args),length-args.length)
}
const sum=currying(add)
console.log(sum(1)(2)(3));
console.log(sum(1,2)(3));
console.log(sum(1)(2,3));
console.log(sum(1,2,3));
function add() { let args = [].slice.call(arguments); let fn = function(){ let fn_args = [].slice.call(arguments) return add.apply(null,args.concat(fn_args)) } fn.toString = function(){ return args.reduce((a,b)=>a+b) } return fn }
const add=(...args)=>{
const fn=(...params)=>add(...args,...params)
fn.toString=()=>args.reduce((a,b)=>a+b)
return fn
}
console.log(add(1,2)(3).toString());
function add(...args) {
let nums = [...args];
function _add(...argsNext) {
if (argsNext.length === 0) {
// 不再有参数传入作为计算结果的信号
return nums.reduce((pre, cur) => {
return pre + cur;
}, 0);
} else {
nums.push(...argsNext);
return _add;
}
}
return _add;
}
function add(...a){
let sum = (...b) => add(...[...a,...b]); //合并参数
let result = a.reduce((x,y) => x+y); //对所有参数进行累加
sum.toString = () => result; //将结果返回
return sum;
}
console.log(add(1,2,3)(2,2).toString()); //10
为什么console的时候不会自动调用 toString方法呢,上面的答案在我的chrome控制台里返回的都是函数
function add(...args1) {
let x = args1.reduce((c,r)=>{return c+r},0)
console.log(x)
return function(...args2){
return add(...args2,x);
};
}
add(1,2)(2)(1,3,4)
可以实现连续不定参数的调用,返回参数和
function add () {
let sum
let arg = [].concat(...arguments)
const fn = function () {
arg = arg.concat(...arguments)
sum = arg.reduce((pre, next) => pre + next)
return fn
}
fn.toString = function () {
return sum
}
return fn()
}
console.log('//' + add(1, 2)(3)()(4, 5, 6))
function addFn(...args) {
return args.reduce((acc, cur) => acc + cur)
}
function currying(fn) {
let args = []
return function demo(...arg) {
console.log(args);
if (arg) {
args = [...args, ...arg]
return demo
} else {
return fn.apply(this, args)
}
}
}
const add = currying(addFn)
console.log(add(1)(2)(3)());
console.log(add(1)(2,3));
var twoSum = function(nums, target) {
const map = {}
for (let i = 0 ;i < nums.length; i ++ ){
if(map[target - nums[i] ] >= 0) {
return [map[target - nums[i]],i]
}
map[nums[i]] = i;
}
};
为什么console的时候不会自动调用 toString方法呢,上面的答案在我的chrome控制台里返回的都是函数
我也遇到了类似的问题,toString的方案在新版的Chrome(我的版本是98)似乎不起作用,打印出来的是一个函数,需要显式调用才能返回结果
function add(a) {
var curSum = a;
function res(b) {
curSum += b
return res
}
res.toString = function () {
return curSum
}
return res
}
建议把题目描述清楚
sum = (...nums)=>{
let res = 0;
sum2 = (...nums2)=>{
res = nums2.reduce((acc,cur)=>acc + cur, res);
console.log(res)
return sum2;
}
return sum2(...nums)
}
// 实现 sum 函数
//sum(1)(2)(3)
//== 6; // true
//sum(1, 2, 3) //== 6; // true
// sum(1); // 1
// sum(1)(2); // 3
// sum(1)(2)(3) // 6
// sum(1)(2, 3) // 6
// sum(1, 2)(3) // 6
// sum(1, 2, 3) // 6
如果只是打印结果不返回值的话,用个宏任务
function add() {
let sum = {current: 0}
sum.current = [...arguments].reduce((a, b) => a + b)
setTimeout(() => {
console.log(sum.current)
})
function _add() {
sum.current += [...arguments].reduce((a, b) => a + b)
return _add
}
return _add
}
add(1, 2)(3, 4)(5)
add(1)(2)(3)(4, 5, 6)
add(1, 2, 3)
上面那些toString的都是隐式调用的,结果拼接个字符串,或者非全等比较,就这样
add(1, 2)(3) + ''
add(1, 2)(3) == 6
题目有让你们调用toString?个个在这乱抄,就不会运行一下?
题目有让你们调用toString?个个在这乱抄,就不会运行一下?
这位同学,不必用这种口气说话
function add(...args) {
const fn = (...newArgs) => add(...args, ...newArgs);
fn.valueOf = () => args.reduce((acc, curr) => acc + curr, 0);
return fn;
}
function add(){
let sum = 0
function innerAdd(...args){
if(args.length===0){
return sum;
}
sum+=args.reduce((a,b)=>a+b,0)
return innerAdd;
}
return innerAdd(...arguments)
}
// 函数求和
function sumFn(...rest) {
return rest.reduce((a, b) => a + b);
}
// 柯里化函数
var currying = function (func) {
// 保存所有传递的参数
const args = [];
return function result(...rest) {
// 最后一步没有传递参数,如下例子
if(rest.length === 0) {
return func(...args);
} else {
// 中间过程将参数push到args
args.push(...rest);
return result; // 链式调用
}
}
}
// 测试
currying(sumFn)(1)(2)(3)(4)(); // 10
currying(sumFn)(1, 2, 3)(4)(); // 10
function curry(fn, acc, initValue) {
let args = [];
fun.toString = function () {
if (args.length === fn.length) {
return fn.apply(this, args);
}
const result = args.reduce(acc, initValue);
args = [];
return result;
};
return fun;
function fun() {
let result = fun;
args = args.concat([...arguments]);
if (args.length === fn.length) {
result = fn.apply(this, args);
args = [];
}
return result;
}
}
var add = curry(
(a, b, c) => {
return a + b + c;
},
(acc, a) => acc + a,
0
);
console.log(add(1).toString()); // 1
console.log(add(1)(2).toString()); // 3
console.log(add(1)(2)(3)); // 6
console.log(add(1)(2, 3)); // 6
console.log(add(1, 2)(3)); // 6
console.log(add(1, 2, 3)); // 6