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

在这里插入图片描述

面试题

//考察:原型,迭代器,可迭代协议
//让下面的代码成立
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

<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

<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.堆和栈

在这里插入图片描述

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

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

let a={},
b = "0",
c = 0
a[b] = "1111"
a[c] = "2222"
console.log(a[b])
结果为:2222
解刨:
a["0"] = "1111"
a[0]   = "2222"
结论:对象属性不能重复,数字和字符串属性名相同,堆就不重要了
#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

var test = (function(i){
	return function(){
		alert(i *=2)
	}
})(2)
test(5)
结果为:"4"
因为alert会把值转为字符串

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

9.1 执行上下文

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

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

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

9.2 作用域链

9.2.1 作用域链例子一

作用域链是通过闭包实现

//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 作用域链例子二
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 作用域链例子三
for(var i = 0;i<5;i++){
	//立即执行
	(function(x){
		setTimeout(function(){
		console.log(i++)
	},4000)
	})(i)
}
console.log(i)
运行结果:
5,0,1,2,3,4

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

10.null和undefined的区别

  /**
   * null 表示无对象
   * undefined 表示没有值
   */

  /**
   * var a;
   * a没有赋值所以是undefined
   */

  /**
   * document.getElementById("xxxxx")  等到为null
   * 应该获取到一个dom对象,但是xxxxx不存在,所有是no object.所以是null
   */

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

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

11.同步和异步

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是单线程 => 浏览器只给其中一个线程来渲染

分析:

创建函数 async1
创建函数 async2
=》"script start"
设置定时器(异步) (宏任务A)
函数执行
	=》"async1 start"
	await async2() 执行async2,等待返回结果(微任务B)
		=》"async2"
new Promise会立即执行函数(new的时候是同步)
	=》"promise1"
		resolve()/reject() (微任务C)
=》"script end"

主栈第一阶段完成

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

微任务						宏任务
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.函数柯里化

/**
   * 什么是柯里化
   * 把接收多个参数的函数编程一个接收一个参数的函数,并返回接收多个参数的时,返回新函数
   * @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

//module.js文件导出
module.exports = {counts, sayHello};

//module.js文件引入
const { xxx } = require('./module.js');

import/exports

//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.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阻塞浏览器进行重试

<!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前端内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部