前端面试题汇总

181 阅读7分钟

记录一些面试的题目。

js基础

typeof和instanceof区别
  • typeof: 识别出所有的值类型,识别函数,判断是否为引用类型
  • instanceof: 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上 补充:
  • 值类型: undefined、string、number、boolean、Symbol,值类型存储于栈中
  • 引用类型: Object,null(指向空地址),数组,function, 引用类型存储于堆中
forEach和for循环中使用await效果一样吗?

不一样。在for循环中awit能够生效,不过在forEach中即使用了async和await,还是不能生效的。在forEach中,只会简单的处理下回调函数,不会去处理异步的情况,不能保证每次的结果都一致。

vue

1. $nextTick的使用场景及对它的理解

官方解答:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

使用场景:要在数据和视图都更新完成,基于新的视图进行的操作的情况下去使用。

要知道在vue是通过异步的方式来更新DOM,故数据和视图不一致的情况是肯定会存在的。在这里就需要对浏览器的事件循环机制(Event loop)有一定的了解。在JS中,代码是一行一行执行的,先执行同步代码,再执行异步代码,同步代码进入到调用栈(执行完就会出栈),如果遇到setTimeout之类的,会把事件存入定时器中。当调用栈中无可执行代码,就会立即启动event loop机制,会去回调队列(callback queue)中,查找是否有函数要执行,有就将对象函数推到调用栈中执行,执行完出栈。 在事件循环中的任务可分为微任务(micro task)和宏任务(marco task)。常见的宏任务有script(js的 整体代码),setTimeout、MessageChannel、postMessage、setImmediate;常见微任务有MutationObsever 和 Promise.then。 执行js代码开始,遇到其他宏任务和微任务会放到后面执行,当同步代码执行完成之后,回去优先执行微任务,微任务执行结束后再去执行宏任务。

关于优化

web端对静态资源缓存的优化

浏览器中的静态资源缓存主要是通过设置http headers来实现的。

  • 设置Cache-Control来控制资源的缓存,比如max-age,pulic,private等。
  • 设置Last-Modified,初次请求资源的时候会得到最后修改时间Last-Modified,再次向服务器发起请求的时候,会带着一个If-Modified-Since,服务器会做出判断,如果没有更新就返回304(客户端有缓存情况下服务端的一种响应),资源变更了就返回新资源和新的Last-Modified
  • 设置Etag,文件唯一标识,每次请求的时候都会在If-None-Match字段中携带上次返回的Etag值,后台根据Etag做相关处理,一致则返回304,否则返回200和最新的资源
服务端渲染缓解服务端压力的方式
  • 缓存优化:配置nginx的微缓存优化;利用serverCacheKey 函数来缓存组件
  • 代码优化:合理减少页面的嵌套层次,优化HTML结构,可减少VDOM的计算耗时
CDN优化访问速度

在项目中合理的配置CDN能带来更好的体验。vue项目中可以配置部分常用第三方库对应的CDN,来提高首页加载速度

前端页面性能分析及优化方案

http

1.http三次握手具体流程

三次握手的目的是确保连接的有效性。

  • 第一次握手是浏览器向服务器发送syn包(SYN:同步序列编号),进入到SYN_SEND状态等待服务器的确认
  • 第二次握手是服务器收到了syn包,确认客户端的SYN(ack=j+1),同时服务端也发送一个syn包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态
  • 第三次握手是客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态 握手完毕了之后就可以进行数据包的发送了,数据包发送完毕了,就要进行接下来的四次挥手了
  • 浏览器向服务器发送一个FIN,来关闭与服务器之间数据的传送
  • 服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号
  • 服务器B关闭与客户端A的连接,发送一个FIN给客户端A
  • 客户端A发回ACK报文确认,并将确认序号设置为收到序号加1
http1.1与http2.0的区别
  • 2.0采用了多路复用的方式,可以连接共享,提高了连接的利用率,降低延迟,在同一个连接中并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级
  • 1.1不支持header数据的压缩,2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快
  • 2.0采用了服务端推送,允许服务端推送资源给浏览器,服务端可以利用这种方式在网络请求空闲的时候向浏览器端推送资源,提高效率
http请求的强弱缓存之分

http请求中Response Headers返回来告诉浏览器该请求是该怎怎么进行缓存。

  • Cache-Control:max-age no-cacha no-store private public
  • Last-Modified:初次请求会得到最后修改时间Last-Modified,当再次请求时,会带着If-Modified-Since,这个值服务端会进行一个判断,没更新返回304,修改了返回新资源和新的Last-Modified
  • Etag: 文件唯一标识 Cache-Control属于强缓存,Last-Modified和Etag属于弱缓存(协商缓存)。
  • 在输入url,跳转链接,前进后退等正常浏览器操作时,强制缓存和弱缓存都有效。
  • 手动F5刷新时,强制缓存失效,弱缓存有效
  • 强制刷新时,强制缓存失效,协商缓存失效

webpack

1. loader和plugin的区别及其使用方式,描述几个常见的loader或者plugin的使用

loader,处理不同类型的文件为webpack能识别的文件(webpack只认识js和json)。 plugin是对loader结束后,webpack在打包的过程中做一些处理,并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,做对应的处理。

常见loader:

  • style-loader,css-loader,sass-loader: 处理样式
  • babel-loader,vue-loader: 处理jsx,vue文件
  • url-loader,file-loader: 解析文件(图片,字体等)

常见plugin:

  • clean-webpack-plugin: 删除清理文件夹
  • html-webpack-plugin: 创建html文件
  • mini-css-extract-plugin: 处理css插件
  • compression-webpack-plugin: 压缩资源
2. webpack按需打包Lodash的方法

使用插件lodash-webpack-plugin,参考 www.npmjs.com/package/lod…

算法

常见的排序算法有哪些?快速排序的原理?

常见的:冒泡排序,归并排序,选择排序,插入排序,快速排序等。

快速排序核心思想就是分区:先从数组中选取一个值作为参考,所有比参考值小的放在其前面,比参考值大的放在后面。利用递归对参考值前后的数组进行分区操作,当所有子数组长度为1的时候排序结束。

function quickSort(arr) {
    if(arr.length <= 1) {return arr}
    let right = [], left = [], startIndex = 0 
    let startNum = arr.splice(startIndex, 1)[0]
    for(let i = 0; i < arr.length; i++) {
        if(arr[i] < startNum) {
            left.push(arr[i])
        } else {
            right.push(arr[i])
        }
    }
    return [...quickSort(left), startNum, ...quickSort(right)]
}
数组里面有若干字符串(存在重复),计算出字符串个数,生成以字符串为属性名称,出现次数为属性值并按出现次数从大到小排列的对象数组
// 输入['x', 'y','a', 'b', 'a', 'b', 'x','x', 'y','a', 'b', 'a']
// 输出 {a: 4, b: 3, x: 3, y: 2}
function getCountStringArray(arr) {
    if(!Array.isArray(arr) || !arr.length) return []
    const tempObj = {}
    arr.forEach(x => {
        if(tempObj[x] === undefined) {
            tempObj[x] = 1
        } else {
            tempObj[x] = tempObj[x] + 1
        }
    })

    const vals = Object.entries(tempObj).sort((a,b) => b[1] - a[1])
    return vals.map(x => {return {[x[0]]: x[1]}})
}

CSS

关于CSS盒模型理解
  • 标准盒模型(width/height 只是内容高度,不包含 padding 和 border 值) 盒子宽度 = width + padding + borer + margin

盒子高度 = height + padding + borer + margin

  • IE的怪异盒模型width/height 包含了 padding 和 border 值 盒子宽度 = width + margin

盒子高度 = height + margin

通过box-sizing属性来控制盒模型,content-box为标准盒模型,border-box为IE的怪异盒模型

垂直水平居中实现方案

利用绝对定位加transform来实现


<style>
    .father {
        position: relative;
        width: 200px;
        height: 200px;
        background: skyblue;
    }
    .son {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
        width: 100px;
        height: 100px;
        background: red;
    }
</style>
<div class="father">
    <div class="son"></div>
</div>

felx: 1; 这个flex是哪几个属性缩写,分别代表什么意思
  • flex-grow:设置 flex 项主尺寸 的 flex 增长系数
  • flex-shrink:指定了 flex 元素的收缩规则,flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值
  • flex-basis:指定了 flex 元素在主轴方向上的初始大小