前端面试八股文个人总结

1,757 阅读40分钟

前端面试八股文是指在面试过程中经常被问到的问题,大多都有固定化、格式化的答案。

下面总结了一些经典的面试八股文。

说在前面,这个只是很基础的一些知识点的了解,希望能帮助的是一些不善于表达或者总结的人,更重要的还是在于你的项目经验和开发能力.祝愿大家都能找到一份满意的工作

HTML + CSS

1. 讲一下盒模型,普通盒模型和怪异盒模型有什么区别?

在我们HTML页面中,每一个元素都可以被看作一个盒子,而这个盒子由内容区(content)、填充区(padding)、边框区(border)、外边界区(margin)四部分组成。

标准盒子: 总宽度 = 内容的width + padding(左右) + border(左右) + margin(左右)

怪异盒子: 总宽度 = 内容的width(padding(左右) + border(左右)) +  margin(左右)

2. 块元素和行内元素区别是什么?常见块元素和行内元素有哪些?

块级元素

特点: 独占一行 宽度默认是父元素的宽度,高度由内容撑开 可以设置宽高 例如: div p h li

行内元素

特点: 一行可以显示多个 宽高默认内容撑开 设置宽高无效 例如: a span em strong

行内块元素

特点 : 一行显示多个 可以设置宽高 input textarea button

模式转换

display:block 转块元素 display:inline 转行内元素 display:inline-block 转为行内块

3. HTML语义化标签 有哪些?

语义化标签: 合适的内容使用合适的标签,能够见名知意,利于SEO

strong  em  title  nav  head  main  footer  aside  ol  ul  h1

4. 伪类和伪元素的区别是什么?

区别在于:它们是否创造了新的元素,关键点在于如果没有伪元素(或伪类),是否需要添加元素才能达到效果,如果是则是伪元素,反之则是伪类

  • 伪元素控制的内容和元素是没有差别的,但是它本身只是基于元素的抽象,并不存在于文档中,所以称为伪元素。用于将特殊的效果添加到某些选择器

  • 伪类用来添加一些选择器的特殊效果,功能和class类似,所以叫伪类

5. CSS如何实现垂直居中?

  • 组合使用display:table-cell和vertical-align、text-align,使父元素内的所有行内元素水平垂直居中
  • display:flex布局 justify-content定义水平方向的元素位置,align-items定义垂直方向的元素位置
  • 绝对定位+transform反向偏移。position:absolute; transform:translate(-50%,-50%),未知盒子宽高比较推荐.
  • 绝对定位+margin:auto(position:absolute; left:0; top:0; right:0; bottom:0; margin:auto)
  • 绝对定位+margin反向偏移 position:absolute; top:50%; left:50%; margin-left:-(width+padding)/2+'px'; margin-top:-(height+padding)/2+'px';
  • margin 位移,已知盒子宽高,直接计算两个盒子的距离

6. CSS常见的选择器有哪些?

标签选择器,类选择器,id选择器,交集选择器,后代选择器,伪类选择器,属性选择器

7. CSS的优先级如何计算?

!important > 内联样式 >  id  >  class  >  标签  >  通配符  > 继承  >   默认

8. 长度单位px、em和rem的区别是什么?

  • px : 相对长度单位,像素px是相对于显示器屏幕分辨率而言的
  • em : 相对长度单位,相对于当前对象内文本的字体大小
  • rem : 相对于根元素,只需要在根元素确定一个参考值。 rem适配的原理: rem是相对于 根元素字体大小的一个单位.

原理:利用媒体查询或js动态检测设备的宽度,不同宽度下动态设置对应的根元素字体大小,设备宽度发生变化(根元素字体大小也会变化),那么所有使用根元素的那些内容自然就跟着变了

9. 讲一下flex弹性盒布局?

  • flex 是flexible box 的缩写,即为“弹性布局”,用来为盒子模型提供最大的灵活性,任何容器都可以指定为flex布局;
  • 伸缩布局 = 弹性布局 = 伸缩盒布局 = 弹性盒布局 = flex布局
  • ①设置弹性盒子的元素不会脱离文档流,并且有自适应的特性
  • ②当父元素为弹性盒子,非块级元素的元素也可以直接设置宽高

常见属性 :

  • display:flex 、inline-flex 父元素设为 Flex 布局以后,其子元素的float、clear和vertical-align属性将失效

  • flex-direction 属性 决定主轴的方向

  • flex-wrap 属性   定义子元素是否换行显示

  • justify-content属性 定义了项目在主轴上的对齐方式。 

  • align-items 属性   定义项目在侧轴(单行)上如何对齐。

  • align-content 属性  定义了多根轴线的对齐方式对于单行子元素,该属性不起作用

10 .怎么实现一个左侧固定,右侧自适应的布局?

父元素 :display:flex 子元素左边固定宽度,右边flex:1

  • 可以 额外了解一下flex:1是什么意思 flex: 1; 的值是 flex-grow: 1; flex-shrink: 1; flex-basis: 0%;

意思就是: 元素占据剩余宽度的 1 份,收缩比例为 1,因为 flex-basis 具有最高优先级,元素首次分配宽度(flex-direction: colunm; 则为高度)如果父元素有设置宽度,则为 0%;父元素没有设置宽度,则和 auto效果一致。

10. 浮动塌陷问题解决方法是什么?

  •    给父盒子设置boder 
  •    给父盒子设置padding值
  •    给父盒子设置overflow:hidden
  •    给父盒子添加position:fixed
  •    给父盒子添加display:table
  •    利用伪元素给父元素前面添加一个空元素
  •    转换为行内块元素
  •    设置浮动

11. position属性的值有哪些?各个值是什么含义?

相对定位 relative 自身偏移前的位置为参照,margin有效,不会脱离标准流

绝对定位 absolute 以带有定位的父元素为参照,否则以浏览器窗口,脱标margin失效

固定定位 fixed 浏览器窗口为参照,会脱标

静态定位 static 默认值不脱标

12.BFC、IFC是什么?

  • BFC(Block Formatting Context)直译为"块级格式化上下文",是 Web 页面的可视化 CSS 渲染中的一部分,是布局过程中生成块级盒子的区域,也是浮动元素和其他元素的交互限定区域。BFC 是一个独立的布局环境,其中元素的布局是不受外界的影响。
  • IFC(Inline Formatting Contexts)直译为"内联格式化上下文",IFC 的 line box(框)高度由其包含行内元素中最高的实际高度计算而来(不受到竖直方向的 padding/margin 影响)。形成条件非常简单,需要注意的是当IFC中有块级元素插入时,会产生两个匿名块将父元素分割开来,产生两个IFC

13.用css怎么实现一个三角形

/*记忆口诀:盒子宽高均为零,三面边框皆透明。 */

div:after{ 
   position: absolute;
   width: 0px; 
   height: 0px; 
   content: " "; 
   border-right: 100px solid transparent;
   border-top: 100px solid #ff0;
   border-left: 100px solid transparent;
   border-bottom: 100px solid transparent; }

JavaScript

1. 谈谈对原型链的理解。

  • 定义: 每一个对象,都有__proto__指向自身的原型。 而原型也是对象,也有自己的__proto__指向原型的原型,以此类推形成链式结构,称之为原型链。(原型链的终点是null)

  • 对象访问原型链中成员的规则 :就近原则. 当访问对象的成员,先看自己有没有,有则访问,没有则看原型有没有。 原型有则访问, 没有则访问原型的原型,没有则继续往上找。以此类推,一直找到原型链终点 : null. 还没有的话, 如果是属性则获取undefined ,如果是方法 ,则报错xxx is not function

  • 构造函数,实例对象和原型对象三者之间的关系:

    1)prototype是构造函数的属性,指向原型对象
    2)__proto__是每个实例都有的属性,指向原型对象
    3)实例的__proto__与其构造函数的prototype指向的是同一个对象

image.png

2.js如何实现继承?

继承的作用: 可以让多个构造函数之间建立关联,便于管理和复用

  • 原型链继承 将构造函数的原型设置为另一个构造函数的实例对象,这样就可以继承另一个原型对象的所有方法student.prototype=new Person()
  • 借用构造函数继承 为了解决原型中包含引用类型值的问题,开始使用借用构造函数,继承的是父类的属性 person.call(this,name)
  • 组合继承 将原型链和借用构造函数的技术组合到一块。使用原型链实现对原型方法的继承,而通过构造函数来实现对实例属性的继承。
  • 原型式继承 不自定义类型的情况下,临时创建一个构造函数,借助已有的对象作为临时构造函数的原型,然后在此基础实例化对象,并返回。本质上是object()对传入其中的对象执行了一次浅复制
  • 寄生式继承 其实就是在原型式继承得到对象的基础上,在内部再以某种方式来增强对象,然后返回。 寄生式继承在主要考虑对象而不是自定义类型和构造函数的情况下非常有用。
  • 寄生组合式继承 组合继承是JS中最常用的继承模式,但其实它也有不足,组合继承无论什么情况下都会调用两次超类型的构造函数,并且创建的每个实例中都要屏蔽超类型对象的所有实例属性。寄生组合式继承就解决了上述问题,被认为是最理想的继承范式。

3.js有哪些数据类型?(MDN上介绍的八种)

  • 简单数据类型 number、string、boolean、undefined、null.symbol.bigint

  • 复杂数据类型 object(array、function.date....)

4. js有哪些判断数据类型的方法?

1 ) typeof 用于判断简单数据类型 ,null检测结果是object

2 ) instanceof 判断左边的能不能通过原型链找到右边的prototype

3 ) object.prototype.toString.call()可以判断所有类型对象原型上的tostring方法

5.如何判断一个变量是否数组?

  • 使用 instanceof Array 判断,如果返回true, 说明是数组

  • 使用 Object.prototype.toString.call判断,如果值是 object Array, 说明是数组

  • 通过 constructor 来判断,如果是数组,那么arr.constructor === Array.

数组的push和pop方法的返回值是什么?

push:新增之后的数组长度; pop:删除的那个元素

伪数组是有数组的长度,能够通过下标去访问元素,但是没有真的数组的方法。

伪数组转真数组的方法有,Array.from() 和 展开运算符 [...arr]

6.Null 和 undefined 的区别?

  • undefined : 未定义。 当变量只声明,但是没有赋值。此时默认值是undefined
  • null : 有定义。 定义的值是空值
  • 相同点 : (1)值相等 (2)转布尔类型都是false
  • 不同点 : (1)数据类型不同 (2)转number类型的值不同,undefined和数字相加是NAN,null和数字相加是数字本身

7.call bind apply的区别?

相同点:

  • 都是改变this指向的;
  • 第一个参数都是this要指向的对象;
  • 都可以利用后续参数传参;

不同点:

  • 传参方式不同 call.bind逐一传参一一对应,apply第二个参数是数值或者维数组
  • 执行机制不同 call和apply都是对函数进行直接调用,而bind方法返回的仍是一个函数.需要手动调用

8.说一下防抖节流的概念?如何实现防抖和节流。

防抖 : 高频率触发的事件,在指定的单位时间内,只响应最后一次,如果在指定的时间在触发,则重新计算时间(后面触发的事件执行,替代了前面的事件)

  • 应用场景: 输入框搜索事件
  • 实现流程: 1)声明一个全局变量存储定时器ID

2)每次触发交互时,先清除上一次的定时器,然后把本次事件处理代码放入定时器中

节流 :高频率触发的事件,在指定的单位时间内,只响应第一次(前面触发的执行前,忽略后面的事件)

  • 应用场景 :滚动条高频触发事件
  • 实现流程 : 1)声明一个全局变量存储触发时间

2)每一次触发事件时,获取当前时间

3)判断当前时间与上一次触发时间,是否超过间隔

4)如果产超过触发间隔,则执行事件处理代码.然后存储本次触发事件

9. 深拷贝、浅拷贝的区别?如何实现深拷贝和浅拷贝?

浅拷贝:浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是值,如果属性是引用类型,拷贝的就是内存地址。

 如何实现浅拷贝

 Array.prototype.slice()

 Array.prototype.concat()

 Object.assign

 展开运算符

深拷贝:深拷贝是将对象从内存中完整的拷贝出来,从堆内存中开辟新的区域存放新对象。

如何实现深拷贝 :

  1. 递归去复制所有层级属性

  2. JSON对象的parse和stringify

区别:浅拷贝基本类型之间互不影响,引用类型其中一个对象改变了地址,就会影响另一个对象;深拷贝改变新对象不会影响原对象,他们之间互不影响。

10.对比 一下var、const、let。

  1. var 声明的变量属于函数作用域,let 和 const 声明的变量属于块级作用域;

  2. var 存在变量提升现象,而 let 和 const 存在暂时性死区;

  3. var 可以重复声明,而在同一个块级作用域,let不能重新声明,const不能修改。

image.png

11. ES next新特性有哪些?

  • ES 全称 EcmaScript,是脚本语言的规范,JavaScript 是 EcmaScript的一种实现,所以 ES 新特性其实指的就是 JavaScript 的新特性.

历史版本查看网址: www.ecma-international.org/publication…

image.png

12.箭头函数和普通函数区别是什么?

区别:

  • 箭头函数没有prototype(原型),所以箭头函数本身没有this
  • 箭头函数的this在定义的时候继承自外层第一个普通函数的this。
  • 如果箭头函数外层没有普通函数,严格模式和非严格模式下它的this都会指向window(全局对象)
  • 箭头函数本身的this指向不能改变,但可以修改它要继承的对象的this。
  • 使用new调用箭头函数会报错,因为箭头函数没有constructor
  • 箭头函数不支持new.target
  • 箭头函数不支持重命名函数参数,普通函数的函数参数支持重命名
  • 箭头函数相对于普通函数语法更简洁优雅

箭头函数的注意事项:

  • 箭头函数一条语句返回对象字面量,需要加括号
  • 箭头函数在参数和箭头之间不能换行
  • 箭头函数的解析顺序相对||靠前

不适用场景: 箭头函数的this意外指向和代码的可读性。

13.使用new创建对象的过程是什么样的?

  1. 创建一个空对象
  2. 指向这个对象 修改构造函数this指向空对象,并执行函数体
  3. 给对象赋值 空对象指向构造函数的原型对象 obj.__proto__= Fn.prototype
  4. 判断返回值 返回对象就是用该对象,没有的话就创建一个对象

14.this指向系列问题。

  • 全局作用域或者普通函数中 this 指向全局对象 window。
  • 方法调用中谁调用 this 指向谁
  • 在构造函数或者构造函数原型对象中 this 指向构造函数的实例
  • 箭头函数中指向外层作用域的 this

15.谈谈对闭包的理解?什么是闭包?闭包有哪些应用场景?闭包有什么缺点?如何避免闭包?

定义 : 闭包就是能够读取其他函数内部变量的函数

闭包的作用: 1)读取函数内部的变量;2)让这些变量始终保持在内存之中。

应用场景 : 作用域链,高级排他,函数节流,参数传递

  • 例如计数器、延迟调用、回调等闭包的应用,其核心思想还是创建私有变量和延长变量的生命周期

闭包的注意事项 : 因为闭包不会销毁变量 所以会造成内存泄漏 也就是说当闭包的变量过多时会导致内存占用过大从而导致运行速度变慢。

  • 在闭包使用结束后手动清除或者置空变量或者方法

16.谈谈对js事件循环的理解?

  • js代码开始执行后,主线程执行栈中会把任务分为两类.

  • 一类是同步任务, 一类是异步任务; 主线程执行栈优先执行同步任务,

  • 异步任务会被放入特定的处理程序中,满足条件后,被放到消息(任务/事件)队列中

  • 主线程执行栈中所有的同步任务执行完毕后通过事件循环去消息(任务/事件)队列中

  • 挑选优先满足条件的程序放入主线程执行栈中,执行事件循环周而复始一直执行。

17.谈对promise理解?

promise是es6新增的特性,它是一个对象或者是一个函数。一般作为一个构造函数来使用,需要new一下来创建一个promise实例,它里面有三种状态:

  • Pending(进行中,初始状态,既不是成功,也不是失败状态。)、

  • Resolved(已完成,又称 Fulfilled)、

  • Rejected(已失败)

promise的构造函数接受一个参数,这个参数是一个函数,并且传入两个参数:

  • resolve ,reject 分别表示异步操作执行操作成功后的回调函数和异步操作执行失败之后的回调函数
  • 可以在then方法中继续写promise对象并返回,然后继续调用then来进行回调操作

promise 的静态方法有 race 、all 、 any。实例方法有 :.then() .catch()

  • race :返回的是一个 promise 对象,表示可以获取到迭代的第一个完成结果的值,这个的成功还是失败,需要看这个值的结果是成功还是失败。
  • all : 表示并发请求,按顺序拿到结果,如果请求中有一个是错误,那么就会抛出一个错误的 promis ,不会向下执行。

promise可以解决回调地狱的问题

promise虽然解决了回调地狱,但是并不能简化代码,所以工作中一般会搭配 async 和 await来使用

async await 是es7里面的新语法、它的作用就是 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。它可以很好的替代promise 中的then

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句

18. http和https的区别

1、HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前的网易官网是http,而网易邮箱是 https 。)

2、HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。

3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)

19. 本地持久化的方式和区别

关于cookie、sessionStorage、localStorage三者的区别主要如下:

  • 存储大小:cookie数据大小不能超过4k,sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大

  • 有效时间:localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage数据在当前浏览器窗口关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭

  • 数据与服务器之间的交互方式,cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端;sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存

应用场景 :

  • 标记用户与跟踪用户行为的情况,推荐使用cookie
  • 适合长期保存在本地的数据(令牌),推荐使用localStorage
  • 敏感账号一次性登录,推荐使用sessionStorage

20. js延迟加载的方式

  • [defer 属性]
  • [async 属性]
  • [动态创建DOM方式]
  • [使用setTimeout延迟方法]
  • [让JS最后加载]

21. 如何减少重绘和回流

  • 当页面中元素的样式改变并不影响它在文档中的位置,浏览器会将新样式赋予元素并重新绘制他,这个叫重绘

  • 当元素的尺寸、结构等属性改变时,浏览器重新渲染部分或者全部文档的过程称为回流

  • 注意:回流要比重绘更耗费性能,我们在做开发的时候尽量减少回流

区别 :

  • 回流必将引起重绘,而重绘不一定会引起回流(只有颜色改变的时候就只会发生重绘而不会引起回流)。
  • 当页面布局和几何属性改变时就需要回流(添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变)。

如何避免

  • 避免使用table布局
  • 不要使用css计算calc
  • 动画效果放在position为absolute或者fixed的元素上
  • 尽可能在dom树的最末端改变样式
  • 用js操作样式的时候尽量一次操作完或者将样式定义为一个class
  • 尽量避免过多的操作dom元素的新增和删除

22.说一下你对事件委托的理解?

是什么? 所谓事件委托,就是平常给子元素绑定的事件统一绑定到父类元素上

怎么用? 例如有100个li,可以直接给ul绑定事件

解决了什么问题? 后续新增的元素同样具有事件绑定的效果,而且提高了性能

原理是什么? 事件冒泡

Vue

1.讲讲对Vuex的理解和使用方法。

定义: vuex是一个专为 Vue.js 应用程序开发的状态管理模式,(vue中实现大范围数据共享的技术方案).数据流动清晰,存取一步到位,数据都是响应式的

理解: vuex是一个全局的状态管理库,解决了非关系型组件间数据的传递和共享问题,一般使用的时候里面有state.mutation.action.getters.modules.plugins等配置项,

  • 例如点击按钮把请求的数据存储到vuex,这个流程是视图=>dispatch=>action=>异步请求并拿到结果=>commit=>mutation=>修改state=>视图改变

原理:

  1. Vuex 本质是一个对象

  2. Vuex 对象有两个属性,一个是 install 方法,一个是 Store 这个类

  3. install 方法的作用是将 store 这个实例挂载到所有的组件上(Vue.mixin)

  4. Store 这个类拥有 commit,dispatch 这些方法,Store 类里将用户传入的 state 包装成 data,作为 new Vue 的参数,从而实现了state 值的响应式

使用流程:

1).下包 npm install vuex --save

2).导入 import Vuex from 'vuex';

3).安装插件 Vue.use(Vuex);

4).创建store对象

const store=new Vuex.Store({
//state中存放的就是全局共享的数据
state:{count:0} })

5).将store挂载到vue实例上

new Vue({
	el:'#app',
	render:h=>h(app),
	router,
	//将创建的共享数据对象,挂载到vue实例中
	//所有组件,就可以直接从store中获取全局的数据了
	store
})

核心属性:

state :vuex的基本数据,用来存储变量,可以把它是为vue中的data。

mutations : 更改 Vuex 的 store 中的状态,可以把它视为vue中的methods。 使用 store.commit 方法触发mutation来修改数据

actions:用于处理异步任务.发请求等,需要触发mutation来修改数据,使用store.dispatch 方法触发actions来处理异步任务

getters:可以对state中的变量进行处理,可以当做vue中的computed,计算属性

modules:模块,将store分割

2.谈谈你对Vue双向绑定原理的理解。

  1. vue双向数据绑定原理,又称vue响应式原理,是vue的核心,双向数据绑定是通过数据劫持结合发布订阅模式的方式来实现的,也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变

  2. vue双向数据绑定原理的实现,其核心是Object.defineProperty()方法

  3. Object.defineProperty(obj, prop, descriptor)方法,接收三个参数,分别为obj(定义其上属性的对象)prop(定义或修改的属性)descriptor(具体的改变方法),就是用这个方法来定义一个值,当调用时我们使用了它里面的get方法,当我们给这个属性赋值时,又用到了它里面的set方法

let obj = {}
Object.defineProperty(obj, 'prop', {
    get(){
        console.log('调用get方法')
    }
    set(newValue){
        console.log('调用set方法,方法的值是' + newValue)
    }
})
obj.prop    //调用get方法
obj.prop = 'p'    //调用set方法,方法的值是p

3.mvvm和mvc区别是什么?

MVC执行流程:
用户操作→View接收用户操作→Controller控制器处理用户操作→Model(数据持久化)→ 通知视图更新

image.png

MVVM 框架 :
实现了数据的双向绑定,也就是实现了View和Model的自动同步:当数据改变时,我们不用再手动操作Dom元素来更新视图,因为它会自动变化。

  • ViewModel能够观察到数据的变化,并通知视图更新
  • ViewModel能够监听到视图的变化,并能够通知数据发生变化

image.png

区别:

1、mvc和mvvm都是一种设计思想。 主要就是mvc中Controller演变成mvvm中的viewModel。 mvvm主要解决了mvc中大量DOM操作使页面渲染性能降低,加载速度变慢的问题 。

2、MVVM与MVC最大的区别就是:它实现了View和Model的自动同步:当Model的属性改变时,我们不用再自己手动操作Dom元素来改变View的显示,它会自动变化。

3.Vue组件间通信方式有哪些?

1、父子组件间通信

  • 子组件通过 props 属性来接受父组件的数据,然后父组件在子组件上注册监听事件,子组件通过 emit 触发事件来向父组件发送数据。

  • 通过 ref 属性给子组件设置一个名字。父组件通过refs组件名来获得子组件,子组件通过parent获得父组件,这样也可以实现通信。

  • 使用 provide/inject,在父组件中通过 provide提供变量,在子组件中通过 inject 来将变量注入到组件中。不论子组件有多深,只要调用了 inject 那么就可以注入 provide中的数据。

2、兄弟组件间通信

  • 使用 eventBus 的方法,它的本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通信的组件引入这个实例,通信的组件通过在这个实例上监听和触发事件,来实现消息的传递。
  • 通过 parent / refs 来获取到兄弟组件,也可以进行通信。

3、任意组件间通信

  • 使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。

4.computed和watch区别是什么?

  • 功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。

  • 是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。

  • 是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。

  • computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)

  • 使用场景:当一个属性受多个属性影响的时候,使用computed------购物车商品结算。当一条数据影响多条数据的时候,使用watch-----搜索框.

5.v-for和v-if同时使用有问题吗?

  • 有问题,官方文档不建议一起使用.

原因:

  • 因为当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。这意味着 v-if 将分别重复运行于 每个 v-for 循环中,即先运行 v-for 的循环,然后在每一个 v-for 的循环中,再进行 v-if 的条件对比,会造成性能问题,影响速度。

解决方案:

  • 可以用计算属性代替
  • 可以把v-if写在外层

6.讲讲前端路由原理。比较一下history和hash这两种路由。

路由原理:

路由的基本原理,就是在不刷新浏览器的情况下修改浏览器链接,同时监听链接的变化并找到匹配的组件渲染。满足这两个条件即可实现。

路由的实现通常有以下两种形式:

  • hash ( /#path )
  • history ( /path ) 两者之间的区别:

7.说说你对vue的理解,有了解过vue3吗?

vue是一个用于创建用户界面的渐进式JavaScript框架

vue的核心特性是MVVM,组件化和指令系统

vue3的特点:

  • Proxy响应式,
  • Composition解决代码反复横跳
  • 虚拟DOM

8.说说Vue的keep-alive使用及原理。

作用:实现组件缓存,保持这些组件的状态,以避免反复渲染导致的性能问题。 需要缓存组件 频繁切换,不需要重复渲染

场景:tabs标签页 后台导航,vue性能优化

原理Vue.js内部将DOM节点抽象成了一个个的VNode节点,keep-alive组件的缓存也是基于VNode节点的而不是直接存储DOM结构。它将满足条件(pruneCache与pruneCache)的组件在cache对象中缓存起来,在需要重新渲染的时候再将vnode节点从cache对象中取出并渲染。

keep-alive是一个组件,这个组件中有三个属性,分别是include、exclude、max

在created中创建缓存列表和缓存组件的key列表,销毁的时候会做一个循环销毁清空所有的缓存和key,

当mounted时会监控include 和 include属性,进行组件的缓存处理。

如果发生变化会动态的添加和删除缓存。渲染的时候会去拿默认插槽,只缓存第一个组件,取出组件的名字,判断是否在缓存中,如果在就缓存,不在就直接return掉,缓存的时候,如果组件没有key,就自己通过组件的标签、key和cid拼接一个key。

如果该组件缓存过,就直接拿到组件实例。如果没有缓存过就把当前的vnode缓存,和key做一个对应关系。这里面有一个算法叫LRU,如果有key就不停的取,如果超限了就采用LRU进行删除最近最久未使用的,从前面删除,LRU就是将当前使用的往数组的后面移,在最前面的就是最久未使用的。

9.谈谈对Vue生命周期的了解?

每个Vue实例在创建时都会经过一系列的初始化过程,vue的生命周期钩子,就是说在达到某一阶段或条件时去触发的函数,目的就是为了完成一些动作或者事件

  • create阶段:vue实例被创建
    beforeCreate: 创建前,此时data和methods中的数据都还没有初始化
    created: 创建完毕,data中有值,未挂载
  • mount阶段: vue实例被挂载到真实DOM节点
    beforeMount:可以发起服务端请求,去数据
    mounted: 此时可以操作DOM
  • update阶段:当vue实例里面的data数据变化时,触发组件的重新渲染
    beforeUpdate :更新前
    updated:更新后
  • destroy阶段:vue实例被销毁
    beforeDestroy:实例被销毁前,此时可以手动销毁一些方法
    destroyed:销毁后

父子组件加载渲染过程:

父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

子组件更新:

父beforeUpdate->子beforeUpdate->子updated->父updated

父组件更新过程:

父beforeUpdate->父updated

销毁

父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

10.你会在哪个阶段发请求,为什么?

created => 请求发的时机越早越好,请求之前可能需要依赖data里面的数据或者methods里面的方法

beforeDestory 干什么事? 解绑事件,清除定时器

11.你了解哪些和vue相关的性能优化?

  • v-if和v-show区分使用场景
  • v-for 循环的时候加key
  • v-for和v-if不要放到一行使用
  • computed和方法优先使用computed
  • 路由懒加载
  • 组件的异步加载
  • keep-alive

12.vue 中的data为啥是一个函数?

1.一个组件被复用多次的话,也就会创建多个实例。本质上,这些实例用的都是同一个构造函数。

2.如果data是对象的话,对象属于引用类型,会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。

(为了避免多个组件实例之间的数据相互影响,data是一个函数返回一个对象,这样再实例化的时候能保证自己的实例对应的是相对独立的一个对象空间,不会和其他的产生关系.)

13.说一下vue有哪些内置组件,什么是动态组件和异步组件?

内置组件: component 还有slot和 keep-alive

动态组件:

  • 让多个组件同使用一个挂载点,并且组件间可以动态切换,这个挂载点就是 component 标签
  • 简单来说是在 component 标签上添加一个is属性,属性值(即currentTabComponent)是控制组件间的切换的
  • 可配合keep-alive使用,这样切换的时候就可以不用频繁渲染
    • 1.keep-alive是vue的内置组件,可以包含动态组件,当组件之间进行切换时,可以保持组件的状态,在内存中缓存不活动组件的实例,而不是销毁它们)
    • 2.并且自身也不会渲染成一个DOM元素,不会显示在父组件链中

规则1. 语法 :is=‘component-name’ 动态对应 data 中对应的组件值

规则2.data中代表组件component的属性值必须是引入组件名

template:

<component :is=“DynamicName”/> // 动态的对应是 data 的值

//引入动态子组件

import Dynamic from ‘./Dynamic.vue//在components中声明

components: {
Dynamic,
}

//在data中定义

data(){
return {
DynamicName: ‘Dynamic’, // 这里DynamicName 的属性名必须是引入组件名Dynamic
}
}

异步组件:

  • vue的一种性能优化的方法,可以实现组件的按需加载
  • 组件通过import函数引用,什么时候需要什么时候加载
  • 有利于项目的性能优化,提高页面的加载速度
  • 路由懒加载就是使用了异步组件的原理

规则:使用import引入

components: {
login: () => import(‘./login.vue’)
},

14.简单说一下bable的编译过程

Babel 是一个 JavaScript 编译器,是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

Babel 本质上就是在操作 AST 来完成代码的转译。AST是抽象语法树(Abstract Syntax Tree, AST)

Babel 的功能很纯粹,它只是一个编译器。大多数编译器的工作过程可以分为三部分:

  1. 解析(Parse) :将源代码转换成更加抽象的表示方法(例如抽象语法树)。包括词法分析和语法分析。词法分析主要把字符流源代码(Char Stream)转换成令牌流( Token Stream),语法分析主要是将令牌流转换成抽象语法树(Abstract Syntax Tree,AST)。
  2. 转换(Transform) :通过 Babel 的插件能力,对(抽象语法树)做一些特殊处理,将高版本语法的 AST 转换成支持低版本语法的 AST。让它符合编译器的期望,当然在此过程中也可以对 AST 的 Node 节点进行优化操作,比如添加、更新以及移除节点等。
  3. 生成(Generate) :将 AST 转换成字符串形式的低版本代码,同时也能创建 Source Map 映射。

经过这三个阶段,代码就被 Babel 转译成功了

React

  1. 讲讲React diff算法。
  2. React组件复用方式有哪几种?
  3. React fiber是什么?有什么用?
  4. React生命周期有哪些?React16废弃了哪些?为什么要废弃?新增的生命周期钩子有哪些?有什么作用?
  5. 如何对React性能优化?
  6. React的setState是同步的还是异步的?
  7. 讲讲React事件绑定原理。
  8. 讲讲React的hooks,有什么好处?有哪些常用的hook?
  9. 讲讲Reactkey的作用。
  10. 谈谈React的类组件和函数式组件的区别。

计算机基础

  1. 进程与线程区别是什么?
  2. 讲讲TCP三次握手、四次挥手,为什么要三次握手、四次挥手?
  3. TCP和UDP区别是什么?

网络通信

1. 说说从输入url到页面展示出来的整个过程。

首先DNS会解析域名,生成对应的ip地址

然后会建立请求连接,进行3次握手,

之后连接成功之后,浏览器从服务器获取到请求的数据包,

浏览器开始解析数据包,通过数据包中的资源开始渲染页面,

执行 DOM 渲染 解析css ,js 等文件,最后渲染完成。

2. 什么是跨域?为什么会出现跨域?如何解决跨域问题?jsonp原理 是什么?

从一个网页去浏览到另一个网页的时候,域名、协议、端口号有一个不相同就会跨越

    1. CORS跟后端商量,将http响应头中配置Access-Control-Allow-Origin:*
    1. 使用JSONP 通过 script 模拟 ajax 发送请求的原理
    1. 第三方代理服务,通过配置 vue.config 中的 Proxy 的配置项去实现 跨域

3. https原理是什么?为什么可以保证安全性?

客户端在使用 HTTPS 方式与 Web 服务器通信时有以下几个步骤:

  1. 客户端使用 https url 访问服务器,则要求 web 服务器建立 ssl 链接
  2. web服务器接收到客户端的请求之后,会将网站的证书(包含了公钥)传输给客户端。
  3. 客户端和 web 服务器端开始协商 SSL链接的安全等级,也就是加密等级。
  4. 客户端浏览器通过双方协商一致的安全等级,建立会话密钥,然后通过网站的公钥来加密会话密钥,并传送给网站。
  5. web 服务器通过自己的私钥解密出会话密钥
  6. web 服务器通过会话密钥加密与客户端之间的通信

4. http常见状态码有哪些?

400(请求参数错误)

401(认证失败,一般是由于 Token 过期造成的认证失败/没有权限)

403(forbidden,禁止访问,没有权限,普通用户却访问了管理员的东西)

405(请求方法/方式错误)

200 (表示请求成功)

201(表示创建成功)

301(表示重定向)

500(服务器端未响应)

501(服务器不支持的响应)

5. get和post区别是什么?

在请求中,get 一般用于获取信息,不会携带数据,get 方法 url 会有长度限制。get的方法参数应该放在 请求头中,post 的方法参数放在请求体中。

post 一般用于获取带参数的请求

Post,请求大小无限制,向服务器提交数据后返回给前端,速度慢,安全, Get,请求大小有限制,直接响应,速度快,不安全。

6. cdn是什么?它的原理是什么?

· 是什么:内容分发网络。

· 用什么:国内最常用的是七牛CDN,公司花钱购买空间。

项目相关

1.介绍一下你最近做过的项目?

主要在于介绍这个项目干啥的,自己负责了哪些模块,主要运用了哪些技术点.,描述需要画面感

2.做这个项目有遇到什么问题吗?(举例路由缓存问题)

点击 用户 1 按钮 和 用户 2 按钮 共用了同一个路由组件 User,我在 User 里面根据 userId 发请求的时候,发现永远是第一次发起的那个请求,好奇怪,当时找不到原因。

template 里面获取数据是实时更新的,但是 created 拿不到最新的数据,后来发现原因是公用了同一个组件,而 created 这个钩子也只会在组件创建完毕执行一次,所以 ...

解决方式 1

 <template>
   <div>User {{ $route.params.id }}</div>
 </template>
 ​
 <script>
   export default {
     name: 'User',
     created() {
       console.log(this.$route.params.id)
     },
     watch: {
       $route(newRoute) {
         console.log(newRoute.params.id)
       }
     }
   }
 </script>

解决方式 2

 <router-view :key="$route.fullPath"></router-view>\

3.怎么处理1px问题?

1px 问题是UI设计稿是750px,但实际移动端375px,所以一般会使用二倍图,1px实际就是0.5px.但是移动端无法识别0.5px,渲染出来的1px就会比较粗

解决办法 : 设置 transform:scle 0.5

4.登录功能怎么完成的?

前端收集数据,校验数据评价 (普通校验 ,兜底校验) 提交数据到后端, 后端返回token 前端拿到token之后存到vuex和做数据持久化处理,然后在请求拦截器给请求头拼接携带token,在响应拦截器根据后端返回的数据做出相应的处理.

image.png

5.图片上传是怎么实现的?

1).准备一个input:file 然后用hidden隐藏

2).准备一个按钮,给按钮绑定点击事件,在事件的回调里主动触发input:file 的click事件

3).监听input 的onchange 事件,在回调里面通过e.target.filer拿到文件信息

4).创建formDate对象,把文件信息放进去通过axios传到后端

const form = new FormData()
form.appent('avatar',e.target.filer[0]

5).图片预览:URL.craterObjctURL(Blob) 或 FileReader(base64)

<input type="file" hidden id="file" />
<img id="img" alt="" />
<button id="btn">click</button>

<script>
  btn.onclick = function () {
    file.click()
  }
  file.onchange = function (e) {
    const f = e.target.files[0]
 
    const formData = new FormData()
    formData.append('avatar', f)
    // axios({ url: '/xxx', data: formData })
    /* const s = URL.createObjectURL(f)
       img.src = s */
    const fileReader = new FileReader()
    // 图片 => base64
    fileReader.readAsDataURL(f)
    fileReader.onload = function () {
      img.src = this.result
    }
  }
</script>

6.说一下路由懒加载和组件懒加载?

按需加载,需要的时候才导入使用

使用import引入

components: {
login: () => import(‘./login.vue’)
},

7.移动端有哪些常见问题,是怎么解决的呢

1).移动端的适配问题,解决适配问题的方法是使用配置媒体查询和引入 js 动态设置 rem 适配的方法,

2). 1px 像素问题 : 主要是 ui 给图的时候,基本上都是二倍图的形式给出的,假设设计图是750px 的二倍图,需要在375px的设备上显示,这个时候就需要将整体的设计图缩小一倍,然而 css 最大只支持 1px 大小,不足1px 就会显示1px,所以当我是0.5px 的时候,就会当成1px去显示,解决方式:设置 tranform:scale() 缩放解决

3).移动端左右滑动右侧有留白 :设置 html ,body的width 为 100% overflow:hidden

4).移动端点击300ms延迟 : 可以使用 fastclick.js 解决

8.图片懒加载是怎么实现的?

图片的懒加载的实现分为以下几点:

1.首先需要配置全局指令,

2.在全局指令中,使用 vueuse 提供的 api { IntersectionObserver } ,去监听我们页面的滚动

3.只有当监听到我们滚动到可视区域的时候,才会执行获取图片的操作,将获取到的图片信息地址,通过全局指令赋值给 img 的 src 属性。

import { useIntersectionObserver } from '@vueuse/core'
import defaultimg from '@/assets/images/load.gif'

// 图片懒加载思想:当图片进入可视区的时候,将真实的图片地址赋值给图片

export default {
  install (app) {
    // 第一个参数指令名称 ,第二个参数是配置信息
    app.directive('imgLazy', {
      // 这的自定义指令的 el 就是 dom 本身 第二个是 dom 绑定的属性数据
      mounted (el, binding) {
        // 绑定数据图片懒加载
        const { stop } = useIntersectionObserver(
          // 这里 el 表示绑定的 DOM
          el,
          ([{ isIntersecting }], observerElement) => {
            // console.log(isIntersecting)
            // console.log(target)
            // 通过判断 isIntersecting 的值去判断是否加载数据
            if (isIntersecting) {
              // console.log(defaultimg)
              // 如果 图片不存在的话就加载默认图片
              // if (!binding.value.length) {
              //   el.src = defaultimg
              //   console.log(666)
              // }
              el.onerror = function () {
                this.src = defaultimg
              }
              el.src = binding.value
              // 停止监听的 hooks
              stop()
            }
          }
        )
      }
    }
    )
  }
}
<img alt="" v-imgLazy="item.picture">  // 这里是 全局指令的使用

9.你封装过什么组件?用到了哪些技术

  • 每一个.vue文件就可以说是一个大的组件,一般称为业务组件
  • 第三方的UI组件 .element vant
  • 路由页面的面包屑组件,每一个路由页面的公众标题,编辑和新增功能的组件封装 上传组件....
  • 技术点 传值和校验, 插槽和作用域插槽,自定义事件
  • 作用域插槽 : 可以在父组件拿到子组件的数据,在父组件加工处理之后再交给子组件使用

10.除了网络回调异步函数以外有没有接触过其他异步函数?

11.定时器是异步函数,有没有用async await封装过setTimeout的异步函数

12.如果不用setTimeout的回调,应该怎么去实现async await去达到跟setTimeout一样的效果

13.怎么区分PC端和移动端

14. 移动端和PC端是两套布局,开发的时候如何去处理这两套布局

15.对接后端的的时候,有没有遇到过后端返回数据风格不一样,而导致要去做一些代码适配的问题,怎么处理的