[前端高频面试] 2023年初级、中级面试题解
单纯为了自己面试方便,整理一些高频面试题,2023希望每个前端小伙伴找到心仪的工作!!
目录
「自我介绍(仅供参考)」
「HTML、CSS相关」
» H5有哪些新特性?
» 浏览器渲染机制、重排、重绘
» 简述CSS盒模型
» 如何让盒子水平垂直居中
» 如何实现一个三角形?
» CSS样式优先级
» display:none 和 visibility: hidden 的区别?
» 去除浮动的几种方式?(问可顺带答出BFC)
» 什么是BFC?BFC布局规则是什么?如何创建BFC?
» cookies、localStorage、sessionStorage的区别?
「JS」
» 什么是闭包?
» 作用域、作用域链、变量提升、函数提升分别是什么?
» JS有哪些数据类型?typeof、instanceof、类型转换
» 原型和原型链
» 继承(含ES6)、多种继承方式
» this指向、new关键字
» bind、call、apply的区别?
» JS 的设计模式?
» 深拷贝和浅拷贝
» TS 和 JS 有什么区别,优点和缺点
» 什么是事件冒泡、事件捕获、事件委托机制?
» 普通事件和事件绑定有什么区别?
» EventLoop(线程机制)
» 防抖和节流
» 函数柯里化
「ES6」
» var 、 const、 let 的区别?
» Promise的理解
» Promise.all 和 Promise.race
» 箭头函数和普通函数的区别?
» 什么时候不能使用箭头函数?
» Set 和 Map 的区别?
» map 和 forEach 的区别?
» for...in 和 for...of 的区别?
「Ajax API模块」
» ajax同源策略的理解,如何解决跨域?
» HTTP状态码有哪些?
» get 和 post 的区别?
» HTTP 和 HTTPS 的区别?
» 浏览器从输入url到渲染页面,发生了什么?
» 输入url 后 http请求的完整过程是什么?
» 浏览器缓存原理?(网站怎么优化)
「Vue2和Vue3」
» vue2 和 vue3的区别?
» vue2相比vue3有什么缺点?
» vue3有哪些新特性吗?它们带来什么影响
» vue2 数据双向绑定原理
» v-model的实现以及实现原理?
» MVVM开发模式的理解?
» vue组件通信有哪几种方式?
» 的作用是什么?或者vue切换页面如何保存状态?
» vuex有哪几种属性?
» vuex和pinia的区别,优缺点?
» vue-router路由实现原理是什么?有什么不同
» $route 和 $router的区别?
» vue中key 的作用是什么?
» 虚拟DOM和真实DOM的区别?
» computed 、watch 、methods的区别?
» 组件中的data为什么是一个函数?
» v-if 和 v-show的区别?
» vue数据变化视图不更新如何解决?
» 父子组件生命周期渲染顺序?
「前端性能优化」
» 前端性能优化的几种方式
» Vue首屏渲染优化有哪些?
» Vue项目做了哪些优化?
» CDN加速静态资源是什么?
「前端工程化」
» express 和 koa 有什么区别?
» 谈谈你对webpack的看法
» 前端为什么要进行打包和构建?
» webpack的基本功能有哪些?
» 常见的Webpack Loader?解决什么问题
» Loader 和 Plugin 的不同?
» 有哪些常见的 Plugin插件?解决什么问题的?
» Vite 和 Webpack区别?
» 为什么Vite 比 webpack速度快?
「职业技能规划、人事面试」
» 你的职业规划是什么?
» 为什么从上一家公司离职?
» 前端是如何学习的?
» 项目中有遇到什么难题?
» 还有什么想问的
「自我介绍(仅供参考)」
注意: 别紧张,目光注视面试官,不要有小动作,自信!!自信!!自信!!
面试官您好,我叫XXX,目前从事前端开发工作已经有X年,我上家公司是一个外包公司做别人的项目的,主要从事H5页面,后台管理系统和小程序等项目开发,其中H5和PC端是一套做保险相关业务的,在做H5的时候遇到过一个bug就是做微信SKD分享签名无效,请求的后台数据也返回了,后端就反映不是自己的问题,但反复排查发现是后端返回的签名和公众号配置的签名不一致,导致签名无效,分享失败...我呢平常喜欢逛一些技术社区丰富自己的技术,像知乎,掘金之类,并且自己也独立开发了个人博客网站,记录自己的工作总结和学习心得。 我的性格比较温和,跟同事朋友相处时比较外向,在工作中代码开发时我喜欢全心全意的投入,对于工作我也抱着认真负责的态度。面试官,以上是我的介绍,谢谢。
「HTML、CSS相关」
» H5有哪些新特性?
- 语义化标签: main、header、nav、article、section、aside、footer
语义化指的就是合理正确的使用语义化标签来创建页面结构,如: header、nav、footer,从标签上就能看出这个标签的作用,而不是滥用div 语义化的优点: 代码结构清晰,易于阅读、利于开发和维护 方便其他设备解析(如屏幕阅读器)根据语义渲染网页 有利于搜索引擎优化(SEO),搜索引擎爬虫会根据不同的标签来赋予不同的权重» CSS3有哪些新特性?
其实并不存在真正意义上的CSS3,因为我有阅读W3C文档
css3并不是一个单一的规范,而是一系列独立模块的集合,这些模块扩展了css的功能
这种模块化的方法允许不同的特性以不同的速度发展,可以更快的标准化一些特性,而不必等待整个规范的完成
选择器 新的属性选择器, 如: [attr^=value] 属性值以特定字符串开头 结构性伪类: nth-child nth-last-child first-child 背景和边框 边框图片:border-image, 允许使用图片来创建边框 多重背景,支持在单个元素上使用多个背景图片 文本效果 文本阴影: text-shadow 文本溢出: taxt-overflow 转换和动画 2D 和 3D 转换( transform ),包括旋转( rotate )、缩放( scale )、倾斜( skew )和平移 ( translate )。 CSS 动画( animation ),允许定义关键帧动画,控制动画序列» 浏览器渲染机制、重排、重绘
网页生成过程:
- HTMl被HTML解析器解析成DOM树
- css被css解析器解析成CSSOM树
- 结合DOM树和CSSOM树,生成一颗渲染树(Render Tree)
- 生成布局(flow),将所有渲染树的所有节点进行平面合成
- 将布局绘制(paint)在屏幕上
重排(也叫回流):当改变DOM元素位置和大小时,浏览器需要重新计算元素的几何属性,将其安放在界面的正确位置,这个过程叫做重排
触发:
- 添加或者删除DOM元素
- 元素位置改变、元素尺寸改变、内容改变
- 浏览器窗口尺寸改变
重绘: 第一次渲染内容称为绘制,之后重新渲染叫重绘;当一个元素的外观发生改变,但布局没有发生变化,重新绘制外观的过程
触发: 改变元素的颜色、文字颜色、背景色、边框颜色,样式等属性
总结:重排一定会引起重绘,重绘不一定会引起重排,重排的性能消耗比重绘大
尽量减少或者避免回流的发生,这个过程是非常消耗性能的
如何避免性能影响?
- css避免使用table布局,避免设置多层内联样式
- 避免频繁操作DOM,对于大量插入DOM操作,建议使用文档片段;用js修改样式,最好不要直接写样式,而是通过class来修改样式
» 分析将JS文件放在HTML文档的不同位置对加载和执行的影响
通常在开发中,JavaScript元素的编写位置我们会放在头部或者尾部,它们是会有区别的。 情况一:普通JavaScript放在头部 1. 当JavaScript文件放置在文档的头部时,浏览器在解析HTML到达<script>标签时会暂停,进行脚本的下载和执行。 2. 这意味着,直到JavaScript执行完成,页面的其余部分(如HTML和CSS)才会继续加载。 3. 这种做法通常会导致可见的延迟,尤其是当脚本文件较大或网络条件较差时。 4. 另外如果涉及到DOM元素操作,因为DOM还没有构建完成,所以操作DOM可能会失败,也需要慎重操作。 情况二:普通JavaScript放到尾部 1. 将JavaScript放在页面底部是一种常见的做法,以提高页面的加载速度。 2. 这样,浏览器可以先加载页面的所有HTML和CSS内容,使用户尽快看到页面的结构和样式,而脚本将在页面的内容完全加载之后才开始下载和执行。 3. 这种方法通常可以提高首次渲染时间和用户感知的加载速度。 4. 当JavaScript放置在页面的底部时,它将在大部分或全部DOM元素已经加载后执行,从而减少了因DOM元素尚未加载而导致的错误。 我们可以结合前面学习defer和async来回答: 1. 为了进一步提升性能,现代的开发实践中常常利用async和defer属性。 2. defer属性让脚本的下载与DOM解析同步进行,但延迟到整个页面解析完成后再执行。 3. async属性允许浏览器异步下载脚本,而不阻塞DOM的解析,脚本会在下载完后立即执行。 4. 这两种属性都有助于优化加载时间和用户体验,选择使用哪一种取决于脚本的具体作用和需求» 简述CSS盒模型
- 标准盒子(内容盒子): 给盒子设置box-sizing:content-box , 宽度 = 内容的宽度,如果后期添加了 padding 或border就会使盒子向外扩张
- IE盒模型(边框盒子): box-sizing:border-box, 设置的宽度 = 内容宽度 + padding + border; 添加的padding和border就在原先设置的width里,padding和border越大就会向内部content扩张,导致content变小
» 如何让盒子水平垂直居中
- 绝对定位方法: top、bottom、left、right设置为0, margin:auto
- 绝对定位方法:top:50%;left:50%; margin-left: 宽度的一半; margin-top:高度的一半
- 绝对定位方法:不确定div的宽度和高度,利用transform: translate(-50%,-50%)
- flex弹性盒布局:父:display:flex; 垂直居中-align-items:center; 水平居中-justify-content:center
» 如何实现一个三角形?
.box { width: 0; height: 0; line-height: 0; font-size: 0; border: 50px solid transparent; border-left-color: pink; } 想要哪个方向的三角设置哪个方向的边框颜色» CSS样式优先级
!important(无穷大) > 行内样式(1000) > id选择器(100) > 类选择器(10)、属性选择器、伪类选择器 > 标签选择器、元素选择器(1) > 继承或 *通配符选择器(0)
- id选择器 ( # myid)
- 类选择器( .box ) 属性选择器 (a[resl = 'external']) 伪类选择器 (a:hover, li:nth-child())
- 标签选择器 (p,div,h1-h6) 伪元素选择器 (p::after p::before)
» display:none 和 visibility: hidden 的区别?
共同点: 都用来隐藏元素
不同点:
- display:none; 隐藏元素不占据任何空间,会导致重排和重绘
- visibility:hidden; 隐藏元素的时候还会占据空间,只是内容不可见,只会导致重绘
- display:none; 非继承属性,子孙节点的消失是因为渲染树消失造成的,通过修改子孙节点属性无法显示
- visibility:hidden; 继承属性,子孙节点的消失是由于继承了hidden,通过设置visibility:visible;可以让子孙节点显示
» 去除浮动的几种方式?(问可顺带答出BFC)
浮动的元素会脱离文档流,什么叫脱离文档流,举个栗子: 有一天你和你老板说:世界那么大,你想去看看,那之后你老板就管不了你了。脱离文档流也同理,一个元素一旦浮动,就会脱离文档流,那父元素也就管不了他了,布局就会往前推进, 父元素就会出现高度塌陷的问题。
- 将父级设置成浮动,float:left 缺点:父级设置浮动了,那爷爷不也受影响了,又得解决爷爷的高度塌陷问题,无限套娃🪆
- 给父级设置定位absolute, 缺点:也会脱离文档流,影响布局
- 给父级设置overflow:hidden,缺点:文本过长,且包含英文时,会出现英文文本被隐藏
- 给父级设置对应的高度,缺点:浮动元素定高还好,如果不定高的情况就不灵活了
- 末尾增加空的div,设置clear:both,缺点:增加了一个div标签
- 给父级添加伪元素进行clear, ::after,伪元素不会被当作dom标签渲染出来(目前最优解)
» 什么是BFC?BFC布局规则是什么?如何创建BFC?
针对BFC网上也是有特别多的说法,我也看过很多视频和文章讲解,后来我查W3C文档是这么说的
在标准流中,我们所有的盒子,不管是行内盒子还是块级盒子,都属于一个FC(格式化上下文),块级盒子属于BFC(块级格式化上下文),行内盒子属于IFC(行内格式化上下文); BFC就是决定盒子是如何排布的,在BFC中,box盒子会在垂直方向一个挨着一个排布,垂直方向的间距是由margin来决定的,并在同一个BFC中,两个相邻的box之间的margin会重叠; 这个就是BFC官方解释!!
哪些元素会生成BFC?
创建BFC的方式有很多,要根据不同的场景去使用不同的方式;
比如HTML根元素本身就创建一个BFC
- 浮动元素: float
- 绝对定位元素absolute和固定定位元素fixed
- 在开发中我们想要在很多情况下不影响布局创建BFC,常用的就是将overflow设置为非visible,比如auto就可以创建BFC
问: 如何解决BFC折叠问题?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta content="width= , initial-scale=1.0"> <title>Document</title> </head> <style> .box1 { height: 100px; background-color: red; margin-bottom: 100px; } .box2 { height: 100px; background-color: pink; margin-top:50px; } .container { overflow: auto; } </style> <body> <!-- 问题: html根元素本身就会创建一个BFC, box1和box2都在同一个BFC下面 同一个BFC中,相邻的两个盒子的margin会发生一个重叠,所以这两个盒子的margin还是100px --> <!-- 解决方法:给box1 创建一个新的BFC,创建一个container盒子进行包裹, 添加 overflow属性既不会影响布局,还能创建BFC--> <div> <div></div> </div> <div></div> </body> </html>» cookies、localStorage、sessionStorage的区别?
- 数据生命周期:
- cookie:可以设置失效时间,默认浏览器关闭失效
- local:本地持久化存储,除非手动删除否则永久保存
- session:仅在当前页有效,浏览器关闭或者页面关闭就会被清除
- 存放数据大小:
- cookie:数据不能超过4k,主要用于保存登录信息,比如登录某个网站看到“记住密码”,通过往cookie存入一段辨识用户的数据来实现的
- local、session:虽然也有存储大小限制,但比cookie大很多,一般在5M或更大
- http请求
- cookie每次请求都会携带http头中,如果使用cookie保存过多数据会带来性能问题;
- local、session在浏览器中保存,不参与和服务器的通信
- 作用域不同
- sessionStorage:不在不同的浏览器窗口中共享,即使在同一个页面
- localStorage和cookie:在所有同源窗口中都是共享的;只要浏览器不关闭,数据仍然在
从安全性来说,因为每次http请求都会携带cookie,这样浪费了带宽,所以cookie尽可能少用,此外cookie需要指定作用域,不能跨域调用,限制很多;local和session可以用来在页面传递参数,session可以保存一些临时的数据,防止用户刷新页面丢失一些参数
「JS」
» 什么是闭包?
通俗一点就是打通了一条函数外部访问函数内部作用域的通道,正常情况下函数外部是访问不到函数内部作用域变量的
如何判断闭包:函数嵌套函数、内部函数被return、内部函数调用外层函数的局部变量
优点:隔离作用域,不造成全局污染
缺点:导致函数变量一直保留在内存中,过多的闭包会导致内存泄露(任何对象不需要它后仍然还在)
闭包的主要作用:延伸变量的作用范围
适用场景:封装组件、for循环和定时器结合、节流和防抖也会用到
vue中出现内存泄露的情况:
- 全局变量引起的内存泄露
- 监听事件没有解绑,在页面销毁的时候,顺便解绑,释放内存,原则不用的东西及时归还
- echarts页面切换的时候,还保留在内存中,导致浏览器卡顿
» 作用域、作用域链、变量提升、函数提升分别是什么?
作用域: js识别变量的范围,包括全局作用域(任何地方都可访问的变量)、局部作用域(只在函数内部定义的变量范围)、块级作用域(ES6用const、let定义的变量都认为是块级作用域中的变量)
作用域链: 从当前作用域开始一层一层向上寻找某一个变量,直到找到全局作用域还是没找到,就放弃!这查找的过程,就是作用域链
变量提升: 使用var关键字定义的变量,只提变量,不提赋值
函数提升: 使用function声明的函数,只提函数,不调用函数
» JS有哪些数据类型?typeof、instanceof、类型转换
js属于弱类型语言(支持隐式转换)
数据类型: String、Number、Boolean、Null、undefined、Object(function,array--堆内存)、symbol(ES10BigInt--栈内存)
typeof: 基本数据类型除了null返回Object,其他都返回对应的类型; 引用数据类型除了函数其他都返回Object
instanceof: 判断一个对象是否是另一个对象的实例,注意只能用来判断对象
null表示空对象,undefined表示已在作用域中声明但未赋值的变量
» 原型和原型链
原型:js中万物皆对象,每一个对象都有自己的属性,js中如何让多个对象共用一个或多个方法呢?原型的出现就是为了解决这个问题,每一个对象都有一个与他关联的原型对象,每次获取对象属性都是一次查找过程,在对象的自有属性中找不到就会去查找它的原型对象
原型链:原型连成一条链,当我们访问一个对象的属性时,如果这个对象内部没有这个属性,我们就会去它的原型对象中查找这个属性,这个原型对象又会有自己的原型,于是这样一直向上查找,直到找到Object为null的时候,这个查找的过程就是原型链
总结:
- 原型存在的意义就是组成原型链
- 原型链存在的意义就是继承:访问对象属性时,在对象本身找不到,就会按原型链一层一层找,说白了就是一个对象可以访问其他对象的属性
- 继承存在的意义就是属性共享:好处:1.代码重用2.可扩展,不同对象可以继承相同的属性,也可以定义只属于自己的属性
» 继承(含ES6)、多种继承方式
- 原型链继承 – 重写prototype
- 构造函数继承 – Parent.call(this)
- 组合继承 – 重写prototype + Parent.call(this)
- 原型式继承 – Object.create(Parent),不添加额外的属性和方法
- 寄生式继承 – Object.create(Parent),添加额外的属性和方法
- 寄生组合式继承 – Object.create(Parent) + Parent.call(this)
- ES6类的继承 – extends + super(props)
- 原型链继承口述:写个父类、子类,子类的原型为父类的实例,子类.prototype = new 父类,修正子类原型为子类本身, 子类.prototype.constructor = 子类, new 子类即可调用父类方法,构造函数继承,写个父类、子类,在子类中父类.call(this)即可实现
» this指向、new关键字
- 构造器函数调用:this指向new创建的新对象
- 箭头函数不绑定this: 捕获在上下文的this,在哪里定义指向谁
- 全局函数中,this指向的是window
- 普通函数this,谁调用指向谁
new操作符干了什么?
- 内存中创建一个新对象
- this指向这个新对象
- 执行构造函数里边代码添加属性
- 返回新对象(所以构造函数里不用return)
» bind、call、apply的区别?
- 都可以改变函数内部this指向
- call、apply可以调用函数,bind不会调用函数