前端面试题(二)

1. 说说React生命周期中有哪些坑?如何避免?

避免生命周期中的坑需要做好两件事:
不在恰当的时候调用了不该调用的代码;
在需要调用时,不要忘了调用。

那么主要有这么 7 种情况容易造成生命周期的坑。

getDerivedStateFromProps 容易编写反模式代码,使受控组件与非受控组件区分模糊。

componentWillMount 在 React 中已被标记弃用,不推荐使用,主要原因是新的异步渲染架构会导致它被多次调用。所以网络请求及事件绑定代码应移至 componentDidMount 中。

componentWillReceiveProps 同样被标记弃用,被 getDerivedStateFromProps 所取代,主要原因是性能问题。

shouldComponentUpdate 通过返回 true 或者 false 来确定是否需要触发新的渲染。主要用于性能优化。

componentWillUpdate 同样是由于新的异步渲染机制,而被标记废弃,不推荐使用,原先的逻辑可结合 getSnapshotBeforeUpdate 与 componentDidUpdate 改造使用。

如果在 componentWillUnmount 函数中忘记解除事件绑定,取消定时器等清理操作,容易引发 bug。

如果没有添加错误边界处理,当渲染发生异常时,用户将会看到一个无法操作的白屏,所以一定要添加。

2. 说说Real diff算法是怎么运作的?

跟vue一致,React通过引入Virtual DOM的概念,极大地避免无效的Dom`操作,使我们的页面的构建效率提到了极大的提升

而diff算法就是更高效地通过对比新旧Virtual DOM来找出真正的Dom变化之处

原理

react中diff算法主要遵循三个层级的策略:

  • tree层级
  • conponent 层级
  • element 层级

tree层级

DOM节点跨层级的操作不做优化,只会对相同层级的节点进行比较

只有删除、创建操作,没有移动操作

conponent层级

如果是同一个类的组件,则会继续往下diff运算,如果不是一个类的组件,那么直接删除这个组件下的所有子节点,创建新的

element层级

对于比较同一层级的节点们,每个节点在对应的层级用唯一的key作为标识

提供了 3 种节点操作,分别为 INSERT_MARKUP(插入)、MOVE_EXISTING (移动)和REMOVE_NODE (删除)

3. 调和阶段setState干了什么?

(1)代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。
(2)经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面;
(3)在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;
(4)在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

4. 说说redux的实现原理是什么,写出核心代码?

(1)将应用的状态统一放到state中,由store来管理state。
(2)reducer的作用是返回一个新的state去更新store中对用的state。
(3)按redux的原则,UI层每一次状态的改变都应通过action去触发,action传入对应的reducer 中,reducer返回一个新的state更新store中存放的state,这样就完成了一次状态的更新
(4)subscribe是为store订阅监听函数,这些订阅后的监听函数是在每一次dipatch发起后依次执行
(5)可以添加中间件对提交的dispatch进行重写

5. React合成事件的原理?

1、React合成事件是什么?
React 合成事件(SyntheticEvent)是 React 模拟原生 DOM 事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器。它根据 W3C 规范 来定义合成事件,兼容所有浏览器,拥有与浏览器原生事件相同的接口。

2、为什么会有合成事件?
将事件绑定在document - v16/容器元素 - v17统一管理,防止很多事件直接绑定在原生的dom元素上。造成一些不可控的情况
React 想实现一个全浏览器的框架, 为了实现这种目标就需要提供全浏览器一致性的事件系统,以此抹平不同浏览器的差异。

3、原理?
合成事件的监听器是统一注册在document上的,且仅有冒泡阶段。所以原生事件的监听器响应总是比合成事件的监听器早
阻止原生事件的冒泡后,会阻止合成事件的监听器执行

6. React组件之间如何通信?

父传子:⽗组件可以通过向⼦组件传 props 的⽅式来实现
子传父:可以采用props+回调的方式
兄弟组件通信:可以通过兄弟节点的共同父节点,由父节点转发信息,实现兄弟间通信
跨层级通信:context状态树
发布者订阅者模式:发布者发布事件,订阅者监听到事件后做出反应,可以通过引⼊ event 模块进⾏
全局状态管理工具:可以借助 Redux 或 Mobx以及react-redux 等全局状态管理⼯具进⾏通信,它们会维护⼀个全局状态中⼼(Store),并可以根据不同的事件产⽣新的状态
hooks中帮我们封装好的:useContext和useReducer

7. 为什么React元素有一个$$typeof属性?

详情: https://blog.csdn.net/weixin_34418883/article/details/88217527

8. 说说Connect组件的原理是什么?

首先connect之所以会成功,是因为Provider组件:

在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
接收Redux的store作为props,通过context对象传递给子孙组件上的connect
那connect做了些什么呢?

它真正连接 Redux 和 React,它包在我们的容器组件的外一层,它接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。

9. 说说你对fiber架构的理解?解决了什么问题?

React Fiber 是 Facebook 花费两年余时间对 React 做出的一个重大改变与优化,是对 React 核心算法的一次重新实现。

在react中,主要做了以下的操作:

为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务

增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行

dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行

从架构角度来看,Fiber 是对 React核心算法(即调和过程)的重写

从编码角度来看,Fiber是 React内部所定义的一种数据结构,它是 Fiber树结构的节点单位,也就是 React 16 新架构下的虚拟DOM

一个 fiber就是一个 JavaScript对象,包含了元素的信息、该元素的更新操作队列、类型

10. 说说你对redux中间件的理解?常用的中间件有哪些?实现原理?

中间件(Middleware)是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的
类似于插件,可以在不影响原本功能、并且不改动原本代码的基础上,对其功能进行增强。在Redux中,中间件主要用于增强dispatch函数。
Redux中,中间件就是放在就是在dispatch过程,在分发action进行拦截处理

常用的中间件

  1. redux-thunk:通过action返回一个函数进行异步操作
  2. redux-promise :通过action返回一个promise进行异步处理
  3. redux-logger:用于日志记录

实现原理
中间件本身是一个函数,该函数接收一个store参数,表示创建的仓库,该仓库并非一个完整的仓库对象,仅包含getState,dispatch。该函数运行的时间,是在仓库创建之后运行。
由于创建仓库后需要自动运行设置的中间件函数,因此,需要在创建仓库时,告诉仓库有哪些中间件
需要调用applyMiddleware函数,将函数的返回结果作为createStore的第二或第三个参数。
中间件函数必须返回一个dispatch创建函数

11. React性能优化的手段有哪些?

1、使用纯组件;(PureComponent)
2、使用 React.memo 进行组件记忆(React.memo 是一个高阶组件),对 于相同的输入,不重复执行;
3、如果是类组件,使用 shouldComponentUpdate(这是在重新渲染组件之前触发的其中一个生命周期事件)生命周期事件,可以利用此事件来决定何时需要重新渲染组件;
4、路由懒加载;
5、使用 React Fragments 避免额外标记;
6、不要使用内联函数定义(如果我们使用内联函数,则每次调用“render”函数时都会创建一个新的函数实例);
7、避免在Willxxx系列的生命周期中进行异步请求,操作dom等;
8、如果是类组件,事件函数在Constructor中绑定bind改变this指向;
9、避免使用内联样式属性;
10、优化 React 中的条件渲染;
11、不要在 render 方法中导出数据;
12、列表渲染的时候加key;
13、在函数组件中使用useCallback和u

12. 说说你对事件循环event loop的理解?EventLoop是什么

即事件循环,是指浏览器或Node的一种解决JavaScript单线程运行时不会阻塞的一种机制,也就是实现异步的原理。作为一种单线程语言,JavaScript本身是没有异步这一说法的,是由其宿主环境提供的。

宏任务与微任务
JavaScript代码运行时,任务分为宏任务和微任务两种,Event Loop也将任务队列分为宏队列和微队列分别管理宏任务和微任务,宏队列和微队列也具备队列特性:先进先出。

  1. 微任务

    Promise中的then、catch、finally
    MutationObserver(监视DOM变动的API)
    Process.nextTick(Node环境)

  2. 宏任务
    script中全部代码
    DOM操作
    用户交互操作
    所有的网络请求
    定时器相关的setTimeout、setInterval等

事件循环的进程模型

  1. 选择当前要执行的宏任务队列,选择一个最先进任务队列的宏任务,如果没有宏任务,则会跳转至微任务的执行步骤。
  2. 将事件循环的当前运行宏任务设置为已选择的宏任务。
  3. 运行宏任务。
  4. 将事件循环的当前运行任务设置为null。
  5. 将运行完的宏任务从宏任务队列中移除。
  6. 微任务步骤:进入微任务检查点。
  7. 更新界面渲染。
  8. 返回第一步。
  9. 只要主线程空了,就会读取任务队列,这就是js的运行机制,也被称为EventLoop机制。
    在同一个上下文中,总的执行顺序:同步代码→微任务→宏任务

13. 前端跨域的解决方案?

一、什么是跨域?
  在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制。

什么是同源策略?
  同源策略是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

同源策略限制以下几种行为:

Cookie、LocalStorage 和 IndexDB 无法读取
DOM和JS对象无法获得
AJAX 请求不能发送

二、9种跨域解决方案
1、JSONP跨域
2、跨域资源共享(CORS)
3、nginx代理跨域
4、nodejs中间件代理跨域
5、document.domain + iframe跨域
6、location.hash + iframe跨域
7、window.name + iframe跨域
8、postMessage跨域
9、WebSocket协议跨域

小结
  以上就是9种常见的跨域解决方案,jsonp(只支持get请求,支持老的IE浏览器)适合加载不同域名的js、css,img等静态资源;CORS(支持所有类型的HTTP请求,但浏览器IE10以下不支持)适合做ajax各种跨域请求;Nginx代理跨域和nodejs中间件跨域原理都相似,都是搭建一个服务器,直接在服务器端请求HTTP接口,这适合前后端分离的前端项目调后端接口。document.domain+iframe适合主域名相同,子域名不同的跨域请求。postMessage、websocket都是HTML5新特性,兼容性不是很好,只适用于主流浏览器和IE10+。

14. React render方法的原理,在什么时候会触发?

在类组件和函数组件中,render函数的形式是不同的。

在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件。

在render函数中的jsx语句会被编译成我们熟悉的js代码

在render过程中,React 将新调用的 render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新 DOM树

触发机制:

类组件调用 setState 修改状态
函数组件通过useState hook修改状态。函数组件通过useState这种形式更新数据,当数组的值不发生改变了,就不会触发render

总结:

render函数里面可以编写JSX,转化成createElement这种形式,用于生成虚拟DOM,最终转化成真实DOM

在React 中,类组件只要执行了 setState 方法,就一定会触发 render 函数执行,函数组件使用useState更改状态不一定导致重新render

组件的props 改变了,不一定触发 render 函数的执行,但是如果 props 的值来自于父组件或者祖先组件的 state

在这种情况下,父组件或者祖先组件的 state 发生了改变,就会导致子组件的重新渲染

所以,一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染

15. 说说你对vue中mixin的理解?

一、mixin是什么
mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类;
mixin类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂。
本质就是一个JS对象,可以包含组件中的任意功能选项,如data、components、methods、creaded、computed以及生命周期函数等等。
只需要将共用的功能以对象的方式传入mixins选项中,当组件使用mixins对象时所有mixins对象的对象都将被混入该组件本身的选项中来。
局部混入

import mixin1 from './mixin1'
export default {
    // mixins:[mixin1]
}

全局混入

Vue.mixin({
  created: function () {
      console.log("全局混入")
    }
})

注意:当组件存在与mixin对象相同的选项的时候,进行递归合并的时候组件的选项会覆盖mixin的选项;但是如果相同的选项为生命周期钩子的时候,会合并成一个数组,先执行mixin的钩子,再执行组件的钩子。

总结:
mixin是一种类,在vue中就是js文件,主要的作用是作为功能模块引用。因为在项目中,可能不同组件会有相同的功能,比如控制元素的显示和隐藏,如果他们的变量和规则也完全相同的话,就可以把这个功能单独提取出来,放在mixin.js中,再引入,就可以实现一样的功能了。引入的方法也分为全局混入和局部混入,局部混入就是在每个组件中引入,全局混入就是在main.js中通过Vue.mixin()引入。

16. for…in循环和for…of循环的区别?

遍历数组时:for…in获取到的是每一项的索引值,而for…of获取到的是每一项的值

遍历对象时:for…in获取到的是每一项的key值(也就是属性名),而for…of不能用于遍历对象,会报错

17. Js数据类型判断都有哪几种方式?至少说出5种?它们的区别是什么?

JavaScript有五种数据判断类型方法:

typeof
instanceof
constructor
Object.prototype.toString.call()
jquery.type()

区别
一、typeof方法:

1、可以判断数据类型,它返回表示数据类型的字符串(返回结果只能包括number,boolean,string,function,object,undefined);
2、可以使用typeof判断变量是否存在(如if(typeof a!=“undefined”){…});
3、Typeof 运算符的问题是无论引用的对象是什么类型 它都返回object

二、instanceof方法:

一般用来检测引用数据类型,表达式为:A instanceof B,判断A是否是B的实例,如果 A 是 B 的实例,则返回 true,否则返回 false,由构造类型判断出数据类型

三、constructor方法:

constructor是prototype对象上的属性,指向构造函数,

四、Object.prototype.toString 方法:
用来检测对象类型

五、无敌万能的方法:jquery.type()
如果对象是undefined或null,则返回相应的“undefined”或“null”。

18. 说说你对Object.defineProperty()的理解?

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

该方法接受三个参数:
 第一个参数是 obj:要定义属性的对象、
 第二个参数是 prop:要定义或修改的属性的名称或 Symbol、
 第三个参数是 descriptor:要定义或修改的属性描述符。

19. 说说你对webSocket的理解?

WebSocket,是一种网络传输协议,位于OSI模型的应用层。可在单个TCP连接上进行全双工通信,能更好的节省服务器资源和带宽并达到实时通迅

客户端和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输
特点:

全双工
二进制帧
协议名
握手

优点:

较少的控制开销:数据包头部协议较小,不同于http每次请求需要携带完整的头部

更强的实时性:相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少

保持创连接状态:创建通信后,可省略状态信息,不同于HTTP每次请求需要携带身份验证

更好的二进制支持:定义了二进制帧,更好处理二进制内容

支持扩展:用户可以扩展websocket协议、实现部分自定义的子协议

更好的压缩效果:Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率

应用场景:

弹幕

媒体聊天

协同编辑

基于位置的应用

体育实况更新

股票基金报价实时更新
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值