我是靠谱客的博主 仁爱橘子,这篇文章主要介绍前端面试点集合【持续更新】ReactVue前端,现在分享给大家,希望可以做个参考。

在这里插入图片描述

面试题

复制代码
1
2
3
4
5
6
7
8
9
10
//考察:原型,迭代器,可迭代协议 //让下面的代码成立 var [a,b] = {a:1,b:2} //在执行这个代码前,执行以下代码 //把对象变成可迭代对象,因为数组就是可迭代对象 Object.prototype[Symbo.iterator] = function(){ return Object.values(this) }

React

1.使用 useState 多次渲染,如何优化

2.react的hook组件有哪些?

3.类组件和函数组件有什么不同?

4.react的生命周期

5.useCallBack和useMemo优化在哪里

6.函数渲染安全还是使用类的this渲染安装

7.react源码解刨

Vue

1.vue 响应式原理如何实现?

vue2 通过object.defineProperty(发布订阅模式+数据劫持)
vue3 通过proxy

Observer负责将数据转换成getter/setter形式;
Dep负责管理数据的依赖列表;是一个发布订阅模式,上游对接Observer,下游对接Watcher
Watcher是实际上的数据依赖,负责将数据的变化转发到外界(渲染、回调);
首先将data传入Observer转成getter/setter形式;当Watcher实例读取数据时,会触发getter,被收集到Dep仓库中;当数据更新时,触发setter,通知Dep仓库中的所有Watcher实例更新,Watcher实例负责通知外界
https://juejin.cn/post/6844903597986037768

2.vue中如何让没有响应式数据变成响应式?

3.proxy和object.defineProperty 之间的优缺点

vue2
vue一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数。

render参数里有一个函数叫h,h就是对单文件组件进行虚拟DOM的创建,然后通过render进行解析
template最终还是通过render的方式再次进行编译

相同之处:
1.render和template都是创建html
不相同之处:
1.template适合简单逻辑,render适合复杂逻辑
2.template理解容易,但灵活度不够高。自定义render灵活性高,但是对使用者要求高
3.render性能比template高
4.render使用js方式做渲染,template使用html方式做渲染
5.render函数优先级大于template

4.1 什么时候用render函数?

组件复杂时可以用render,简单直接使用template
创建一个各种类型的按钮为例子:
template

复制代码
1
2
3
4
5
6
<template> <div class="btn btn-success" v-if="type === 'success'">{{ text }}</div> <div class="btn btn-danger" v-else-if="type === 'danger'">{{ text }}</div> <div class="btn btn-warning" v-else-if="type === 'warning'">{{ text }}</div> </template>

render

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<script> Vue.component("G-Btn", { # 获取父级传来的值 props: { type: { type: String, default: 'default' }, text: { type: String, default: '按钮' } }, # 计算属性 computed: { tag() { switch(this.type) { case'success': return 1; case'danger': return 2; case'warning': return 3; default: return 1; } } }, # 创建html render(createElement) { return createElement('div', { class: { btn: true, 'btn-success': this.type==='success', 'btn-danger': this.type==='danger', 'btn-warning': this.type==='warning' }, on: { click: this.handleClick } }, this.$slots.default ); }, methods: { handleClick() { console.log('点击成功'); } } }) let appData= new Vue({ el: "#app" }) </script>

5.template渲染过程

Vue推荐在绝大多数情况下使用template来创建你的HTML。但是模版毕竟是模版,不是真实的dom节点。从模版到真实dom节点还需要经过一些步骤:
1.把模版编译为render函数
2.实例进行挂载,根据跟节点render函数的调用,递归的生成虚拟dom
3.通过diff算法对比虚拟dom,渲染到真实dom(类似于react的虚拟DOM渲染过程)
4.组件内部data发生变化,组件和子组件引用data作为props重新调用render函数,生成虚拟DOM,返回到步骤3

6.在 Vue 中为什么不推荐用 index 做 key

1.用 index 作为 key 时,在对数据进行,逆序添加,逆序删除等破坏顺序的操作时,会产生没必要的真实 DOM更新,从而导致效率低

2.用 index 作为 key 时,如果结构中包含输入类的 DOM,会产生错误的 DOM 更新

3.在开发中最好每条数据使用唯一标识固定的数据作为 key,比如后台返回的 ID,手机号,身份证号等唯一值
4.如果不存在对数据逆序添加,逆序删除等破坏顺序的操作时,仅用于渲染展示用时,使用 index 作为 key 也是可以的(但是还是不建议使用,养成良好开发习惯)。

作者:政采云前端团队
链接:https://juejin.cn/post/7026119446162997261
来源:稀土掘金

7.mutation为什么是同步,action为什么是异步的?

Vuex

state:存储公共数据(相当于组件中的data)
mutations:修改数据方法的集合,必须是同步
getters:类似于computed计算属性(利用现有的状态进项计算得到新的数据—派生)
actions:异步操作
modules:模块化拆分
2

8.封装vue3组件的注意问题

前端

1.单向数据流和双向数据流的区别。

2.js中的this指针指向问题

https://zhuanlan.zhihu.com/p/159322871
箭头函数、call、apply、bind等手法改变this指向

3.call apply修改this指向

4.闭包的坏处,如何使用闭包?

5.原型链

6.作用域和作用域链

作用域:程序中定义变量的区域,它决定了当前执行代码对变量的访问权限
作用域链:可执行代码内部访问变量时,会先查找当前作用域下有无该变量,有则立即返回,没有则会去父级作用域中查找,一直找到全局作用域。这种作用域的嵌套机制称为作用域链

7.堆和栈

在这里插入图片描述

基本数据类型:直接存储在内存中,占据空间小,大小固定,属于被频繁使用的数据。
引用数据类型:同时存储在内存与内存中,占据空间大,大小不固定。引用数据类型将指针存在中,将值存在中。当我们把对象值赋值给另外一个变量时,复制的是对象的指针,指向同一块内存地址。

堆:存储引用类型值的空间
栈:存储基本类型和指定代码的环境

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
let a={}, b = "0", c = 0 a[b] = "1111" a[c] = "2222" console.log(a[b]) 结果为:2222 解刨: a["0"] = "1111" a[0] = "2222" 结论:对象属性不能重复,数字和字符串属性名相同,堆就不重要了
复制代码
1
2
3
4
5
6
7
8
9
10
#ES6新增:Symbol 表示独一无二的值 let a={}, b = Symbol("1") c = Symbol("1") a[b] = "1111" a[c] = "2222" console.log(a[b]) 结果为:1111 结论:对象属性名只能是字符串是不严谨的,这里看出还有Symbol的值

8.对象和数组的区别?

区别一:
数组表示有序数据的集合
对象表示无序数据的集合
如果数据对顺序很重要,就用数组,否则用对象
区别二:
数组的数据没有名称,对象的数据有名称

9.闭包

9.1

复制代码
1
2
3
4
5
6
7
8
9
var test = (function(i){ return function(){ alert(i *=2) } })(2) test(5) 结果为:"4" 因为alert会把值转为字符串

匿名函数可以访问外部 i 的值,因为匿名函数可以创建自己的执行上下文,会创建自己相应的作用域链和变量对象

9.1 执行上下文

每当运行代码时,代码就会执行上下文(执行环境)

执行上下文分为两个阶段:
创建阶段:作用域链(当前变量对象+所有父级变量对象)变量对象(参数,变量,函数声明)this
执行阶段:变量赋值函数引用

执行上下文分为:全局环境函数环境Eval环境

9.2 作用域链

9.2.1 作用域链例子一

作用域链是通过闭包实现

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
//books执行上下文 fucntion books(){ var book = "书包里的书本" //匿名函数执行上下文 return function(){ console.log(book) } } var bag = books() //全局执行上下文 bag();

说明:
可执行代码内部访问变量时,会查找当前作用域是否有book变量,有就会立马返回输出,没有就会向父级作用域中查找,知道找到全局作用域

匿名函数执行上下文:{作用域链:{匿名函数变量对象+books变量对象+books变量对象+全局变量对象},{变量对象}}
books执行上下文:{作用域链:{books变量对象+全局变量对象},{变量对象:book}}
全局执行上下文:{作用域链:{全局变量对象},{变量对象:books,bag}}

作用域链的解释:
作用域链都是一层链接一层,每新建一层都会包含之前新建的一层变量对象,最顶层的链层是最优先的。这里的三层中匿名函数就是顶层链,所以是最优先执行
在这里插入图片描述

9.2.2 作用域链例子二
复制代码
1
2
3
4
5
6
7
8
9
for(var i = 0;i<5;i++){ setTimeout(function(){ console.log(i++) },4000) } console.log(i) 运行结果: 5,5,6,7,8,9

先运行主栈,然后再运行宏任务(setTimeout中的方法)

9.2.3 作用域链例子三
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
for(var i = 0;i<5;i++){ //立即执行 (function(x){ setTimeout(function(){ console.log(i++) },4000) })(i) } console.log(i) 运行结果: 501234

先运行主栈,然后再运行宏任务(setTimeout中的方法)

10.null和undefined的区别

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/** * null 表示无对象 * undefined 表示没有值 */ /** * var a; * a没有赋值所以是undefined */ /** * document.getElementById("xxxxx") 等到为null * 应该获取到一个dom对象,但是xxxxx不存在,所有是no object.所以是null */

什么时候用null?
你要表达的数值是一个对象,但是现在没有对象,就可以用null

什么时候用undefined?
当前值可以表示任何东西,但是他没有值,就可以用undefined

11.同步和异步

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
async function async1(){ console.log("async1 start") await async2() console.log("async1 end") } async function async2(){ console.log("async2") } console.log("script start") setTimeout(function(){ console.log("setTimeout") },0) async1(); new Promise(functtion(resolve){ console.log("promise1") resolve(); }).then(function(){ console.log("promise2") }) console.log("script end") 运行结果 script start async1 start async2 promise1 script end async1 end promise2 setTimeout

浏览器是多线程
JS是单线程 => 浏览器只给其中一个线程来渲染

分析:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
创建函数 async1 创建函数 async2 ="script start" 设置定时器(异步) (宏任务A) 函数执行 ="async1 start" await async2() 执行async2,等待返回结果(微任务B) ="async2" new Promise会立即执行函数(new的时候是同步) ="promise1" resolve()/reject() (微任务C) ="script end"

主栈第一阶段完成

异步队列分为:微任务队列宏任务队列
宏任务执行完,才到微任务

复制代码
1
2
3
4
5
6
7
微任务 宏任务 B:async2的结果,有结果 A:setTimeout() xxms执行 再执行下面代码 C:resolve/reject 执行的时候把then/catch 中的方法执行

12.宏任务和微任务

异步队列分为:微任务队列宏任务队列
宏任务执行完,才到微任务
宏任务队列有:
1.setTimeout()和setInterval()

微任务队列有:
1.新程序或子程序被直接执行
2.事件的回调函数
3.Promise .then() .catch() .finally()
4.MutationObserver

遇到new promise直接执行,因为构造方法会直接执行

宏任务和微任务的运行机制
在这里插入图片描述
参考:https://blog.csdn.net/qq_44624386/article/details/107344664

13.defer和async的区别

因为js是单线程执行,所以async和defer可以解决网络的阻塞的问题,但是两则都只适用于外部脚本
async:异步处理函数
浏览器会立即进行下载,同时继续加载页面。但是async下的脚本具体什么时候执行就说不一定了
在这里插入图片描述
defer:推迟执行函数
不管脚本是否加载完,都会等到浏览器解析完html以后再执行脚本,defer比较适合与DOM有关联的脚本
在这里插入图片描述

14.Promise

Promise优点:
1.Promise能解决异步处理的问题
2.解决回调地狱
3.能对错误代码进行捕获

Promise缺点:
1.无法取消Promise,一旦新建他会立即执行,中途无法取消。
2.如果不设置回调,promise内部抛出的错误,外部是不会获取到。
3.如果处于pending等待状态时,无法得知目前进展到哪一个阶段。

15.typeof和instanceof的区别

typeof:检测数据类型输出类型名称
简单数据类型
Undefined,Null,Boolean,Number和String
复杂数据类型
Object

instanceof:检测对象之间的关联性。(常用在检测该属性和函数是否在原型链中)

16.函数柯里化

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/** * 什么是柯里化 * 把接收多个参数的函数编程一个接收一个参数的函数,并返回接收多个参数的时,返回新函数 * @returns {inner} */ //基本柯里化 // function add(){ // //把保存参数的arguments赋值给args变量 // let args = arguments // let inner = function(){ // args.push(...arguments) // } // //返回inner内部函数实现基本的柯里化 // return inner // } // // console.log(add(1)); // function add(){ // //Array.prototype.slice.call是把调用方法的参数截取出来 // let args = Array.prototype.slice.call(arguments) // let inner = function(){ // args.push(...arguments) // let sum = args.reduce((prev,cur)=>{ // return prev+cur; // }) // return sum; // } // //返回inner内部函数实现基本的柯里化 // return inner // } // // console.log(add(1)(2)); function add() { // 将传入的不定参数转为数组对象 let args = Array.prototype.slice.call(arguments); // 递归:内部函数里面进行自己调用自己 // 当 add 函数不断调用时,把第 N+1 个括号的参数加入到第 N 个括号的参数里面 let inner = function() { args.push(...arguments); return inner; } inner.toString = function() { // args 里的值不断累加 return args.reduce(function(prev, cur) { return prev + cur; }); }; return inner; } // 测试一下 let result = add(1)(2)(3)(4); console.log(result.toString()); //结果为:10

17.虚拟DOM

17.1 什么是虚拟DOM?

虚拟DOM就是一个普通的js对象,用于描述视图的界面结构。
在vue中,每个组件都有一个render函数,每个render函数都会返回一个虚拟DOM树,这也就意味着每个组件都对应一棵虚拟DOM树

17.2 为什么需要虚拟DOM?

在渲染时,直接使用真实DOM,因为真实DOM的创建,更新,插入等操作会带来大量的性能损耗,降低渲染效率。所以需要减少对真实DOM的操作

17.3 虚拟DOM是如何转换为真实DOM的?

在一个组件实例首次被渲染时,它先生成虚拟DOM树,然后根据虚拟DOM树创建真实DOM,并把真实DOM(挂载)到页面中适合的位置,此时,每个虚拟DOM便会对应一个真实的DOM

17.4 模板和虚拟dom的关系?

vue框架中有一个compile模块,它主要负责将模版转换为render函数,而render函数调用后得到虚拟DOM。

18.require和import的区别

require/exports

复制代码
1
2
3
4
5
6
//module.js文件导出 module.exports = {counts, sayHello}; //module.js文件引入 const { xxx } = require('./module.js');

import/exports

复制代码
1
2
3
4
5
6
//module.js文件导出 exports = {counts, sayHello}; //module.js文件引入 import { xxx } from'./module.js';
  1. import: 是编译时执行,理解为异步加载
  2. require: 是运行时执行,理解为同步加载
  3. 导入require 导出 exports/module.exports 是 CommonJS 的标准,通常适用范围如 Node.js
  4. import/export 是 ES6 的标准,通常适用范围如 React,Vue
  5. require性能比import稍低
    因为 require 是在运行时才引入模块并且还赋值给某个变量,而 import 只需要依据 import 中的接口在编译时引入指定模块所以性能稍高

19.计算属性和methods方法的区别

计算属性 只有当数值更改后才能被触发。如果依赖的值,没有发生改变,使用的就是缓存中的属性

methods方法 无论什么时候,只要你触发了方法,数值都会被重新计算。不存在缓存机制。

20.性能优化

复制代码
1
2
3
4
5
1.1 while循环快还是for循环快? 关于循环 1.2 0是不是比Math.floor性能好? 关于取值 1.3 if else与三元运算符哪个快? 关于逻辑运算 以上都不算不上性能优化,都是执行效率

20.1 输入url与浏览器渲染过程
在这里插入图片描述
20.2 什么是性能?什么是执行效率
操作虚拟dom就是性能问题
vue是数据驱动 => 虚拟dom 操作dom(影响到浏览器速度)

20.3 性能分析
页面加载性能(加载时间,用户体验)
动画与操作性能(是否流畅无卡顿)
内存占用(占用过大,浏览器崩掉等)
电量消耗(游戏方面,可不考虑)

20.4 性能优化有哪些?
a.加载
1.减少http请求 css和图片都能做的事,最好用css,因为图片也是一个请求
2.缩小文件大小(资源压缩)
3.cdn库
4.懒加载
5.服务端渲染,预渲染

b.动画与操作性能
1.减少dom操作 => 文档碎片
2. 避免回流

21.TCP协议三次握手和四次挥手

面试题视频链接
https://www.bilibili.com/video/BV1iE411q7Qd?spm_id_from=333.337.search-card.all.click&vd_source=65e0538de0332111f890a0bd755ca4e7
前端面试题:
https://juejin.cn/post/7049164339630047245

TCP和UDP的区别

22.防抖和节流的应用场景

防抖
防抖,顾名思义,防止抖动。用于将用户的操作行为触发转换为程序行为触发,防止用户操作的结果抖动。一段时间内,事件在我们规定的间隔 n 秒内多次执行,回调只会执行一次。

特点:等待某种操作停止后,加以间隔进行操作

1.持续触发不执行
2.不触发的一段时间之后再执行

节流
节流,顾名思义,控制流量。用于用户在与页面交互时控制事件发生的频率,一般场景是单位的时间或其它间隔内定时执行操作。一段时间内,事件在每次到达我们规定的间隔 n 秒时触发一次。

特点:每等待某种间隔后,进行操作

1.持续触发并不会执行多次
2.到一定时间 / 其它间隔 ( 如滑动的高度 )再去执行

作者:政采云前端团队
链接:https://juejin.cn/post/7018296556323340324

23.Typescript中的extends关键字理解

1.继承/拓展
2.泛型约束
3.条件类型与高阶类型
https://blog.csdn.net/qq_34998786/article/details/120300361

24.跨域是怎么引起?

跨域就是同源策略引起

同源策略: 同端口 同域名 同协议(如果这三个里有一个不同,就叫不同源)
跨域: 违反同源策略

常见的跨域方式有哪些?

  1. jsonp
    html中的script src属性获取其他源的数据

  2. .cors 跨域资源共享 支持所有的主流浏览器
    XMLHttpRequest 发送请求的时候,如果不同源
    后台处理: 请求头部设置 Access-control-allow-origin

  3. h5 window.postMessage跨域
    window.postMessage(“字符串”,“*”)

注意:vue的跨域: proxy代理跨域(本质上就是cors跨域)
vue.config.js里进行配置

25.AMD与CMD区别

https://juejin.cn/post/6844903541853650951#heading-2

26.资源提示符

资源提示符跟浏览器渲染密切相关

  1. async //异步加载
  2. defer //延迟加载
  3. preload //加载优先级大于prefetch
  4. prefetch //加载优先级较低,浏览器空闲时才加载
    preload,prefetch加载的资源重复时,浏览器不会进行重复请求

27.脚本加载失败该怎么办?

1.什么时候重试?
使用window.addEventListener捕获脚本报错的时候重试
2.如何重试?
使用document.write阻塞浏览器进行重试

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!DOCTYPE html> <html lang="en"> <head> <script> //需要替换的域名 const domains = [ "unpkg.com", "www.bootcdn.cn", "www.staticfile.org", "cdn.baomitu.com", "cdn.bytedance.com", ] //重试次数 const maxRetry = 3; const retryInfo = {} window.addEventListener('error',(e)=>{ //通过标签,判断是脚本爆出的错误 const tag = e.target //什么时候触发脚本加载失败? if(tag.tagName === "SCRIPT" && !(e instanceof ErrorEvent)){ let url = new URL(tag.src) if(!retryInfo[url.pathname]){ retryInfo[url.pathname]={ time:0, nextIndex:0, } } const info = retryInfo[url.pathname] if(maxRetry>=info.time){ url.host = domains[info.nextIndex] //阻塞页面后续的加载 document.write(`<script src="${url.toString()}"></script>`) info.time++; info.nextIndex = (info.nextIndex+1)%domains.length } } },true) </script> </head> <body> <script src="https://333.com/vue"></script> <script src="https://4444.com/pinia"></script> </body> </html>

28.计算属性(computed)和监听器(watch)的区别

  1. 计算属性的应用场景是计算的内容需要依赖多个属性的情况
    侦听器的应用场景是计算的内容依赖一个属性的情况
  2. 计算属性缓存结果时每次都会重新创建变量
    而侦听器是直接计算,不会创建变量保存结果
  3. computed的结果是通过return返回的,而watch不需要return
  4. watch中的参数可以得到侦听属性改变的最新结果,而computed函数没有这种参数。

29.外包线上面试前端

vue

  1. v-model实现原理

  2. MVVM简要
    https://zhuanlan.zhihu.com/p/59467370

  3. 父子组件通信方式有哪些?

  4. 父子组件生命周期执行顺序

  5. computed和watched的使用场景和区别

  6. 模板数据不同步,该如何同步?

  7. vue2和vue3使用什么实现双向绑定?实现原理是什么?

  8. keep-alive使用场景有哪些?

css
10. em rem px rpx的区别

  1. css选择器优先级

  2. 什么是盒子模型?

  3. display: none与visibility: hidden的区别

javascript

  1. 多个对象合并 多个数组合并方式有哪些,说出es5和es6

  2. JavaScript 数据类型和数据结构
    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Data_structures

  3. sessionStorage,localstorage,cookie的区别

  4. 防抖和节流的区别和概念

最后

以上就是仁爱橘子最近收集整理的关于前端面试点集合【持续更新】ReactVue前端的全部内容,更多相关前端面试点集合【持续更新】ReactVue前端内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(128)

评论列表共有 0 条评论

立即
投稿
返回
顶部