2023年最新的 前端面试题(个人总结)

目录

vue

1.vue2 和 vue3 的区别

2.vue2 和 vue3的原理

3.组合式api 和 选项式api

3. Proxy和object.defineproperty

4..v-show 与 v-if 的区别

5.计算属性和 watcher

6.虚拟DOM

7.key的作用是什么?

8.v-if 和 v-for 的优先级是什么?

9.vuex

JS

1.原型 原型链

2.你对闭包的理解?

3.内存泄漏

4.数组的常用方法有哪些?

5.Promise

6.什么是防抖和节流?有什么区别?如何实现?

7.谈谈 this 对象的理解

8.深拷贝与浅拷贝

9.箭头函数

10.reduce

css

1.css 新特性

2.BFC

3.说说你对盒子模型的理解?

4.块级元素和行内元素和行内块的区别

网络相关

1.什么是 HTTP? HTTP 和 HTTPS 的区别?

2.三次握手和四次挥手

3.Vue 项目中你是如何解决跨域的呢?


vue

1.vue2 和 vue3 的区别

1.更容易维护

更好的组合式api , vue2是选项式 更好的的ts支持

Vue 3引入了组合式API,使得代码组织更加灵活和可维护。Vue 2中使用的Options API虽然简单易用,但对于大型项目来说,组织和复用代码变得困难。组合式API允许我们根据逻辑相关性组织代码,提供了更好的封装性和代码复用性。

2.更快的速度

重写diff算法

3.更小的提交 按需引入

Vue 3在体积上进行了优化,使得打包后的文件更小。通过移除了一些不常用的特性、使用了更好的树摇(Tree Shaking)和代码压缩算法,Vue 3的体积相比Vue 2更小,加载速度更快

4.更优的数据响应式

proxy , 相较于Vue 2的Object.defineProperty,性能更好。

2.vue2 和 vue3的原理

1.vue2通过object.definedProperty()的get()和set()来做数据劫持、结合发布订阅者模式来实现,Object.definedProperty()会遍历每一个属性。

2.vue3通过proxy代理的方式实现。

3.proxy的优势:不需要像object,definedProperty()的那样遍历每一个属性,有一定的性能提升proxy,可以理解为在目标对象之前架设一层“拦藏”,外界对该对象的访问都必须通过这一层拦藏。这个拦藏可以对外界的访问进行过滤和改写。

4.当属性过多的时候利用Object.definedProperty(O要通过遍历的方式监听每一个属性。利用proxy则不需要遍历,会自动监听所有属性,有利于性能的提升

3.组合式api 和 选项式api

vue2 通过 data、methods、watch , 只能定义一个 是选项式API写法

组合式是 vue3 中的 所有逻辑在setup函数中 ,通过ref 定义

组合式的好处有:可复用,可维护

组合式api更加有利于: 逻辑复用, v2中使用mixins来做 , 但是mixins会产生命名冲突和数据来源不明确等问题

在项目开发中,有两个功能特别类似,如果单独实现,会有很多重复的代码

在v3中,我们利用组合式api的特点,他们抽象出来,进行封装,把得到函数写在一个单独的模块中,导出,以供复用

3. Proxy和object.defineproperty

Object.defineProperty只能遍历对象属性进行劫持

Proxy直接可以劫持整个对象,并返回一个新对象,我们可以只操作新的对象达到响应式目的

Proxy可以直接监听数组的变化(push、shift、splice)

Proxy有多达 13 种拦截方法,不限于apply、ownKeys、deleteProperty、has等等,这是Object.defineProperty不具备的

正因为defineProperty自身的缺陷,导致Vue2在实现响应式过程需要实现其他的方法辅助(如重写数组方法、增加额外set、delete方法)

Proxy 不兼容 IE,也没有 polyfill, defineProperty 能支持到 IE9

4..v-show 与 v-if 的区别

  • 控制手段不同
  • 编译过程不同
  • 编译条件不同

控制手段:v-show隐藏则是为该元素添加css--display:none,元素依旧还在。v-if显示隐藏是将元素整个添加或删除

编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于 css 切换

编译条件:v-if是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。只有渲染条件为假时,并不做操作,直到为真才渲染

  • v-show 由false变为true的时候不会触发组件的生命周期

  • v-iffalse变为true的时候,触发组件的beforeCreatecreatebeforeMountmounted钩子,由true变为false的时候触发组件的beforeDestorydestoryed方法

性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

5.计算属性和 watcher

答:   区别: watch 侦听某一数据的变化从而会触发函数,当数据为对象类型时,对象中的属性值变化时需要使用深度侦听 deep 属性,也可在页面第一次加载时使用立即侦听 immdiate 属性 computed 计算属性是触发函数内部任一依赖项的变化都会重新执行该函数,计算属性有缓存,多次重复使用计算属性时会从缓存中获取返回值,计算属性必须要有 return 关键词

vue 中的 watcher 有三类

  1. render watcher
  2. computed
  3. 自定义 watcher

computed 是一种特殊的 watcher

watch 和 computed 都是以函数为基础的,它们都是通过监听自身依赖的数据在变化时触发相关的函数去实现自身数据的变动。

不同点

运行时机不同

1.computed 是在 HTML,DOM 加载后马上执行的,如赋值;(属性将被混入到 Vue 实例)

2.watch 它用于观察 Vue 实例上的数据变动,一般情况下是依赖项的值变化之后再执行,当然可以设置立刻执行

6.虚拟DOM

虚拟dom相对于真实DOM而言的,在react,vue等技术出现之前,我们要改变页面展示的内容只能通过遍历查询 dom 树的方式找到需要修改的 dom 然后修改样式行为或者结构,来达到更新 ui 的目的。

这种方式相当消耗计算资源,因为每次查询 dom 几乎都需要遍历整颗 dom 树,如果建立一个与 dom 树对应的虚拟 dom 对象( js 对象),以对象嵌套的方式来表示 dom 树及其层级结构,那么每次 dom 的更改就变成了对 js 对象的属性的增删改查,这样一来查找 js 对象的属性变化要比查询 dom 树的性能开销小。

7.key的作用是什么?

页面上的标签都对应具体的虚拟 dom 对象(虚拟 dom 就是 js 对象), 循环中 ,如果没有唯一 key , 页面上删除一条标签, 由于并不知道删除的是那一条! 所以要把全部虚拟 dom 重新渲染, 如果知道 key 为对应标签被删除掉, 只需要把渲染的 dom 为对应标签去掉即可!key 是给每一个 vnode 的唯一 id,也是 diff 的一种优化策略,可以根据 key,更准确, 更快的找到对应的 vnode 节。

作用:更准确、更快速、提高效率

8.v-if 和 v-for 的优先级是什么?

v-if 不能和 v-for 一起使用的原因是 v-for 的优先级比 v-if 高,先循环再做分支判断,一起使用会造成性能浪费 解决方案有两种:

  1. 把 v-if 放在 v-for 的外层

  2. 把需要 v-for 的值先在计算属性中过滤一次

最终结论:

v2 中:v-for优先级比v-if

v3 中:v-if优先级比v-for

使用过程中,不要把它们同时用在一个元素上。

9.vuex

  •  vuex  是一个状态管理模式,  vuex 是为了解决整个网站状态数据共享问题的,虽然有父向子,子向父等数据传递,但在网站开发过程中一些无直接关联关系的组件也需要共享相同的数据时,就需要使用 vuex 了

vuex 中有六个主要的成员:

  • state 是用来存储数据的
  • mutations 是用来修改 state 中的数据的方法
  • actions 是用来处理一些异步操作数据的行为方法
  • getters 有点类似计算属性,是对 state 中的数据做了一些处理
  • modules 是用来对复杂业务分模块的,每个模块也可以有 state,mutaions,actions,getters
  • plugins 插件。比较常用的有用来持久化的 vuex-persistedstate

JS

1.原型 原型链

  • 原型是我们创建函数的时候,系统帮我们自动生成的一个对象。 主要作用是解决构造函数内部方法内存资源浪费问题。在开发中我们一般把实例对象一些通用的方法放入原型中,在 vue 里面有时候也会给 vue 的原型添加一些公共类方法来实现所有的组件中可以共享成员。像一些常见的$router和$store 都是挂载到 vue 的原型上的。
  • 原型链是 js 对象一种查找机制,遵循就近原则。当我们访问一个对象中的成员的时候,会优先访问自己的,如果自己没有就访问原型的,如果原型也没有就会访问原型的原型,直到原型链的终点 null. 如果还没有,此时属性就会获取 undefined,方法就会报错 xxx is not a function。一般原型链主要是用来实现面向对象继承的。

2.你对闭包的理解?

闭包是一个可以访问其他函数内部变量的函数,主要作用是解决变量污染问题,也可以用来延长局部变量的生命周期。闭包在 js 中使用比较多,几乎是无处不在的。一般大多数情况下,在回调函数中闭包用的是最多的。闭包可能会造成内存泄漏

3.内存泄漏

  • 内存泄漏一般是指变量的内存没有及时的回收,导致内存资源浪费。一般有三种情况出现内存泄露比较多。(1)常见的声明了一个全局变量,但是又没有用上,那么就有点浪费内存了,(2)定时器没清除 (3)循环引用:A 对象里面有一个属性指向 B 对象,B 对象有一个属性指向 A 对象。互相引用

  • 解决内存泄露:我们编译器有一个自动的内存清理。常见的主要是引用记数 和 标记清除。 谷歌浏览器主要是用标记清除,大概流程是给每一个变量添加一个标记,通过内部算法计算引用情况,当不使用的时候就会自动清除。如果遇到定时器的话,我一般会在页面关闭的时候手动清除。如果遇到循环引用,我一般会手动把变量赋值为 null 来清除

4.数组的常用方法有哪些?

数组的方法有很多,大概分为以下几类

  • 遍历方法
    • map: 遍历数组,并做一一映射,得到一个新数组
    • forEach:遍历数组,没有返回值
    • filter:筛选数组,保留符合要求的元素
    • some:判断数组是否有元素满足条件(相当于逻辑或:一真则真,全假为假)
    • every:判断数组是否所有满足都满足条件(相当于逻辑与:一假则假,全真为真)
    • find:查找满足条件的第一个元素
    • findIndex:查找满足条件的第一个元素的下标
    • reduce:给数组每一个元素执行一次回调,一般用于数组元素求和(也可以求最大值、最小值)
  • 增删改查方法
    • push() : 末尾新增元素,返回值是新数组长度
    • unshift():开头新增元素,返回值是新数组长度
    • pop() :末尾删除元素,返回值是删除的那个末尾元素
    • shift(): 开头删除元素,返回值是开头的那个末尾元素
    • splice() : 删除指定下标元素,第三个参数是一个剩余参数,可以在删除的元素后面插入元素
  • 其他方法
    • reverse:翻转数组,会修改数组自身
    • sort: 数组排序,会修改数组自身
    • json: 拼接数组元素,返回值是拼接之后的字符串
    • slice: 根据下标范围查询数组元素,返回值是查询后的新数组
    • indexOf: 查询元素下标,一般用于元素是值类型

5.Promise

Promise 是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现一定程度上解决了异步编程中回调地狱的问题,它比传统的解决方案回调函数和事件更合理和更强大。

所谓 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

三种状态

  • pending(进行中)
  • fulfilled(或者resolved, 已成功)
  • rejected(已失败)

promise 的状态改变是不可逆的

  1. pending → resolved
  2. pending → rejected
  3. 只有这两种 且一个 promise 对象只能改变一次无论成功还是失败,都会有个结果

promise 的常见 API

  1. 构造函数 Promise( excutor ){ }
  • executor 函数: 执行器 ( resolve, reject ) =>{ }
  • resolve 函数: 内部定义成功时我们调用的函数 value => { }
  • reject 函数: 内部定义失败时我们调用的函数 reason => { }
  • 说明: executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行
  1. Promise.prototype.then 方法: (onResolved, onRejected) => {}
  • onResolved 函数: 成功的回调函数 (value) => {}
  • onRejected 函数: 失败的回调函数 (reason) => {}
  • 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调

返回一个新的 promise 对象

  1. Promise.prototype.catch 方法: (onRejected) => {}
  • onRejected 函数: 失败的回调函数 (reason) => {}
  1. Promise.resolve 方法: (value) => {}
  • value: 成功的数据或 promise 对象
  • 说明: 返回一个成功/失败的 promise 对象
  1. Promise.reject 方法: (reason) => {}
  • reason: 失败的原因
  • 说明: 返回一个失败的 promise 对象
  1. Promise.all 方法: (promises) => {}
  • promises: 包含 n 个 promise 的数组
  • 说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败
  1. Promise.allSettled 方法: (promises) => {}
  • promises: 包含 n 个 promise 的数组
  • 说明: 返回一个新的 promise, 所有的 promise 都执行完成(不论成功还是失败)才成功
  1. Promise.race 方法: (promises) => {}
  • promises: 包含 n 个 promise 的数组
  • 说明: 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态

为啥可以链式调用?

链式调用就是用.语法持续去调用示例方法,例如: Promise.then().then().catch().finally().catch().then() 之所以可以链式调用的原因是这些示例方法的返回值仍是一个promise对象,所以可以持续的链式调用。值得注意的是finally()的返回值仍是一个Promise对象,它也可以继续链式调用

6.什么是防抖和节流?有什么区别?如何实现?

防抖和节流是性能优化手段

什么是防抖? 防抖:单位时间内,频繁触发事件,只执行最后一次。 防抖的主要应用场景:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测

什么是节流? 节流:单位时间内,频繁触发事件,只执行一次。 节流的主要应用场景:

  • 高频事件 例如 resize 事件、scroll 事件
  • 手机号、邮箱验证输入检测

相同点:

  • 都可以通过使用 setTimeout 来实现
  • 降低回调执行频率。节省计算资源

不同点:

  • 函数防抖,在一段连续操作结束后,处理回调,利用 clearTimeout 和 setTimeout 来实现。函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能
  • 函数防抖关注一定时间连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行一次

7.谈谈 this 对象的理解

在绝大多数情况下,函数的调用方式决定了 this 对象的指向

this 关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象

根据不同的使用场合,this 对象有不同的指向,主要分为下面几种情况

  • 默认绑定

    • 全局环境中定义的函数,函数内部的 this 指向 window 对象
  • 隐式绑定

    • 函数还可以作为某个对象的方法调用,这时 this 就指这个上级对象

    • new 绑定

      • 通过构建函数 new 关键字生成一个实例对象,此时 this 指向这个实例对象
    • 显示绑定

      • apply()、call()、bind()是函数的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时 this 指的就是这第一个参数
    • 箭头函数

      • 箭头函数没有自己的 this 值,箭头函数中所使用的 this 来自于函数作用域链

      • 箭头函数没有自己的 this 值,箭头函数中所使用的 this 都是来自函数作用域链,它的取值遵循普通普通变量一样的规则,在函数作用域链中一层一层往上找。

8.深拷贝与浅拷贝

浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址。实际开发常用的方法有:object.assgin,扩展运算符(...) ,Array.prototype.slice()Array.prototype.concat()等等。

深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址。开发中常用的方法有: (1) loadsh 中的_.cloneDeep()方法 (2)JSON.stringify() JSON.parse() 。缺点是会忽略undefinedsymbol函数

9.箭头函数

箭头函数是ES6提出了的新语法。它最大的意义是解放了Function的功能。 在js中,Function是一等公民,它不但承担了本质的函数的功能,还可以做构造函数来使用,现在有了箭头函数,其实大大简化了Function的使用频率。

与普通函数相比,他:

  1. 写法更加简洁,可以根据具体情况省略 小括号,return 等。这一点在高阶函数的使用中特别方便。例如,数组的map, forEach等.
  2. 箭头函数内部没有自己的 this ,它的this就是外层作用域的 this 。它不能通过call,apply,bind来修改。
  3. 箭头函数内部没有arguments对象。但是,es6配套提供了剩余参数,可以用来替代argument.
  4. 不能当前构造器来使用。

我现在在写v3的代码,所以使用箭头函数还是比较多的。

10.reduce

  • reduce 作用:给每一个元素执行一次回调函数,并且返回最终的结果

  • reduce 参数有两个:第一个是回调函数,第二个是初始值。 一般初始值都会设置为 0,目的是避免空数组报错

    • 回调函数内部常用的形参有三个,依次是累加值、当前元素、当前下标
    • 回调函数内部的 return 返回值就是下一次回调的累加值
  • reduce 方法的返回值:就是执行完遍历之后,最终的累加值

css

1.css 新特性

C3 的新特性有很多,常见的如下:

  • border-radius:圆角边框
  • box-shadow:盒子阴影
  • background-size:背景图片大小
  • transition:过渡
  • transform:转换(位移 旋转 缩放)
  • animation:动画
  • linear-gradient:线性渐变
  • box-sizing:css3 盒子模型

2.BFC

BFC 的中文意思是块级格式化上下文,是用于布局块级盒子的独立渲染区域,一个创建了新的 BFC 的盒子是独立布局的,盒子内元素的布局 不会影响盒子外面的元素。

简单来说就是 BFC 就是 css 的一个布局概念,是一个独立的区域(容器)

满足下列条件之一就可以触发 BFC:

  • HTML 根元素
  • position 为 absolute 或 fixed
  • float 属性不为 none(常用)
  • overflow 不为 visible(常用)
  • display 为 inline-block, table-cell, table-caption, flex

可以解决什么问题:margin 重叠,清除浮动,自适应布局.

参考文章:https://juejin.cn/post/6950082193632788493

3.说说你对盒子模型的理解?

  • 盒子模型组成有 4 部分,分别为:内容 内边距 外边距(一般不计入盒子实际宽度) 边框

  • 盒子模型有 2 种:标准盒子模型与怪异盒子模型

  • 标准盒子模型=content(内容)+border(边框)+padding(内边距)

  • 怪异盒子模型=content(内容)(已经包含了 padding 和 border)

  • css3 种可以通过设置 box-sizing 属性来完成标准或许怪异盒子模型之间的切换,怪异盒子模型:box-sizing: border-box;标准盒子模型:box-sizing:content-box

4.块级元素和行内元素和行内块的区别

通过设置 display 属性可以改变元素的类型。

1.块级元素(block)的特点

  1. 占据一行
  2. 高度,行高以及外边距和内边距都可设置
  3. 宽度默认为是它的容器的100%,但可以设定一个宽度
  4. 它可以容纳内联元素和其他块元素

常见的有:div, h1, p

2.inline元素的特点

  1. 和其他元素共享一行上
  2. 高,行高及外边距和内边距不可改变
  3. 宽度就是它的文字或图片的宽度,不可改变

常见的有:i span a

3.inline-block元素的特点

  1. 和其他元素都在一行上
  2. 行高及外边距和内边距都可改变;

常见的有:buttton img, input

网络相关

1.什么是 HTTP? HTTP 和 HTTPS 的区别?

http 是无状态的超文本传输协议,连接简单,信息是明文传输,端口为 80。

https 协议是由 http+ss 协议构建的可进行加密传输、身份认证的具有安全性网络协议,端口是 443

优缺点

https 有加密认证相对于 http 安全一些

https 因为需要进行加密解密等过程,因此速度会更慢;

2.三次握手和四次挥手

三次握手是为了确认双方的接收与发送能力是否正常。

1、第一次握手:客户端给服务器发送一个 SYN 报文。

2、第二次握手:服务器收到 SYN 报文之后,会应答一个 SYN+ACK 报文。

3、第三次握手:客户端收到 SYN+ACK 报文之后,会回应一个 ACK 报文。 服务器收到 ACK 报文之后,三次握手建立完成。

当客户端和服务端通过三次握手建立 TCP 连接进行可靠数据传输后,当数据传送完毕,肯定是要断开 TCP 连接,所以就有了四次挥手。

四次挥手是为了断开连接后「资源」正常释放,双方都可以主动断开连接。

1、第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。

2、第二次握手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 + 1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。

3、第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。

4、第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 + 1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态

5、服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态

扩展

为什么只有三次握手才能确认双方的接受与发送能力是否正常,而两次却不可以:

第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。

第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。

第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。

因此,需要三次握手才能确认双方的接收与发送能力是否正常。

3.Vue 项目中你是如何解决跨域的呢?

跨域,是指在浏览器中a页面去请求了b页面的资源,更具体的来说是指a页面和b页面的:协议,主机,端口这三个有一个不同,就是跨域请求。

这种情况在网页开发中是非常常见的。但是,对于特殊的ajax请求,出于安全性的考虑,浏览器对跨域的ajax请求做了限制。

跨域的请求不一定报错(例如:script, css等等), ajax请求才会报错。

常见的解决方案有 3 种:

  1. JSONP: 利用 script 标签,不受跨域限制的特点,缺点是只能支持 get 请求
  2. CORS: 后端设置响应头 Access-Control-Allow-Origin。
  3. 代理。在开发阶段,我们可以在 devServer中配置 proxy 项。在项目开发完成上线之后,一般使用 nginx 配置代理转发。

你可能感兴趣的:(前端)