Daily-Interview-Question icon indicating copy to clipboard operation
Daily-Interview-Question copied to clipboard

第 84 题:请实现一个 add 函数,满足以下功能。

Open yygmind opened this issue 5 years ago • 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

yygmind avatar May 30 '19 00:05 yygmind

之前写过 2 篇文章,可以参考一二。 1、【进阶 6-1 期】JavaScript 高阶函数浅析 2、【进阶 6-2 期】深入高阶函数应用之柯里化

其中第一篇文章给出了前三个功能的实现,并没有覆盖到后面三种。 第二篇文章实现了一个通用的柯里化函数,覆盖实现了所有功能。

yygmind avatar May 30 '19 00:05 yygmind

实现 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 剩余参数的长度

yygmind avatar May 30 '19 00:05 yygmind

const curry = (fn, arity = fn.length, ...args) =>
  arity <= args.length ? fn(...args) : curry.bind(void 0, fn, arity, ...args);

ZodiacSyndicate avatar May 30 '19 00:05 ZodiacSyndicate

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
}

zhouyangit avatar May 30 '19 01:05 zhouyangit

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;
}

ablikim915 avatar May 30 '19 01:05 ablikim915

还有一种方法

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)();

ablikim915 avatar May 30 '19 01:05 ablikim915

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))

GitHdu avatar May 30 '19 02:05 GitHdu

function add(...args) {
  let sum = 0;
  const innerAdd = (...args) => {
    args.forEach(i => (sum += i));
    return innerAdd;
  };
  innerAdd.toString = () => sum;
  return innerAdd(...args);
}

CoffeeWorm avatar May 30 '19 03:05 CoffeeWorm

如果要做成高阶函数以便支持任意迭代器,累加器的初始值设定要麻烦一点 尤其是考虑到任意长度输入和空输入,要多一些判断逻辑。

写了一个支持以上所有特性的

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));
});

seognil avatar May 30 '19 07:05 seognil

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;
}

linchengzzz avatar May 30 '19 09:05 linchengzzz

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 avatar May 31 '19 01:05 wjryours

@wjryours sum 函数定义的参数长度为 3,调用时参数为 4,所以问题出在这里

yygmind avatar May 31 '19 03:05 yygmind

@wjryours sum 函数定义的参数长度为 3,调用时参数为 4,所以问题出在这里

柯里化生成的 add 函数若是存储的形参个数达不到定义的参数长度, 则是返回 [Function]

那么如题 add(1) ==>1 , add(1)(2) ==> 3 则不是没有实现吗

ryanZiegler avatar May 31 '19 03:05 ryanZiegler

@wjryours sum 函数定义的参数长度为 3,调用时参数为 4,所以问题出在这里

柯里化生成的 add 函数若是存储的形参个数达不到定义的参数长度, 则是返回 [Function]

那么如题 add(1) ==>1 , add(1)(2) ==> 3 则不是没有实现吗

我想表达的就是这个意思,按照你这个写法那些基本的功能都通过不了,可以解答一下吗@yygmind

wjryours avatar May 31 '19 03:05 wjryours

@wjryours sum 函数定义的参数长度为 3,调用时参数为 4,所以问题出在这里

柯里化生成的 add 函数若是存储的形参个数达不到定义的参数长度, 则是返回 [Function] 那么如题 add(1) ==>1 , add(1)(2) ==> 3 则不是没有实现吗

我想表达的就是这个意思,按照你这个写法那些基本的功能都通过不了,可以解答一下吗@yygmind

我觉得题目出的不好(描述有歧义)。 我的理解里,题目本身和柯里化是有差异的, 题目更像是迭代器而不是柯里化

如果是柯里化,那么缺少参数的时候是等待所有参数到齐则再开始进行运算,并返回计算结果。 (因为不是所有方法都像 add 一样简单,能支持部分参数计算,不然因为缺少参数,计算逻辑报错了怎么办?) 参数不足的时候返回一个中间 function,以便继续调用。

至于直接能读到(toString),这是一个 trick。 对于柯里化这个高阶方法来说,我觉得不应该一起实现。 就像我说的,是应该等参数到齐再计算(固定参数 function 的 length), 可以参考一下 lodash 或者 ramda 里的 curry

至于如何实现题目本身 (任意长度也能返回计算结果,也就是说,调用一次执行一次) (像我上面说的,更像是实现一个迭代器,add 只是一个算子) 可以参考一下我的答案 https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/134#issuecomment-497232565 Inspired by @CoffeeWorm https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/134#issuecomment-497185092

seognil avatar May 31 '19 04:05 seognil

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);

B2D1 avatar Jun 20 '19 03:06 B2D1

 // 第一步,先实现加和运算

            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

woyiweita avatar Jun 25 '19 09:06 woyiweita

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>

libin1991 avatar Jul 09 '19 16:07 libin1991

`

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;
}

`

linushp avatar Jul 11 '19 07:07 linushp

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;
}

negativeentropy9 avatar Jul 14 '19 05:07 negativeentropy9

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

harryliuy avatar Jul 17 '19 12:07 harryliuy

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
}

gitHber avatar Jul 18 '19 08:07 gitHber

诸位真的是大佬---膜拜了 我看了半天算是看懂函数柯里化的应用了

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))

Yxiuchao avatar Jul 19 '19 07:07 Yxiuchao

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 是怎么调用的... 看你的回答 太真实了

xiabeizi avatar Jul 19 '19 08:07 xiabeizi

感觉关键点在重写函数toString方法啊,我就一直在想,怎么又返回函数,而最后又输出结果,真棒!

PatrickLh avatar Jul 21 '19 03:07 PatrickLh

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 

使用了一个闭包完成了这个效果

xtxt5555 avatar Jul 28 '19 02:07 xtxt5555

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 1f 6...

image

w3cmark avatar Aug 05 '19 02:08 w3cmark

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();

caihaihong avatar Aug 13 '19 09:08 caihaihong

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 1f 6...

image

在不知道会一直调用多少次的情况下, 不返回一个函数, 怎么能够继续调用呀

xtxt5555 avatar Aug 14 '19 12:08 xtxt5555

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); }

ToBeNumeroOne avatar Aug 19 '19 09:08 ToBeNumeroOne

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 给的方法做下翻译

XJawher avatar Aug 21 '19 00:08 XJawher

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;
}

yaodongyi avatar Sep 12 '19 05:09 yaodongyi

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 }

dongkeng001 avatar Oct 10 '19 02:10 dongkeng001

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
}

Wuxiaa avatar Oct 31 '19 15:10 Wuxiaa

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) 就不行啊大佬

dbfterrific avatar Nov 09 '19 10:11 dbfterrific

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));

2118180500 avatar Nov 22 '19 12:11 2118180500

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 都是函数类型

bbrucechen avatar Dec 25 '19 07:12 bbrucechen

感觉大家的办法都有问题啊。。。这题是不是出的不太好

bbrucechen avatar Dec 25 '19 08:12 bbrucechen

诸位真的是大佬---膜拜了 我看了半天算是看懂函数柯里化的应用了

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))

你这个也不行兄弟。。。

bbrucechen avatar Dec 25 '19 08:12 bbrucechen

function add(...args1) {
    function innerAdd(...args2) {
        args1 = [...args1, ...args2];
        return innerAdd;
    }

    innerAdd.toString = function() {
        return args1.reduce((sum, cur) => sum + cur, 0);
    }

    return innerAdd;
}

yinzuowen avatar Jan 10 '20 09:01 yinzuowen

厉害了,看似柯里化,其实考的是...

jwdzzhz777 avatar Jan 16 '20 11:01 jwdzzhz777

会这道的都是大佬吧...

Hjw52 avatar Feb 12 '20 08:02 Hjw52

// 定义累加函数
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

fatesigner avatar Feb 19 '20 04:02 fatesigner

function add(...args) {
  if(args.length === 3) return args.reduce((a,b) => a+b, 0)
  return add.bind(null, ...args)
}

blingboot avatar Mar 14 '20 08:03 blingboot

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))

zuoyi615 avatar Apr 17 '20 08:04 zuoyi615

// https://wsvincent.com/javascript-currying/
  const curry = (fn, ...args) =>
    (fn.length <= args.length) ?
      fn(...args) :
      (...more) => curry(fn, ...args, ...more);

random-yang avatar Apr 17 '20 15:04 random-yang

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)

LFdeWeb avatar Apr 19 '20 15:04 LFdeWeb

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; }

zhangsim avatar Apr 19 '20 15:04 zhangsim

看不懂 toString 的建议看看这篇文章 https://www.cnblogs.com/coco1s/p/6509141.html

Liu-10004 avatar Apr 27 '20 03:04 Liu-10004

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)

qianlongo avatar May 12 '20 13:05 qianlongo

闭包的方式也可以实现

    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
    }

ac731064535 avatar Jun 10 '20 08:06 ac731064535

image

alan1111 avatar Jun 30 '20 06:06 alan1111

//加() 立即执行的 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)());

fariellany avatar Jun 30 '20 09:06 fariellany

     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) { ... } 

自动柯里化,通用函数

Fan-zexu avatar Jul 09 '20 03:07 Fan-zexu

实现 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 剩余参数的长度

你这写的必须最后加个()执行,不然得不到结果

pzl1026 avatar Jul 11 '20 03:07 pzl1026

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))

hjiog avatar Jul 13 '20 15:07 hjiog

我觉得题目不严谨

taichiyi avatar Jul 21 '20 09:07 taichiyi

https://theanubhav.com/2019/02/03/js-currying-in-interview/#first-implement-add23-in-javascript

muzichen avatar Sep 03 '20 03:09 muzichen

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;
}

z253573760 avatar Oct 03 '20 08:10 z253573760

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
}

zhongyangxun avatar Oct 12 '20 13:10 zhongyangxun

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)

m7yue avatar Oct 16 '20 06:10 m7yue

toString实在过于hacky,这题本质和各种括号加减运算差不多

ItoshikiNozomu avatar Dec 24 '20 14:12 ItoshikiNozomu

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));

negativeentropy9 avatar Feb 22 '21 01:02 negativeentropy9

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
}

这返回的是函数啊??

pureZjr avatar Feb 22 '21 02:02 pureZjr

单纯从题意触发,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

orime avatar Mar 01 '21 06:03 orime

题目不严谨,有歧义。

在实际项目中如果有这样的需求,或者用 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:“猜猜我变没变”

// ...卒

WayneGongCN avatar Mar 01 '21 08:03 WayneGongCN

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满足吗

dengbupapapa avatar Mar 04 '21 03:03 dengbupapapa

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)这种

crush12132 avatar Apr 11 '21 02:04 crush12132

做一个可循环调用add函数,执行时把arg1arg2内外传入的两个参数加到一块。函数的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
}

slc3a2 avatar Apr 30 '21 09:04 slc3a2

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;
}

zhelingwang avatar May 10 '21 10:05 zhelingwang

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;

}

tianfengbiao avatar Jul 31 '21 03:07 tianfengbiao

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));

qinyakang avatar Sep 02 '21 09:09 qinyakang

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());

qinyakang avatar Sep 02 '21 09:09 qinyakang

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;
}

SH-dxj-SF avatar Sep 15 '21 12:09 SH-dxj-SF

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

xiangfei1 avatar Oct 21 '21 03:10 xiangfei1

为什么console的时候不会自动调用 toString方法呢,上面的答案在我的chrome控制台里返回的都是函数

z547224313 avatar Oct 29 '21 08:10 z547224313

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)

可以实现连续不定参数的调用,返回参数和

virgo-van avatar Nov 01 '21 08:11 virgo-van

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))

zhangtaolei avatar Nov 20 '21 07:11 zhangtaolei

 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));

SnailOwO avatar Dec 23 '21 07:12 SnailOwO


 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;   
    }
};

yangfan-coder avatar Dec 28 '21 08:12 yangfan-coder

为什么console的时候不会自动调用 toString方法呢,上面的答案在我的chrome控制台里返回的都是函数

我也遇到了类似的问题,toString的方案在新版的Chrome(我的版本是98)似乎不起作用,打印出来的是一个函数,需要显式调用才能返回结果

CHristopherkeith avatar Feb 14 '22 05:02 CHristopherkeith

function add(a) {
    var curSum = a;
    function res(b) {
        curSum += b
        return res
    }
    res.toString = function () {
        return curSum
    }
    return res
}

Lingdeqing avatar Mar 19 '22 07:03 Lingdeqing

建议把题目描述清楚

chengfengfengwang avatar Apr 30 '22 13:04 chengfengfengwang

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

CHENJIAMIAN avatar Sep 09 '22 08:09 CHENJIAMIAN