十道大厂面试题(含答案)总结

144次阅读
没有评论

十道大厂面试题(含答案)总结插图

又到了跳槽季啦 , 该刷题走起了。这里总结了一些被问到可能会懵逼的面试真题 , 有需要的可以看下 ~

PS: 点击阅读原文即可进入前端 Q 题库 , 每周 N 题 , 来刷题吧 ~

1. 不借助变量 , 交换两个数

1. 算术交换

针对的是 Number, 或者类型可以转换成数字的变量类型

function swap(a, b) {a = a + b; b = a - b; a = a - b;} 

通过算术运算过程中的技巧 , 可以巧妙地将两个值进行互换。但是 , 有个缺点就是变量数据溢出。因为 JavaScript 能存储数字的精度范围是 -2^53 到 2^53。所以 , 加法运算 , 会存在溢出的问题。

2. 异或运算

^ 按位异或 若参加运算的两个二进制位值相同则为 0 , 否则为 1 此算法能够实现是由异或运算的特点决定的 , 通过异或运算能够使数据中的某些位翻转 , 其他位不变。这就意味着任意一个数与任意一个给定的值连续异或两次 , 值不变.

a = a ^ b; b = a ^ b; a = a ^ b; 

3. ES6 的解构

[a, b] = [b, a]; 

更多参考 :

  • https://juejin.im/post/58b42fcc5c497d006793cd04

  • https://www.jianshu.com/p/61370227d096

2. 实现 sum(1,2,3)==sum(1)(2)(3)

function sum(...args){function currySum(...rest){args.push(...rest) return currySum } currySum.toString= function(){ return args.reduce((result,cur)=>{return result + cur}) } currySum.toNumber= function(){ return args.reduce((result,cur)=>{return result + cur}) } return currySum } 

更多参考 :https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/134

3. 观察者模式 vs 发布 - 订阅模式 , 说说区别

观察者模式的概念

观察者模式模式 , 属于行为型模式的一种 , 它定义了一种一对多的依赖关系 , 让多个观察者对象同时监听某一个主题对象。这个主体对象在状态变化时 , 会通知所有的观察者对象 , 使他们能够自动更新自己。

发布订阅者模式的概念

发布 - 订阅模式 , 消息的发送方 , 叫做发布者 (publishers), 消息不会直接发送给特定的接收者 , 叫做订阅者。意思就是发布者和订阅者不知道对方的存在。需要一个第三方组件 , 叫做信息中介 , 它将订阅者和发布者串联起来 , 它过滤和分配所有输入的消息。换句话说 , 发布 - 订阅模式用来处理不同系统组件的信息交流 , 即使这些组件不知道对方的存在。

区别

十道大厂面试题(含答案)总结插图1

我们把这些差异快速总结一下 :

在观察者模式中 , 观察者是知道 Subject 的 ,Subject 一直保持对观察者进行记录。然而 , 在发布订阅模式中 , 发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。

在发布订阅模式中 , 组件是松散耦合的 , 正好和观察者模式相反。

观察者模式大多数时候是同步的 , 比如当事件触发 ,Subject 就会去调用观察者的方法。而发布 - 订阅模式大多数时候是异步的 ( 使用消息队列 )。

观察者 模式需要在单个应用程序地址空间中实现 , 而发布 - 订阅更像交叉应用模式。

更多 :https://juejin.im/post/5a14e9edf265da4312808d86

PS: 最好把对应的模式的模型代码也写一下

4. 实现 LRU 算法

实现一个 LRU 过期算法的 KV cache, 所有 KV 过期间隔相同, 满足如下性质:

  1. 最多存储 n 对 KV;

  2. 如果大于 n 个, 则随意剔除一个已经过期的 KV;

  3. 如果没有过期的 KV, 则按照 LRU 的规则剔除一个 KV;

  4. 查询时如果已经过期, 则返回空;

class LRUCache {constructor(capacity,intervalTime){this.cache = new Map(); this.capacity = capacity; this.intervalTime = intervalTime; } get(key){if(!this.cache.has(key)){return null} const tempValue = this.cache.get(key) this.cache.delete(key); if(Date.now() - tempValue.time > this.intervalTime){return null} this.cache.set(key, {value: tempValue.value, time: Date.now()}) return tempValue.value } put(key, value){if(this.cache.has(key)){this.cache.delete(key) } if(this.cache.size >= capacity){// 满了 const keys = this.cache.keys() this.cache.delete(keys.next().value) } this.cache.set(key, {value,time:Date.now()}) } } 

巧妙地利用了 Map 结构的 key 是有序的这个特点。普通 Object 的 key 是无序的。

5. 如何监控网页崩溃 ?

基于 Service Worker 的崩溃统计方案

随着 PWA 概念的流行 , 大家对 Service Worker 也逐渐熟悉起来。基于以下原因 , 我们可以使用 Service Worker 来实现网页崩溃的监控 :

  1. Service Worker 有自己独立的工作线程 , 与网页区分开 , 网页崩溃了 ,Service Worker 一般情况下不会崩溃 ;

  2. Service Worker 生命周期一般要比网页还要长 , 可以用来监控网页的状态 ;

  3. 网页可以通过 navigator.serviceWorker.controller.postMessage API 向掌管自己的 SW 发送消息。

基于以上几点 , 我们可以实现一种基于心跳检测的监控方案 :

  • p1: 网页加载后 , 通过 postMessageAPI 每 5s 给 sw 发送一个心跳 , 表示自己的在线 ,sw 将在线的网页登记下来 , 更新登记时间 ;

  • p2: 网页在 beforeunload 时 , 通过 postMessageAPI 告知自己已经正常关闭 ,sw 将登记的网页清除 ;

  • p3: 如果网页在运行的过程中 crash 了 ,sw 中的 running 状态将不会被清除 , 更新时间停留在奔溃前的最后一次心跳 ;

  • sw:Service Worker 每 10s 查看一遍登记中的网页 , 发现登记时间已经超出了一定时间 ( 比如 15s) 即可判定该网页 crash 了。

更多 :https://zhuanlan.zhihu.com/p/40273861

6. 求代码输出 , 并说出为什么

var obj = {'2':3, '3':4, 'length':2, 'splice':Array.prototype.splice, 'push':Array.prototype.push} obj.push(1) obj.push(2) obj.push(3) console.log(obj) 

答案 :

{'2':1 '3':2, '4':3, 'length':5, 'splice':Array.prototype.splice, 'push':Array.prototype.push} 

obj 有长度 , 相当于类数组 , 调用数组的 push, 会在数组的最后加一项 , 第一次调用 , 相当于长度变为 3 , 那么下标为 2 的那一项被赋值为 1 , 下标是 2 , 当其作为对象的 key 值的时候 , 会隐式调用 toString 方法转为字符串 2 , 则和 obj 本来有的 key '2' 相同 , 原来的 key 为 2 的 value 就被覆盖了。以此类推后面的 2 个 push。

详情 :https://github.com/LuckyWinty/fe-weekly-questions/issues/48

7.node 中的 setTimeout 和 setImmediate 有什么区别

setImmediate() 和 setTimeout() 很类似 , 但是基于被调用的时机 , 他们也有不同表现。

  • setImmediate 设计在 poll 阶段完成时执行 , 即 check 阶段 ;

  • setTimeout 设计在 poll 阶段为空闲时 , 且设定时间到达后执行 , 但它在 timer 阶段执行

执行计时器的顺序将根据调用它们的上下文而异。如果二者都从主模块内调用 , 则计时器将受进程性能的约束。举个例子 , 有如下代码 :

setTimeout(() => console.log(1)); setImmediate(() => console.log(2)); 

上面代码应该先输出 1 , 再输出 2 , 但是实际执行的时候 , 结果却是不确定 , 有时还会先输出 2 , 再输出 1。

这是因为 setTimeout 的第二个参数默认为 0。但是实际上 ,Node 做不到 0 毫秒 , 最少也需要 1 毫秒 , 根据官方文档 , 第二个参数的取值范围在 1 毫秒到 2147483647 毫秒之间。也就是说 ,setTimeout(f, 0)等同于 setTimeout(f, 1)。

实际执行的时候 , 进入事件循环以后 , 有可能到了 1 毫秒 , 也可能还没到 1 毫秒 , 取决于系统当时的状况。如果没到 1 毫秒 , 那么 timers 阶段就会跳过 , 进入 check 阶段 , 先执行 setImmediate 的回调函数。

但是 , 如果是这样的情况 , 输出顺序就固定了 , 例 :

const fs = require('fs'); fs.readFile('test.js', () => {setTimeout(() => console.log(1)); setImmediate(() => console.log(2)); }); 

在上述代码中 , 一定是先输出 2 , 再输出 1。因为两个代码写在 IO 回调中 ,IO 回调是在 poll 阶段执行 , 当回调执行完毕后队列为空 , 发现存在 setImmediate 回调 , 所以就直接跳转到 check 阶段去执行回调了 , 执行完成后再去到 timers 阶段 , 然后执行 setTimeout。

8. 写一个正则 , 根据 name 取 cookie 中的值。

function get(name){var reg = new RegExp(name+'=([^;]*)?(;|$)'); var res = reg.exec(document.cookie); if(!res || !res[1])return ''; try{if(/(%[0-9A-F]{2}){2,}/.test(res)){//utf8 编码 return decodeURIComponent(res); }else{//unicode 编码 return unescape(res); } }catch(e){return unescape(res); } } 

正则表达式中重点看这几句代码: '([^;])', 意思是匹配 str= 后面的不为; ([^;]表示非集, 也就是所有不为; 的字符都能被匹配)的字符串, 该字符串出现 0 或更多次(), 之后将匹配到的字符串放入第一个捕获组.

详情 :https://github.com/LuckyWinty/fe-weekly-questions/issues/32

9. 在不改变 html 结构的情况下 , 写出至少 7 种方法实现以下布局。

要求 : 左边 2 列 , 右边 1 列 , 中间自适应

 <div class="parent" style="width: 200px"> <div class="child child1" style="width: 20px"></div> <div class="child child2" style="width: 20px">2</div> <div class="child child3" style="width: 20px">3</div> </div> 

答案 :

/* 1 */ .parent{background-color: burlywood; display: flex;} .child{background-color: black; font-size: 20px; color: white;} .child3{margin-left: auto;} /* 2 */ .parent{background-color: burlywood; position: relative;} .child{font-size: 20px; color: white;} .child1{background-color: black; position: absolute; left: 0;} .child2{background-color: black; position: absolute; left: 20px;} .child3{background-color: black; position: absolute; right: 0;} /* 3 */ .parent{background-color: burlywood;} .child1{background-color: black; float: left;} .child2{background-color: red; float: left;} .child3{float: right; background-color: blue} /* 4 */ .parent{background-color: burlywood; display: table;} .child{background-color: black; display: table-cell; height: 20px;} .child3{display: block; margin-left: auto;} /* 5 */ .parent{background-color: burlywood; position: relative;} .child{background-color: black; position: absolute; top:0; left:0;} .child2{transform: translate(20px, 0); } .child3{transform: translate(180px, 0); } /* 6 */ .parent{background-color: burlywood; display: grid; grid-template-columns: repeat(10, 1fr); } .child{background-color: black; font-size: 20px; color:white;} .child3{grid-column: 10 / 11;} /* 7 */ .parent{background-color: burlywood; font-size: 0;} .child{background-color: black; display: inline-block; font-size: 20px; color: white;} .child3{margin-left: 140px;} 

10. 用 css 画一个扇形 ?

width: 0; height: 0; border: solid 100px red; border-color: red transparent transparent transparent; border-radius: 100px; 

说明

本文部分题目及答案来源于网络 , 如有错误 , 欢迎纠正 , 如有侵权问题 , 麻烦微信联系 winty230 交涉处理。

最后

  • 欢迎加我微信(winty230), 拉你进技术群 , 长期交流学习 …

  • 欢迎关注「前端 Q」, 认真学前端 , 做个专业的技术人 …

十道大厂面试题(含答案)总结插图2

十道大厂面试题(含答案)总结插图3

原创不易 , 点个 在看 支持我吧

十道大厂面试题(含答案)总结插图4

原文链接:https://blog.csdn.net/LuckyWinty/article/details/105384452

正文完
 0