拿到大厂前端 offer 的前端开发是怎么回答面试题的
代码输出问题
输出结果:1 undefined 2
解析:
console.log(new A().a),new A()为构造函数创建的对象,本身没有 a 属性,所以向它的原型去找,发现原型的 a 属性的属性值为 1,故该输出值为 1;
console.log(new B().a),ew B()为构造函数创建的对象,该构造函数有参数 a,但该对象没有传参,故该输出值为 undefined;
console.log(new C(2).a),new C()为构造函数创建的对象,该构造函数有参数 a,且传的实参为 2,执行函数内部,发现 if 为真,执行 this.a = 2,故属性 a 的值为 2。
一个 tcp 连接能发几个 http 请求?
如果是 HTTP 1.0 版本协议,一般情况下,不支持长连接,因此在每次请求发送完毕之后,TCP 连接即会断开,因此一个 TCP 发送一个 HTTP 请求,但是有一种情况可以将一条 TCP 连接保持在活跃状态,那就是通过 Connection 和 Keep-Alive 首部,在请求头带上 Connection: Keep-Alive,并且可以通过 Keep-Alive 通用首部中指定的,用逗号分隔的选项调节 keep-alive 的行为,如果客户端和服务端都支持,那么其实也可以发送多条,不过此方式也有限制,可以关注《HTTP 权威指南》4.5.5 节对于 Keep-Alive 连接的限制和规则。
而如果是 HTTP 1.1 版本协议,支持了长连接,因此只要 TCP 连接不断开,便可以一直发送 HTTP 请求,持续不断,没有上限; 同样,如果是 HTTP 2.0 版本协议,支持多用复用,一个 TCP 连接是可以并发多个 HTTP 请求的,同样也是支持长连接,因此只要不断开 TCP 的连接,HTTP 请求数也是可以没有上限地持续发送
代码输出结果
输出结果如下:
代码的执行过程如下:
首先执行函数中的同步代码
async1 start
,之后遇到了await
,它会阻塞async1
后面代码的执行,因此会先去执行async2
中的同步代码async2
,然后跳出async1
;跳出
async1
函数后,执行同步代码start
;在一轮宏任务全部执行完之后,再来执行
await
后面的内容async1 end
。
这里可以理解为 await 后面的语句相当于放到了 new Promise 中,下一行及之后的语句相当于放在 Promise.then 中。
冒泡排序--时间复杂度 n^2
题目描述:实现一个冒泡排序
实现代码如下:
参考:前端进阶面试题详细解答
内存泄露
意外的全局变量: 无法被回收
定时器: 未被正确关闭,导致所引用的外部变量无法被释放
事件监听: 没有正确销毁 (低版本浏览器可能出现)
闭包
第一种情况是我们由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。
第二种情况是我们设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留在内存中,而无法被回收。
第三种情况是我们获取一个 DOM 元素的引用,而后面这个元素被删除,由于我们一直保留了对这个元素的引用,所以它也无法被回收。
第四种情况是不合理的使用闭包,从而导致某些变量一直被留在内存当中。
dom
引用:dom
元素被删除时,内存中的引用未被正确清空控制台
console.log
打印的东西
可用
chrome
中的timeline
进行内存标记,可视化查看内存的变化情况,找出异常点。
计算属性和 watch 有什么区别?以及它们的运用场景?
浅拷贝
选择排序--时间复杂度 n^2
题目描述:实现一个选择排序
实现代码如下:
Vue 为什么要用 vm.$set() 解决对象新增属性不能响应的问题 ?你能说说如下代码的实现原理么?
1)Vue 为什么要用 vm.$set() 解决对象新增属性不能响应的问题
Vue 使用了 Object.defineProperty 实现双向数据绑定
在初始化实例时对属性执行 getter/setter 转化
属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的(这也就造成了 Vue 无法检测到对象属性的添加或删除)
所以 Vue 提供了 Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value)
2)接下来我们看看框架本身是如何实现的呢?
Vue 源码位置:vue/src/core/instance/index.js
我们阅读以上源码可知,vm.$set 的实现原理是:
如果目标是数组,直接使用数组的 splice 方法触发相应式;
如果目标是对象,会先判读属性是否存在、对象是否是响应式,
最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理
defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法
节流
**节流(throttle
)**:触发高频事件,且 N 秒内只执行一次。这就好比公交车,10 分钟一趟,10 分钟内有多少人在公交站等我不管,10 分钟一到我就要发车走人!类似 qq 飞车的复位按钮。
核心思想:使用时间戳或标志来实现,立即执行一次,然后每 N 秒执行一次。如果 N 秒内触发则直接返回。
应用:节流常应用于鼠标不断点击触发、监听滚动事件。
实现:
代码输出结果
输出结果如下:
代码的执行过程如下:
首先会进入 Promise,打印出 3,之后进入下面的 Promise,打印出 7;
遇到了定时器,将其加入宏任务队列;
执行 Promise p 中的 resolve,状态变为 resolved,返回值为 1;
执行 Promise first 中的 resolve,状态变为 resolved,返回值为 2;
遇到 p.then,将其加入微任务队列,遇到 first().then,将其加入任务队列;
执行外面的代码,打印出 4;
这样第一轮宏任务就执行完了,开始执行微任务队列中的任务,先后打印出 1 和 2;
这样微任务就执行完了,开始执行下一轮宏任务,宏任务队列中有一个定时器,执行它,打印出 5,由于执行已经变为 resolved 状态,所以
resolve(6)
不会再执行;最后
console.log(p)
打印出Promise{<resolved>: 1}
;
代码输出结果
输出结果如下:
(1)第一轮事件循环流程分析如下:
整体 script 作为第一个宏任务进入主线程,遇到
console.log
,输出 1。遇到
setTimeout
,其回调函数被分发到宏任务 Event Queue 中。暂且记为setTimeout1
。遇到
process.nextTick()
,其回调函数被分发到微任务 Event Queue 中。记为process1
。遇到
Promise
,new Promise
直接执行,输出 7。then
被分发到微任务 Event Queue 中。记为then1
。又遇到了
setTimeout
,其回调函数被分发到宏任务 Event Queue 中,记为setTimeout2
。
上表是第一轮事件循环宏任务结束时各 Event Queue 的情况,此时已经输出了 1 和 7。发现了process1
和then1
两个微任务:
执行
process1
,输出 6。执行
then1
,输出 8。
第一轮事件循环正式结束,这一轮的结果是输出 1,7,6,8。
(2)第二轮时间循环从**setTimeout1**
宏任务开始:
首先输出 2。接下来遇到了
process.nextTick()
,同样将其分发到微任务 Event Queue 中,记为process2
。new Promise
立即执行输出 4,then
也分发到微任务 Event Queue 中,记为then2
。
第二轮事件循环宏任务结束,发现有process2
和then2
两个微任务可以执行:
输出 3。
输出 5。
第二轮事件循环结束,第二轮输出 2,4,3,5。
(3)第三轮事件循环开始,此时只剩 setTimeout2 了,执行。
直接输出 9。
将
process.nextTick()
分发到微任务 Event Queue 中。记为process3
。直接执行
new Promise
,输出 11。将
then
分发到微任务 Event Queue 中,记为then3
。
第三轮事件循环宏任务执行结束,执行两个微任务process3
和then3
:
输出 10。
输出 12。
第三轮事件循环结束,第三轮输出 9,11,10,12。
整段代码,共进行了三次事件循环,完整的输出为 1,7,6,8,2,4,3,5,9,11,10,12。
代码输出结果
输出结果: 10 2
解析:
第一次执行 fn(),this 指向 window 对象,输出 10。
第二次执行 arguments[0],相当于 arguments 调用方法,this 指向 arguments,而这里传了两个参数,故输出 arguments 长度为 2。
代码输出结果
执行结果为如下:
需要注意的是最后一个定时器打印出的 p1 其实是.finally
的返回值,我们知道.finally
的返回值如果在没有抛出错误的情况下默认会是上一个 Promise 的返回值,而这道题中.finally
上一个 Promise 是.then()
,但是这个.then()
并没有返回值,所以 p1 打印出来的 Promise 的值会是undefined
,如果在定时器的下面加上一个return 1
,则值就会变成 1。
什么情况会阻塞渲染?
首先渲染的前提是生成渲染树,所以 HTML 和 CSS 肯定会阻塞渲染。如果你想渲染的越快,你越应该降低一开始需要渲染的文件大小,并且扁平层级,优化选择器。然后当浏览器在解析到 script 标签时,会暂停构建 DOM,完成后才会从暂停的地方重新开始。也就是说,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因。
当然在当下,并不是说 script 标签必须放在底部,因为你可以给 script 标签添加 defer 或者 async 属性。当 script 标签加上 defer 属性以后,表示该 JS 文件会并行下载,但是会放到 HTML 解析完成后顺序执行,所以对于这种情况你可以把 script 标签放在任意位置。对于没有任何依赖的 JS 文件可以加上 async 属性,表示 JS 文件下载和解析不会阻塞渲染。
Vue 路由守卫有哪些,怎么设置,使用场景等
instanceof
作用:判断对象的具体类型。可以区别 array
和 object
, null
和 object
等。
语法:A instanceof B
如何判断的?: 如果 B 函数的显式原型对象在 A 对象的原型链上,返回true
,否则返回false
。
注意:如果检测原始值,则始终返回 false
。
实现:
代码输出结果
输出结果如下:
.finally()
一般用的很少,只要记住以下几点就可以了:
.finally()
方法不管 Promise 对象最后的状态如何都会执行.finally()
方法的回调函数不接受任何的参数,也就是说你在.finally()
函数中是无法知道 Promise 最终的状态是resolved
还是rejected
的它最终返回的默认会是一个上一次的 Promise 对象值,不过如果抛出的是一个异常则返回异常的 Promise 对象。
finally 本质上是 then 方法的特例
.finally()
的错误捕获:
输出结果为:
说一下 vue3.0 你了解多少?
常见的图片格式及使用场景
(1)BMP,是无损的、既支持索引色也支持直接色的点阵图。这种图片格式几乎没有对数据进行压缩,所以 BMP 格式的图片通常是较大的文件。
(2)GIF 是无损的、采用索引色的点阵图。采用 LZW 压缩算法进行编码。文件小,是 GIF 格式的优点,同时,GIF 格式还具有支持动画以及透明的优点。但是 GIF 格式仅支持 8bit 的索引色,所以 GIF 格式适用于对色彩要求不高同时需要文件体积较小的场景。
(3)JPEG 是有损的、采用直接色的点阵图。JPEG 的图片的优点是采用了直接色,得益于更丰富的色彩,JPEG 非常适合用来存储照片,与 GIF 相比,JPEG 不适合用来存储企业 Logo、线框类的图。因为有损压缩会导致图片模糊,而直接色的选用,又会导致图片文件较 GIF 更大。
(4)PNG-8 是无损的、使用索引色的点阵图。PNG 是一种比较新的图片格式,PNG-8 是非常好的 GIF 格式替代者,在可能的情况下,应该尽可能的使用 PNG-8 而不是 GIF,因为在相同的图片效果下,PNG-8 具有更小的文件体积。除此之外,PNG-8 还支持透明度的调节,而 GIF 并不支持。除非需要动画的支持,否则没有理由使用 GIF 而不是 PNG-8。
(5)PNG-24 是无损的、使用直接色的点阵图。PNG-24 的优点在于它压缩了图片的数据,使得同样效果的图片,PNG-24 格式的文件大小要比 BMP 小得多。当然,PNG24 的图片还是要比 JPEG、GIF、PNG-8 大得多。
(6)SVG 是无损的矢量图。SVG 是矢量图意味着 SVG 图片由直线和曲线以及绘制它们的方法组成。当放大 SVG 图片时,看到的还是线和曲线,而不会出现像素点。这意味着 SVG 图片在放大时,不会失真,所以它非常适合用来绘制 Logo、Icon 等。
(7)WebP 是谷歌开发的一种新图片格式,WebP 是同时支持有损和无损压缩的、使用直接色的点阵图。从名字就可以看出来它是为 Web 而生的,什么叫为 Web 而生呢?就是说相同质量的图片,WebP 具有更小的文件体积。现在网站上充满了大量的图片,如果能够降低每一个图片的文件大小,那么将大大减少浏览器和服务器之间的数据传输量,进而降低访问延迟,提升访问体验。目前只有 Chrome 浏览器和 Opera 浏览器支持 WebP 格式,兼容性不太好。
在无损压缩的情况下,相同质量的 WebP 图片,文件大小要比 PNG 小 26%;
在有损压缩的情况下,具有相同图片精度的 WebP 图片,文件大小要比 JPEG 小 25%~34%;
WebP 图片格式支持图片透明度,一个无损压缩的 WebP 图片,如果要支持透明度只需要 22%的格外文件大小。
评论