前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面字节涨薪70%:朋友却说这题目太没挑战了

面字节涨薪70%:朋友却说这题目太没挑战了

作者头像
前端胖头鱼
发布2022-07-25 08:41:53
2490
发布2022-07-25 08:41:53
举报
文章被收录于专栏:胖头鱼学前端胖头鱼学前端

前言

最近有个好哥们面试阿里字节...等一众一线互联网大厂,全部收割了offer,堪称收割机中的战斗机,然而一面的部分题目,在他眼里,却很没挑战(确实是有资本,哈哈哈),到底是啥...一起来学习一波。

1.# 查找两个DOM节点的最近公共父节点

oNode1和oNode2在同一文档中,且不会为相同的节点,寻找这两个节点最近的一个共同父节点,可以包括节点本身。

代码语言:javascript
复制

function findCommonParent(oNode1, oNode2) {
  // 填充这里
}

看到这个题目相信大家和我一样,冥冥中感觉似乎会用到递归,但是还没啥明确的思路。

这时候千万不能慌,一定要稳住心神,从题目中找出更多有效的信息,并尝试多画图,多动笔(如果是现场面试,记得带只笔,多画画有时候思路就出来了)

1.1# 两个节点同级

一张网页可以看成是一棵N叉树,。要在茫茫众多节点中找到他们的最近的共同祖先,可以尝试先画一下这两个节点可能存在的关系,如下图,他们的直接父节点就是要找的目标节点

1.2# 两个节点是互为祖先关系

如下图,oNode1就是目标节点,可以通过oNode1.contains(oNode2)得到节点2被节点1包含,当然反过来是一样的。oNode2也可以是oNode1的祖先

1.3# 两个节点没有半毛钱关系

如下图,两个节点隔了十万八千里,谁都不认识谁,但是有一点,如果按照某个节点一直往上查找,一定可以找到某个点包含oNode1或者oNode2.

1.4# 递归实现版本

根据上面画的几张图,相信你很快就可以写出下面的代码。

代码语言:javascript
复制
function findCommonParent(oNode1, oNode2) {
  // 判断情况1和2 
  if (oNode1.contains(oNode2)) {
    return oNode1
    // 判断情况1和2
  } else if (oNode2.contains(oNode1)) {
    return oNode2
  } else {
    // 判断情况3,从其中一个节点往上查找,会找到一个共同的祖先节点
    return findCommonParent(oNode1.parentNode, oNode2)
  }
}

1.5# 遍历实现版本

递归实现很好理解,仅仅通过遍历能不能实现呢?其实往往递归的问题都可以通过遍历去解决.

代码语言:javascript
复制
function findCommonParent (oNode1, oNode2) {
  // 这里用oNode2是一样的
  // 如果某个节点包含另一个节点,直接返回,否则不断往上查找
  while (!oNode1.contains(oNode2)) {
    oNode1 = oNode1.parentNode 
  }

  return oNode1
}


2.# cookie和localstorage 的概念和区别,设计一个可以设置有效期的localstorage API

cookielocalstorage有什么区别,相信大家直接开口就能说出来,这里我们关键看如何实现一个有过期时间的localstorage

解题思路

localstorage不同于cookie会自动过期,过期时间需要自己维护,在setItem时,将过期时间种下,getItem时将种下的时间与当前时间进行对比,如果大于当前时间,将值返回即可,否则需要通过removeItem将值移除,并且返回null

代码语言:javascript
复制
const storage = {
  prefix: 'fatFish',
  timeSign: '|fatFish|',
  setItem (key, value, time) {
    // 做一个key的保护
    key = `${this.prefix}${key}`
    // 没有传入时间,默认过期时间是一个月,当然也可以是其他时间或者不设置
    time = time ? new Date(time).getTime() : Date.now() + 24 * 60 * 60 * 31 * 1000
    // 构造一个形如 1646094676134|fatFish|"前端胖头鱼" 结构的字符串
    window.localStorage.setItem(key, `${time}${this.timeSign}${JSON.stringify(value)}`)
  },
  getItem (key) {
    key = `${this.prefix}${key}`
    let value = window.localStorage.getItem(key)

    if (value) {
      let index = value.indexOf(this.timeSign)
      let time = +value.slice(0, index)
      // 判断时间是否已过期
      if (time > Date.now()) {
        value = JSON.parse(value.slice(index + this.timeSign.length))
      } else {
        value = null
        window.localStorage.removeItem(key)
      }
    }

    return value
  }
}

测试一下

代码语言:javascript
复制
storage.setItem('name', '前端胖头鱼', Date.now() + 100 * 1000) // fatFishname 1646095230191|fatFish|"前端胖头鱼"
storage.getItem('name') // 前端胖头鱼

// 100s later
storage.getItem('name') // null

storage.setItem('obj', { name: '前端胖头鱼', age: 100 }, Date.now() + 100 * 1000) // fatFishobj 1646095311366|fatFish|{"name":"前端胖头鱼","age":100}

storage.getItem('obj') // {name: '前端胖头鱼', age: 100}


可以看到基本是符合题意,当然我们还可以针对异常情况进行兼容处理,比如空间满了,设置出错等

3#. 自己尝试实现一下Promise.all

为什么很多公司都喜欢面手写实现Promise.all呢?可能是相比实现Promise来说他相对简单一些,但是又可以考察候选人对日常Promise的基本掌握?胖头鱼之前写过一篇因为实现不了Promise.all,一场面试凉凉了, 542个赞,近4万阅读量,也包括Promise的其他静态方法实现,这里直接贴一下Promise.all的实现思路。

3.1# 简要回顾

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。这个静态方法应该是面试中最常见的啦

代码语言:javascript
复制
const p = Promise.all([p1, p2, p3])

最终p的状态由p1p2p3决定,分成两种情况。

(1)只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

代码语言:javascript
复制
const p1 = Promise.resolve(1)
const p2 = new Promise((resolve) => {
  setTimeout(() => resolve(2), 1000)
})
const p3 = new Promise((resolve) => {
  setTimeout(() => resolve(3), 3000)
})

const p4 = Promise.reject('err4')
const p5 = Promise.reject('err5')
// 1. 所有的Promise都成功了
const p11 = Promise.all([ p1, p2, p3 ])
 .then(console.log) // [ 1, 2, 3 ]
      .catch(console.log)
      
// 2. 有一个Promise失败了
const p12 = Promise.all([ p1, p2, p4 ])
 .then(console.log)
      .catch(console.log) // err4
      
// 3. 有两个Promise失败了,可以看到最终输出的是err4,第一个失败的返回值
const p13 = Promise.all([ p1, p4, p5 ])
 .then(console.log)
      .catch(console.log) // err4

3.2# 源码实现

代码语言:javascript
复制

Promise.myAll = (promises) => {
  return new Promise((rs, rj) => {
    // 计数器
    let count = 0
    // 存放结果
    let result = []
    const len = promises.length
    
    if (len === 0) {
      return rs([])
    }
    
    promises.forEach((p, i) => {
      // 注意有的数组项有可能不是Promise,需要手动转化一下
      Promise.resolve(p).then((res) => {
        count += 1
        // 收集每个Promise的返回值 
        result[ i ] = res
        // 当所有的Promise都成功了,那么将返回的Promise结果设置为result
        if (count === len) {
          rs(result)
        }
        // 监听数组项中的Promise catch只要有一个失败,那么我们自己返回的Promise也会失败
      }).catch(rj)
    })
  })
}

// 测试一下
const p1 = Promise.resolve(1)
const p2 = new Promise((resolve) => {
  setTimeout(() => resolve(2), 1000)
})
const p3 = new Promise((resolve) => {
  setTimeout(() => resolve(3), 3000)
})

const p4 = Promise.reject('err4')
const p5 = Promise.reject('err5')
// 1. 所有的Promise都成功了
const p11 = Promise.myAll([ p1, p2, p3 ])
 .then(console.log) // [ 1, 2, 3 ]
      .catch(console.log)
      
// 2. 有一个Promise失败了
const p12 = Promise.myAll([ p1, p2, p4 ])
 .then(console.log)
      .catch(console.log) // err4
      
// 3. 有两个Promise失败了,可以看到最终输出的是err4,第一个失败的返回值
const p13 = Promise.myAll([ p1, p4, p5 ])
 .then(console.log)
      .catch(console.log) // err4
// 与原生的Promise.all返回是一致的    

4.# 使用reduce实现map函数功能

这题会相对简单一些,咱们直接上代码

代码语言:javascript
复制
输入 [1, 2, 3]
输出 [2, 4, 6]

代码语言:javascript
复制
Array.prototype.map2 = function (callback, ctx = null) {
  if (typeof callback !== 'function') {
    throw('callback must be a function')
  }

  return this.reduce((result, cur, index, array) => {
    return  result.concat(callback.call(ctx, cur, index, array))
  }, [])
}

let arr = [ 1, 2 ]
let arr2 = arr.map2(function (it, i, array) {
  console.log(it, i, array, this)
  return it * 2
}, { name: '前端胖头鱼' })

console.log(arr2) 

结尾

字节一面的题目,看起来确实难度不是很大,不过毕竟是一面,二面和三面才是难,后面大家如果有兴趣想了解他后面的题,可以在下方评论,我去捞一波,哈哈哈。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端胖头鱼 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1.# 查找两个DOM节点的最近公共父节点
    • 1.1# 两个节点同级
      • 1.2# 两个节点是互为祖先关系
        • 1.3# 两个节点没有半毛钱关系
          • 1.4# 递归实现版本
            • 1.5# 遍历实现版本
            • 2.# cookie和localstorage 的概念和区别,设计一个可以设置有效期的localstorage API
            • 3#. 自己尝试实现一下Promise.all
              • 3.1# 简要回顾
                • 3.2# 源码实现
                • 4.# 使用reduce实现map函数功能
                • 结尾
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档