add(1,2).add(3,4)也能计算哦

906 阅读2分钟

见面先抛一道题:

// 实现一个add方法
add(1,2); // 3
add(1, 2).add(3, 4); // 10

有没有发现,这个有点像 add(1, 2)(3, 4) ?

add(1, 2)(3, 4) 用柯里化可以顺利解决:

function add() {
  let args = [...arguments];
  function _add () {
    args.push(...arguments);
    return _add;
  }
  _add.toString = function () {
    return args.reduce((acc, cur) => acc + cur);
  }
  return _add;
}

那么 add(1, 2).add(3, 4) 是否也能这样解决呢?

答案应该是否定的,因为看起来像是链式调用的方法,用柯里化来做会报错,柯里化会返回一个函数,但是已经不是刚开始调用的那个函数了,而是内部的一个函数(如: _add),所以直接刚上 add(1, 2).add(3, 4) 无疑是错误的。

上面说了,这种看上去像是链式调用,那么有没有方法实现呢?链式调用的关键的返回 this ,后面的函数才能正常执行,如:

function Student() {
  this.getName = function (name) {
    console.log('I am ' + name);
    return this;
  }
  this.getAge = function (age) {
    console.log('I am ' + age)
    return this;
  }
}

var student = new Student();
student.getName('pig').getAge(11);

可见,add(1, 2).add(3, 4) 使用链式调用是可以解决的,但是,链式调用需要对象来实现,这个是一个方法(add(1, 2).add(3, 4)),那么应该怎么办呢?我们其实可以将这个方法挂载在 Number 对象的原型上,这个就解决了需要对象的问题。

Number.prototype.add = function(x, y) {
  if (Object.prototype.toString.call(this).toUpperCase() !== '[OBJECT NUMBER]') {
    return (0).add(x, y);
  }
  // Number(this)是前面计算得到的值
  return Number(this) + x + y; 
}

var add = Number.prototype.add;
console.log(add(1, 2).add(3, 4)); // 10

等等!为什么不是返回this,而是返回相加结果???

因为返回的是数字类型,那么它就可以调用 Number 原型上面的方法,而且将结果返回来给下一个调用用,美滋滋!

如果输入的参数不一,其实也可以处理:

Number.prototype.add = function() {
  if (Object.prototype.toString.call(this).toUpperCase() !== '[OBJECT NUMBER]') {
    return (0).add(...arguments);
  }
  return arguments.length > 0 ? 
      Number(this) + ([...arguments].reduce((acc, cur) => acc + cur)) : Number(this);
}

var add = Number.prototype.add;
var number = add(1).add(2, 3).add(4, 5, 6).add(7, 8, 9, 10).add();
console.log(number); // 55

至此,我们结束了 add(1, 2).add(3, 4) 的解答了,而且得到了一些扩展的答案。

如果还有什么巧妙的方法, 请不吝指教!