FE-Interview icon indicating copy to clipboard operation
FE-Interview copied to clipboard

第 15 题:实现 add(1)(2)(3)

Open lgwebdream opened this issue 4 years ago • 20 comments

欢迎在下方发表您的优质见解

lgwebdream avatar Jun 19 '20 12:06 lgwebdream

考点:函数柯里化

函数柯里化概念: 柯里化(Currying)是把接受多个参数的函数转变为接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。

1)粗暴版

function add (a) {
	return function (b) {
		return function (c) {
		    return a + b + c;
		}
	}
}
console.log(add(1)(2)(3)); // 6

2)柯里化解决方案

  • 参数长度固定
const curry = (fn) =>
(judge = (...args) =>
    args.length === fn.length
    ? fn(...args)
    : (...arg) => judge(...args, ...arg));
const add = (a, b, c) => a + b + c;
const curryAdd = curry(add);
console.log(curryAdd(1)(2)(3)); // 6
console.log(curryAdd(1, 2)(3)); // 6
console.log(curryAdd(1)(2, 3)); // 6
  • 参数长度不固定
function add (...args) {
    //求和
    return args.reduce((a, b) => a + b)
}

function currying (fn) {
    let args = []
    return function temp (...newArgs) {
        if (newArgs.length) {
            args = [
                ...args,
                ...newArgs
            ]
            return temp
        } else {
            let val = fn.apply(this, args)
            args = [] //保证再次调用时清空
            return val
        }
    }
}

let addCurry = currying(add)
console.log(addCurry(1)(2)(3)(4, 5)())  //15
console.log(addCurry(1)(2)(3, 4, 5)())  //15
console.log(addCurry(1)(2, 3, 4, 5)())  //15

Genzhen avatar Jun 23 '20 04:06 Genzhen

function currying(){
    let args = [...arguments]
    temp.getValue = ()=>{
        return args.reduce((a,b)=> a + b, 0)
    }
    function temp(...arg){
        if(arg.length){
            args = [
                ...args,
                ...arg
            ]
            return temp
        }
    }
    return temp
}

H246802 avatar Jul 15 '20 03:07 H246802

const add = (a: number, b: number, c: number) => a + b + c;

const adding = (...args: number[]) => args.reduce((pre, cur) => pre + cur, 0);

//参数确定
const curry = (fn: Function) => {
  let args = [];

  return function temp(...newArgs) {
    args.push(...newArgs);
    if (args.length === fn.length) {
      const val = fn.apply(this, args);
      args = [];
      return val;
    } else {
      return temp;
    }
  };
};

//参数不确定
const currying = (fn: Function) => {
  let args = [];

  return function temp(...newArgs) {
    if (newArgs.length) {
      args.push(...newArgs);
      return temp;
    } else {
      const val = fn.apply(this, args);
      args = [];
      return val;
    }
  };
};

const curryAdd = curry(add);
console.log(curryAdd(1)(2)(3)); // 6
console.log(curryAdd(1, 2)(3)); // 6
console.log(curryAdd(1)(2, 3)); // 6

let addCurry = currying(adding);
console.log(addCurry(1)(2)(3)(4, 5)()); //15
console.log(addCurry(1)(2)(3, 4, 5)()); //15
console.log(addCurry(1)(2, 3, 4, 5)()); //15

123456zzz avatar Jul 15 '20 17:07 123456zzz

function curring(fn,arr = []){
  var length = fn.length;
  return (...args) => {
   const currentArr = [...arr.push(args)]
   if(arr.length < length){
        return curring(fn,currentArr];
    } else {
         fn(...currentArr )
    }
  }
}

yaooooooooo avatar Jul 20 '20 01:07 yaooooooooo

function currying(fn, args = []) {
    return function temp(...innerArgs) {
        if (innerArgs.length > 0) {
            // 收集后面传入的参数
            args = [...args, ...innerArgs];
            // 返回函数供后面可以继续调用
            return temp;
        } else {
            const val = fn.apply(this, args);
            // 清空参数数组,为了保证下次执行函数可以继续迭代
            args = [];
            return val;
        }
    }
}
// 求和函数
const add = (...args) => args.reduce((a, b) => a + b);
let addCurry = currying(add)
console.log(addCurry(1)(2)(3)(4, 5)())  //15
console.log(addCurry(1)(2)(3, 4, 5)())  //15
console.log(addCurry(1)(2, 3, 4, 5)())  //15

GolderBrother avatar Jul 20 '20 15:07 GolderBrother

除了typeof为function 正常运算都没问题 function add(num) { const add2 = (num2) => { num = num + num2; add2.toString = () => num; return add2; } return add2; } add(1)(2)(3) + 5 // 11 add(1)(2)(3)(4) // ƒ 10

JL003 avatar Jul 24 '20 02:07 JL003

有个疑问,就是参数长度不固定时,addCurry(1)(2)(3)(4, 5)(),最后的需要加函数执行的(),但是题目不是没有吗,也就是只要addCurry(1)(2)(3)(4, 5)这样

ABoyCDog avatar Aug 11 '20 06:08 ABoyCDog

function curry(fn, ...args) {
    if (args.length >= fn.length) {
        return fn(...args);
    }

    return (...args2) => curry(fn, ...args, ...args2);
}

function sum(a, b, c) {
    return a + b + c;
}

let add = curry(sum);

console.log(add(1)(2)(3));

huzedong2015 avatar Sep 01 '20 03:09 huzedong2015

function add (...params) {
    let result = params.reduceRight((a, b) => a + b)
    const tmp = (...paramsInit) => {
        result = [...paramsInit, result].reduceRight((a, b) => a + b)
        return tmp
    }
    tmp.toString = () => `${result}`
    tmp.valueOf = () => result
    return tmp
}

可以这样实现 @ABoyCDog

mapoio avatar Oct 17 '20 07:10 mapoio

const curryAdd = (...args) => {
  const Add = (...args2) => {
    return curry(...args, ...args2)
  }
  Add.toString = () => args.reduce((t, v) => t+v);
  
  return Add
}

console.log(curryAdd(1)(2)(3,4))

m7yue avatar Feb 08 '21 07:02 m7yue

function curry(fn, args) {
  var length = fn.length;
  args = args || [];
  return function () {
    newArgs = args.conct(Array.prototype.slice.call(arguments));
    return newArgs.length < length
      ? curry.call(this, fn, newArgs)
      : fn.apply(this, newArgs);
  };
}

function multiFn(a, b, c) {
  return a * b * c;
}

var multi = curry(multiFn);

console.log(multi(2)(3)(4));

wjiantao avatar Jul 11 '21 14:07 wjiantao

const sum = (arr) => { return arr.reduce((pre, cur, index) => { return pre + cur }, 0) }

function add() { const outArgs = Array.from(arguments) let res = sum(outArgs);

function newAdd() { if (arguments.length > 0) { const innerArgs = Array.from(arguments); res += sum(innerArgs) return newAdd } else { return res; } }

newAdd.valueOf = function () { return res }

newAdd.toString = function () { return res + '' }

return newAdd }

var result = add(1, 2)(3)(4)(5); // 参数可能为多个的情况下

console.log(result());

geekftz avatar Jul 13 '21 23:07 geekftz

function curry(fn, args) {
    const { length } = fn;
    const params = args || [];
    return function() {
        const args = params.concat([].slice.call(arguments));
        if (args.length < length) {
            return curry.apply(this, fn, args); 
       } else {
           return fn.apply(this, args);
      }
   }
}

xcs-go avatar Jul 24 '21 08:07 xcs-go

const curryAdd = (...args) => {
  const Add = (...args2) => {
    return curry(...args, ...args2)
  }
  Add.toString = () => args.reduce((t, v) => t+v);
  
  return Add
}

console.log(curryAdd(1)(2)(3,4))

测一测吧,测好了再发出来。curry已经undefined了。

image

Evllis avatar Aug 11 '21 10:08 Evllis

const curry = (fn) => {
  const prevArgs = [];

  const rec = (...currArgs) => {
    prevArgs.push(...currArgs);
    
    if(fn.length - prevArgs.length <= 0) {
      return fn(...prevArgs);
    }
    
    return rec;
  }

  return rec;
}

const add = (a: number, b: number, c: number) => a + b + c;
const curryAdd = curry(add);

1uckyneo avatar Sep 28 '21 17:09 1uckyneo

函数的柯里化的应用

const curry = (fn, args) => {
  const length = fn.length;
  let _args = args || [];
  return function () {
    let argArray = _args.slice(0);
    for (let i = 0; i < arguments.length; i++) {
      argArray.push(arguments[i]);
    }
    if (argArray.length < length) {
      return curry(fn, argArray);
    } else {
      return fn.apply(this, argArray);
    }
  }
}
const add = curry(function (a, b, c) {
  return a + b + c;
})
console.log(add(1)(2)(3));

zizxzy avatar Nov 02 '21 13:11 zizxzy

const add = a => b => c => a + b + c

ikozn avatar Feb 26 '22 13:02 ikozn

function curry(fn) { const length = fn.length return function _curry(...args) { if (args.length >= length) { return fn.apply(this, args) } else { return _curry.bind(this, ...args) } } } // 测试 function add(x, y, z) { return this.val + x + y + z } let fun1 = curry(add) let obj = { val: 10, fun1 } console.log(obj.fun1(1)(2)(3))

wringY avatar Mar 28 '22 09:03 wringY

function curry(...args1) {
  const fn = args1[0]
  const restArgs = args1.slice(1)

  function curried(...args2) {
    return curry.call(this, fn, ...[...restArgs, ...args2])
  }

  curried.toString = function() {
    return fn.call(this, ...restArgs)
  }

  return curried
}

function sum(...args) {
  let result = 0

  args.forEach(arg => {
    result += arg
  })

  return result
}

const add = curry(sum)

// toString 修改了但是不生效,需要自己利用 + 操作符进行转换
console.log(+add(1)(2)(3, 4, 5))

chinbor avatar Aug 02 '23 06:08 chinbor

暴力写法

function add(a) {
  return function (b) {
    return function (c) {
      return a + b + c;
    };
  };
}

console.log(add(1)(2)(3))

如果不限调用3次呢,比如add(1)(2)(3)(4)返回8


// 通过返回一个拥有获取值方法的函数
function add(x) {
  let sum = x;

  function innerAdd(y) {
    sum += y;
    return innerAdd;
  }

  innerAdd.getResult = function () {
    return sum;
  };

  return innerAdd;
}

console.log(add(1)(2)(3)(4).getResult()); // 输出 10
// 缺点:获取值时需要额外调用.getResult()

题目没说add(1)(2)(3)就是返回值了,有没有可能是类里的方法

class MyNumber {
  constructor(value) {
    this.value = value;
  }
  add(num) {
    this.value += num;
    return this.add.bind(this);
  }
}
const myNum = new MyNumber(0);
myNum.add(1)(2)(3);
console.log(myNum.value);

函数柯里化

// Function.length返回函数必传参数的长度
const curry = (fn) => {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn(...args);
    } else {
      return function (...nextArgs) {
        return curried(...args, ...nextArgs);
      };
    }
  };
};
const baseAdd = (a, b, c) => a + b + c;
const add = curry(baseAdd);
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)(2)); // 返回方法
try {
  console.log(add(1)(2)(3)(4)); // 报错
} catch (error) {
  console.error(error);
}
// 缺点,baseAdd长度写死,比暴力好在修改baseAdd更简单

不限长度的函数柯里化

const infiniteCurry = (fn) => {
  let lastArgsLength = 0;
  return function curried(...args) {
    if (args.length === lastArgsLength) {
      return fn(...args);
    } else {
      lastArgsLength = args.length;
      return function (...nextArgs) {
        return curried(...args, ...nextArgs);
      };
    }
  };
};
const infiniteAdd = (...args) => {
  return Array.from(args).reduce((a, b) => a + b);
};
const add = infiniteCurry(infiniteAdd);
console.log(add(1)(2)());
console.log(add(1)(2)(3)());
console.log(add(1)(2)(3)(4)());
console.log(add(1, 2, 3)(4, 5)());
console.log(add(1, 2, 3, 4, 5, 6)());
// 缺点:获取值时要()

Kisthanny avatar Mar 20 '24 13:03 Kisthanny