美文网首页
js实现链式加法的思考

js实现链式加法的思考

作者: miao8862 | 来源:发表于2021-04-17 00:11 被阅读0次

由一道面试题引出的思考:
实现一个add函数,支持对多个参数求和以及多次调用求各,如下效果:

add(1) // 1
add(1)(2) // 3
add(1,2) //3
add(1,2,3)(4)(6) // 13
  1. 对于不定参的实现,很容易,使用arguments获取所有参数,然后使用reduce来实现累加
function add() {
  console.log(arguments); // [Arguments] { '0': 1, '1': 2, '2': 3 }
  return [...arguments].reduce((total, num) => {
    return total + num;
  })
}

console.log(add(1,2,3));
  1. 因为要求是链式的,所以我们必须返回的是一个函数
    这里,我们可以利用柯里化的思想,将多个参数的函数转化为一次只处理一部分参数的函数

什么是柯里化

柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

这句话听起来不太好理解,可以用代码来理解:

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

console.log(add.length) // 2, 返回的是这个函数对应的参数个数


// 使用柯里化后,函数变为:
function _add(x) {
  return function(y) {
    return function(z) {
      return x + y + z
    }
  }
}
// 调用形式可以变成 _add(x)(y)(z)

柯里化的实现

// 原函数
function add(x, y, z) {
  return x + y;
}


// 柯里化的实现
function curry(fn, args = []) {
  // 获取函数的参数个数
  let len = fn.length;
  // 返回一个函数,用于链式调用
  return function(...newArgs) {
    // 将内层参数和外层参数合并
    args = [...args, ...newArgs]
    // 当合并的参数还小于fn所需的参数个数时,继续递归收集参数,直至参数够了为止
    if(args.length < len) {
      return curry.call(this, fn, args)
    }

    // 收集够参数后,调用fn函数,相当于调用:fn(...args)
    return fn.apply(this, args)
  }
}

// add(x, y)
const _add = curry(add)

// 柯里化后,参数传参变成任意组合形式
// _add(x)(y)(z)
// _add(x, y)(z)
// _add(x)(y, z) 
const res = _add(2,3)(8)
console.log(res); // 13

// 注意,不能同时调用,因为_add在res时已经执行过函数了,即停止返回函数了,所以这几个调用是不能同时出现的
// 这里只是为了演示结果,才放多一个出来看
const res2 = _add(2)(3)(8)
console.log(res2);  // 13

但是这个题目并不是我们设定的固定已知参数长度,而是任意长度,那么判断在什么时候结束递归,执行函数就是我们接下来要解决的事情.

可以按照柯里化的思想,改进上面的add函数,可以实现链式调用
利用打印函数会自动调用toString()方法,和使用函数进行运算时,会默认调用valueOf的方法,我以此设为停止条件
但在nodejs里是要手动调用toString()或valueOf()调用时才停止,怎么才能自动检测到最后一个链式调用呢?
在chrome浏览器里倒是能得出结果,但会有个f字符,感觉都不是最终答案

// 使用柯里化思想改进上面那个加法
function add(...args) {
  let arr = args
  // 返回一个函数,用于获取链式调用的参数
  function fn(...newArgs) {
    // 将内层参数和外层参数合并
    arr = [...arr, ...newArgs]
    // 返回函数本身
    return fn
  }

  // 在调用toString()或valueOf()方法时计算所有参数之和
  fn.toString = fn.valueOf = function() {
    return arr.reduce((total, num) => total + num)
  }
  return fn
}

// 在nodejs环境下,要手动调用才行,怎么才能自动检测到最后一个链式调用呢?
console.log(add(1)(2)(3).valueOf()) // 6
console.log(add(1)(2)(3).toString()) // 6

// chrome浏览器环境下,返回 ƒ 6
const res22 = add3(1)(2)(3)
console.log(res22) // ƒ 6

暂时没想到好的解决方案,有大佬会嘛,求请教~~~

相关文章

  • js实现链式加法的思考

    由一道面试题引出的思考:实现一个add函数,支持对多个参数求和以及多次调用求各,如下效果: 对于不定参的实现,很容...

  • JS链式加法实现

    方法一 方法二 方法三 方法四 方法五 继承、闭包、递归、柯里化 相关文章 JavaScript链式调用 add(...

  • 自制jquery-第一篇

    1, jquery.js脚本文件 2,实现链式调用的原理 非链式调用:$xxx.addClass("active"...

  • 链式编程

    链式编程 实现一个类似于 Masonry 的链式编程,加法。 第一步 我们需要一个返回值是 Int 的方法,入参应...

  • js链式函数的实现:()()()

    先看一个问题 有一个函数 multiply可以无限调用,如:multiply(1,2)(4)(1,2)(),求所有...

  • JavaScript 中的链式调用

    最近在看 jQuery 的源码,正好看到异步队列 Deferred 的实现,联想到链式调用的实现。 实现 在 JS...

  • 【加法笔记系列】JS 加法器模拟

    JS 加法器模拟,实现 半加器 全加器 波纹进位加法器 全部代码 补码 & 减法 常规位运算 位运算 & 简单的 ...

  • 链式编程实现加法计算器

    链式编程:是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好。a(1).b(2).c(3...

  • Closure

    JS当中的一段实现“加法器”的代码。 显然,fiveAdder是用来每次加5的加法器,而tenAdder是用来每次...

  • JS如何实现链式调用

    方法链,当方法的返回值是一个对象,这个对象就可以继续调用它的方法。一般当函数不需要返回值时,直接 return t...

网友评论

      本文标题:js实现链式加法的思考

      本文链接:https://www.haomeiwen.com/subject/fbaylltx.html