从百度一面中我学到了啥?

558 阅读3分钟

柯里化

面试官看我的简历里有一个:“通过柯里化实现一个请求自动重试函数,一上来就让我写一个无限累加函数。”

我们先看看这个老生常谈的题目。

fn(1)(2)(3)()
// ans = 6

也就是说,我们多次调用,然后最后输出一个 6。

这个题目当然是不难的,我就直接把答案放在这里了。

我当时写第一种方法的时候出了些 bug,当时有一个参数传递错误,导致我 debug 了五分钟没跑出来(

function reduce(...args) {
  return args.reduce((x, y) => x + y)
}
function currying(fn) {
  let args = []
  return function temp(...newArgs) {
    if(newArgs.length > 0) {
      args = [...args, ...newArgs]
      return temp
    } else {
      const val = fn.apply(this, args)
      args = []
      return val
    }
  }
}
const fn = currying(reduce)
console.log(fn(1)(2)(3)())

然后我就立刻换了一种我更熟悉的写法

const sum = (...args) => {
  const f = (...newArgs) => sum(...args, ...newArgs)
  f.valueOf = () => args.reduce((x, y) => x + y, 0)
  return f
}
console.log(sum(1)(2)(3).valueOf())

这样得到答案后面试官就没说啥了,觉得应该是 ok 的。

然后问我柯里化的概念。

这一下让我不清楚了,我没记具体概念,大概说的是“使用闭包实现重复调用。”

面试官没说啥,但我觉得自己表述的并不是很清楚。

柯里化的概念

在计算机科学中,柯里化(英语:Currying ),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数,而且返回结果的新函数的技术。

这个技术由克里斯托弗·斯特雷奇以逻辑学家哈斯凯尔·加里命名的,尽管它是 Moses Schönfinkel 和戈特洛布·弗雷格发明的。柯里化其实也是函数式编程的思想。

柯里化的优点

  1. 单一原则:在函数式编程中,往往是让一个函数处理的问题尽可能单一,而不是一个函数处理多个任务。
  2. 提高维护性以及降低代码的重复性

柯里化的使用场景

就是我提到的自动请求重试咯~

当时面试官还让我写了一下我的自动请求重试的伪代码

匆匆忙忙,当时写的大概是这个样子。

function autoRetry(fn, maxTryTime) {
  // 初始化请求开始次数
  let tryTime = 0
  return function tryFunc(...args) {
  // 进行请求
   try {
    fn.apply(this, ...args)
   } catch {
    if (tryTime < maxTryTime) {
      return tryFunc
    } else {
      // 处理错误
    }
   }
  }
}

深拷贝的循环引用

第三个问题好像就是让我写一个深拷贝,也算常规题目了。

我很快写出来了,提了一嘴 A.A = A 是循环引用

function deepClone(target, map = new WeakMap()) {
  if (typeof target === 'object') {
    const newTarget = Array.isArray(target) ? [] : {}
    if (map.get(target)) return map.get(target)
    for(const key in target) {
      newTarget[key] = deepClone(target[key])
    }
    map.set(target, newTarget)
    return newTarget
  } else {
    return target
  }
}

然后面试官让我详细解释一下循环引用,然后我蒙住了,A.A = A 不够咩。

他说:“这样解释,我是不懂的。”

我来查查

循环引用是个啥

比如我们有这样的一个对象

image.png

我们可以看到循环引用是这样的

image.png

我们在进行拷贝的时候,会递归的进行拷贝不停歇,所以会造成循环引用。

所以你看我的代码,有一个 weakMap,他保留了映射关系,再次出现直接用之前的就行,不会一直 deepClone 下去。

那么这就是本次文章的全部内容啦。

感谢阅读~