[面试题目]如何实现multi(2)(3)(4)=24?

被一道面试题目难到了。
有函数multi(2)(3)(4)=24,算法是2X3X4=24。
求解multi函数。

求大神解答~

------------------分割线---------------------
最终采纳了@Ende93 的答案,感觉更优美一些。但是代码需要调整一下:

function multi(n){
  var fn = function(x) {
    return multi(n * x);
  };
  
  fn.toString = function() {
    return n;
  };
  
  return fn;
}

demo: http://jsfiddle.net/etianqq/7sjo4nwt/

------------------分割线---------------------
谢谢 @kikong 的comments,我之前想法是仓促些,之所以demo里面显示为24,是因为dom操作时自动调用了function.toString(),所以显示为数字了。
如果直接console.log(multi(2)(3)(4))--->function... ,如果是console.log(multi(2)(3)(4)+1)--->25.
所以,上面的方案还是有所欠缺的。

阅读 13.9k
14 个回答

首先返回值要是函数,其次要传递值:

function multi(n){
  var fn = function(x) {
    return multi(n * x);
  };
  
  fn.valueOf = function() {
    return n;
  };
  
  return fn;
}

multi(1)(2)(3)(4) == 24; // true

上诉代码来自于:codewar 加法链 Best Practices

这不就是函数柯里化嘛。
最简单的方式是定义一个正常的函数,然后用lodash或underscore或者其他类似库完成柯里化。方法如下:

var baseFun = function(a, b, c){
  return a * b * c;
}
var multi = _.curry(baseFun);
console.log(multi(2)(3)(4));

需要注意的是,柯里化需要指定总参数个数,在lodash中如果未指定则视为this.length,在上例中也就是3.
柯里化后的函数将在连续调用n次后返回所需的结果,n为刚刚说的参数个数。

当然,你也可以不用柯里化的方式,直接按对方的逻辑要求用递归简单的实现一下。。

function multi(v, last, times){
  times = (times || 0) + 1;
  last = (last || 1) * v;
  if(times < 3) {
    return function(v) {
      return multi(v, last, times);
    }
  } else {
    return last;
  }
}
console.log(multi(2)(3)(4));
function curry(fn){
   var value;
   var callback = function(next){
      value = typeof value === "undefined" ? next : fn.apply(null,[value,next]);
      return callback;
   }
   callback.valueOf = callback.toString = function(){
     return value;
   
   }
   return callback
}
//加
function add(x,y){
  return x + y
}
//减
function minus(x,y){
  return x -y
}
//乘
function multiply(x,y){
  return x * y;
}
//除
function divide(x,y){
  return x / y;
}
curry(add)(2)(3)(4)(5)(6) //2+3+4+5+6=20
curry(minus)(2)(3)(4)(5)(6) //2-3-4-5-6=-16
curry(multiply)(2)(3)(4)(5)(6) //2*3*4*5*6=720
curry(divide)(2)(3)(4)(5)(6) //2 / 3 / 4/ 5 /6 = 0.00555555...

你指的是这样么?

var multi = function(num1){
        return function(num2){
                return function(num3){
                        return num1 * num2 * num3;
                };
        };
};

var baseFun = function(a, b, c){
return a b c;
}
var multi = _.curry(baseFun);
console.log(multi(2)(3)(4));

var multi = x => y => z => x * y * z;
function multi(num){
  return function(secondNum){return function(thirdNum){return num*secondNum*thirdNum}}
}

函数curry化,提供一个类似的思路:

函数Curry(柯里)化(部分传参,返回一个已传部分参数的函数;适用于公用一个函数,且传给改函数的部分参数是相同的情况)

function curry (fn) {
     var slice = Array.prototype.slice,
          old_args = slice.call(arguments, 1);
     return function () {
          var new_args = slice.call(arguments),
               args = old_args.concat(new_args);
          return fn.apply(null, args);
     }
}

var add = function (x, y, z) {
     return x+y+z;
}

//一步curry化
curry(add, 1)(2, 3);     //返回6

//两步curry化
var addOne =  curry(add, 1);
var addTwo = curry(addOne, 2);
addTwo(3);     //返回6

实现1:)

var multi=function(arg0){
    return function(arg1){
        return function(arg2){
            return arg0*arg1*arg2
        }
    }
};

实现2:要多调用一次,可能和题目的要求不符,但提供了一种可以更多参数调用的可能,参考下

var multi=(function(){

    var result=1;
    return function __multi__(arg){
        if(!arg){
            return result;
        }
        result=result*arg;
        return __multi__;
    };
}());
···
console.log(multi(2)(3)(5)());
新手上路,请多包涵

currying。撸主可以去查一下~

这道题对于懂得/或者习惯函数式编程的不是事,但是对于一般的命令式/OO程序员一开始还真不容易让绕清楚。

看了各位大神的解答后,感觉很受启发。我试着写了一个科里化函数:

var curry = function(func) {
    var that=this;
    var curry_func = function() {
        var this_func = arguments.callee;
        var new_params = this_func.params.slice();
        for(var i=0;i<arguments.length;i++)
            new_params.push(arguments[i]);
        if(new_params.length >= func.length)
            return func.apply(that, new_params);
        else{
            // dirty way to copy function
            eval('var new_func =' + this_func.toString());
            new_func.params = new_params;
            return new_func;
        }
    };
    curry_func.params = [];
    return curry_func;
};

// 原函数
var test_func = function(a, b, c) { return a*b*c; };

var f0 = curry(test_func);

// 实现科里化功能
console.log(f0(2,3,4));
console.log(f0(2)(3)(4));
console.log(f0(2,3)(4));

// 科里化结果不会互相影响
f1 = f0(2,3);
console.log(f1(10));
console.log(f1(11));
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏