一道前端函数面试题

这题的规则是这样的

给定有一个 Add 函数,要支持以下形式的调用

Add(1)(2)(3).sumOf(); // 输出 6
Add(1,2)(3)(4).sumOf(); // 输出 10
Add(1,2,...)(3)(4)(...).sumOf();  // ...

拿到这种题目,我先来说说我自己的做题流程,一般会去找它最简单的形态。我们一步一步来拆解。

先去掉 sumOf() 变成了以下形态

Add(1,2,...)(3)(4)(...)

嗯….有点熟悉…但是还是有点复杂,那我们再去掉无限调用这个限制。

Add(1,2,...)(3)(4)

唔,还是有点难呀…没关系,再砍, 不要传入多个参数。

Add(1)(2)(3)

有….有….有那味了….这….这不就是柯里化吗….

有些小朋友可能没有听过,对于大朋友而言耳熟能详,融会贯通。

我们还是来介绍一下。

在《javascript高级程序设计》这本书中有如下介绍:

与函数绑定紧密相关的主题是函数柯里化,它用于创建已经设置好的一个或者多个参数的函数。函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数。

我们来写写看:

function Add(x) {
 return function (y) {
  return return functio (z) {
   return x + y + z;
  }
 }
}
// 简洁写法
const Add = x => y => z => x+y+z;

执行一下

Add(1)(2)(3) // 6 

是我们要的那味~

那么我们既然已经写出了这个形态,我们就一步一步反推。

这个时候千万别紧张,我们从最低级的形态出发,写出一个最基本的形态,能够有效地帮助我们建立自信心,吃下定心丸,按照这种方式,哪怕我们最终没有写出完美的结果,让面试官看到你思考解题的过程,也是一种加分。

好,接着说~

那我们接下来需要实现这个样子。

Add(1,2,...)(3)(4)

传入参数不止一个

我们知道,对于不确定参数个数,我们可以使用 arguments 这个对象来获取到所有的入参,但是 arguments 不是一个 Array,但是我们可以使用 ES6 中的 Spread syntax (展开语法)去将他变成一个数组。表演继续。

function Add() {
 const nums = [...arguments];
 return function() {
  nums.push(...arguments);
  return function() {
   nums.push(...arguments);
   return nums.reduce((a, b) => a + b);
  }
 }
}

nice!已经离我们最终的形态越来越近了。接下来是这个函数能够无限的进行调用。

Add(1,2,...)(3)(4)(...)

那么怎么样才能无限调用呢?没错,用递归。

function Add() {
 const nums = [...arguments];
 function AddPro() {
  nums.push(...arguments);
    return AddPro;
 }
 return AddPro;
}

嗯,其实我们写到这里发现了… 由于是无限递归,我们没办法确定最后一次函数调用,因此我们需要最后显式调用一个结束的方法来打印出最后的数据。

很自然地,我们可以在 AddPro 添加一个方法 sumOf 来解决这个问题。

学弟就是卡在这里地方,被函数添加上一个方法搞懵了。你是否知道呢?

function Add() {
 const nums = [...arguments];
 function AddPro() {
  nums.push(...arguments);
    return AddPro;
 }
 AddPro.sumOf = () => {
  return nums.reduce((a, b) => a + b);
 }
 return AddPro;
}

好啦好啦,结束啦。

等等

在最后,我再来补充一种方案,function 不仅可以继续挂载 function ~ 还可以挂载变量哦~

function Add() {
 if (!Add.nums) {
   Add.nums = [];
  }
  Add.nums.push(...arguments);
  return Add;
}
Add.sumOf = () => {
 return Add.nums.reduce((a, b) => a + b);
}

如果上述回答有更优解,请公众号后台回复,留下你的微信,红包相送。

我们总结一下,小小的面试题涉及到的基础知识。

闭包、递归、作用域、函数与对象

基础就是基础,永远是你爸爸,掌握好基础,以不变应万变。

一个彩蛋

function Add() {
 const nums = [...arguments];
 return () => {
  nums.push(...arguments);
  return () => {
   nums.push(...arguments);
   return nums.reduce((a, b) => a + b);
  }
 }
}
// 如果我上述代码中间换成箭头函数又会怎么样呢~,思考一下
Like (0)
Donate 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
ZEROZERO
Previous 2020年9月8日
Next 2020年11月24日

相关推荐

  • HTTP 常见的面试题图解

    前言 在面试过程中,HTTP 被提问的概率还是比较高的。小林我搜集了 5 大类 HTTP 面试常问的题目,同时这 5 大类题跟 HTTP 的发展和演变关联性是比较大的,通…

    2020年3月17日
    1.5K
  • 前端开发工程师怎样独立调试前端项目?

    在前后端分离开发的大环境下,前端开发已经不仅仅局限于所谓的切图,写页面的工作,同时,也给前端开发定义了新的含义。有前后端分离项目开发的工程师,都知道,这样的项目开发起来有多么的方便…

    2020年8月31日
    1.5K
  • 简单酷炫的hover效果,值得收藏

    在浏览B站的时候,发现一个简单酷炫的hover效果的制作视频。浏览完之后,发现其中包含的知识点蛮经典的,特此收藏。 HTMl结构布局很普通,就是简单的一个水平垂直方向居中的表单,代…

    2020年7月20日
    1.8K
  • Webpack入门,打包第一个工程

    简介 Webpack是一个开源的JavaScript模块打包工具,其最核心的功能是解决模块之间的依赖,把各个模块按照特定的规则和顺序组织在一起,最终合并为一个JS文件(有时会多个)…

    2022年11月8日
    411
  • Angular与vue对比

    Vue.js 是开源的 JavaScript 框架,能够帮助开发者构建出美观的 Web 界面。当和其它网络工具配合使用时,Vue.js 的优秀功能会得到大大加强。如今,已有许多开发…

    2019年6月13日
    1.7K
  • 异步神器async-await

    async-await和Promise的关系 async-await是建立在promise机制之上 ,async-await是promise和generator的语法糖。增强了代码…

    2019年6月3日
    1.5K
  • typeof 和 instanceof的区别

    在前端开发过程中,typeof与instanceof是经常要用到的, 了解两者的区别是每一个合格前端工程师所要掌握的。 JavaScript中typeof和instanceof常用…

    2019年6月18日
    1.6K
  • 浏览器渲染机制

    为什么要了解浏览器渲染页面机制?主要是还是性能的优化。 了解浏览器如何进行加载,我们可以在引用外部样式文件、外部JS时,将它们放到合适的位置,是浏览器以最快的速度,将文件加载完毕。…

    2019年5月31日
    1.6K
  • vue开发小程序项目总结

    最近全权负责一个小程序的前端开发工作,之前小程序使用原生技术开发过一版,当时由于进入项目组晚,且项目开发周期短,没有详细了解项目的各种情况,导致后期开发过程中出现各种各样的让人烦心…

    2020年11月24日
    1.4K
  • HTTP三次握手与四次挥手详解

    前端工程师面试的时候,关于HTTP三次握手是最常被询问的一个知识点,往往很多人,都是知道其原理及过程,就是用话语表达不出来,正式一点,就是词不达意。今天浏览到一篇关于HTTP三次握…

    2019年12月6日
    1.6K

发表回复

Please Login to Comment