面试题总结

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

几种情况下容易造成生命周期的坑
  • getDerivedStateFromProps 容易编写反模式代码,使受控组件和非受控组件区分模糊

  • componentWillMount 在 React 中已被标记弃用,不推荐使用,主要的原因是因为新的异步架构会导致它被多次调用,所以网络请求以及事件绑定应该放到 componentDidMount 中

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

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

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

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

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

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

  1. Diff算法是虚拟DOM的一个必然结果,它是通过新旧DOM的对比,将在不更新页面的情况下,将需要内容局部更新

  1. Diff算法遵循深度优先,同层比较的原则

  1. 可以使用key值,可以更加准确的找到DOM节点

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

tree层级

conponent 层级

element 层级

tree层不会做任何修改,如果有不一样,直接删除创建

component层从父级往子集查找,如果发现不一致,直接删除创建

element层有key值做比较,如果发现key值可以复用的话,就会将位置进行移动,如果没有,则执行删除创建

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

当调用 setState 时,React 会做的第一件事情是将传递给 setState 的对象合并到组件的当前状态

这将启动一个称为和解(reconciliation)的过程。和解(reconciliation)的最终目标是以最有效的方式,根据这个新的状态来更新UI。 为此,React将构建一个新的 React 元素树(您可以将其视为 UI 的对象表示)

一旦有了这个树,为了弄清 UI 如何响应新的状态而改变,React 会将这个新树与上一个元素树相比较( diff )

调用setState发生什么?

(1)代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。

(2)经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面;

(3)在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;

(4)在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

  1. redux的实现原理是什么,核心代码

  1. 将应用的状态统一放到state中,由store来管理state。

  1. reducer的作用是 返回一个新的state去更新store中对用的state。

  1. 按redux的原则,UI层每一次状态的改变都应通过action去触发,action传入对应的reducer 中,reducer返回一个新的state更新store中存放的state,这样就完成了一次状态的更新

  1. subscribe是为store订阅监听函数,这些订阅后的监听函数是在每一次dipatch发起后依次执行

  1. 可以添加中间件对提交的dispatch进行重写

核心API
  1. createStore 创建仓库,接受reducer作为参数

  1. bindActionCreator 绑定store.dispatch和action 的关系

  1. combineReducers 合并多个reducers

  1. applyMiddleware 洋葱模型的中间件,介于dispatch和action之间,重写dispatch

  1. compose 整合多个中间件

  1. react合成时间的原理?

React并不是将click事件绑在该div的真实DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行。

收集的事件放在dispatchQueue数组中,而冒泡和捕获的区别在于执行时机和顺序,那么我们只需要对数组按照不同顺序循环执行即可

首先会在fiber节点进入render阶段的complete阶段时,将事件监听绑定在root上。然后调用ensureListeningTo进行事件绑定,生成事件合成对象、收集事件、触发真正的事件。

  1. react组件之间如何通信?

  1. 父组件向子组件通讯:

父组件可以向子组件传入props的方式,向子组件进行通讯。

  1. 子组件向父组件通讯:

props+回调的方式,父组件向子组件传递props进行通讯,此props为作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中。

  1. 兄弟组件通信:

兄弟组件之间的传递,则父组件作为中间层来实现数据的互通,通过使用父组件传递

例:组件A – 传值 --> 父组件 – 传值 --> 组件B

  1. 跨层级通讯:

Context 设计⽬的是为了共享那些对于⼀个组件树⽽⾔是“全局”的数据,

使用context提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据

例如当前认证的⽤户、主题或⾸选语⾔,对于跨越多层的全局数据通过 Context 通信再适合不过。

  1. 发布订阅者模式:

发布者发布事件,订阅者监听事件并做出反应,我们可以通过引⼊event模块进⾏通信。

  1. 全局状态管理工具:

借助Redux或者Mobx等全局状态管理⼯具进⾏通信,这种⼯具会维护⼀个全局状态中⼼Store,并根据不同的事件产⽣新的状态。

  1. 为什么react元素有一个$$type属性?

目的是为了防止 XSS 攻击。因为 Synbol 无法被序列化,所以 React 可以通过有没有 $$typeof 属性来断出当前的 element 对象是从数据库来的还是自己生成的。

如果没有 $$typeof 这个属性,react 会拒绝处理该元素。

  1. connect组件的原理

connect是一个高阶函数,它真正连接 ReduxReact,包在我们的容器组件的外一层,接收上面 Provider 提供的 store 里面的 statedispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。

原理:

首先传入mapStateToProps、mapDispatchToProps,然后返回一个生产Component的函数(wrapWithConnect),然后再将真正的Component作为参数传入wrapWithConnect,这样就生产出一个经过包裹的Connect组件,该组件具有:

(1)通过props.store获取祖先Component的store

(2)props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component

(3)componentDidMount时,添加事件this.store.subscribe(this.handleChange),实现页面交互

(4)shouldComponentUpdate时判断是否有避免进行渲染,提升页面性能,并得到nextState

(5)componentWillUnmount时移除注册的事件this.handleChange

  1. fiber架构的理解 解决了什么问题

理解:

React Fiber 是对 React 做出的一个重大改变与优化,是对 React 核心算法的一次重新实现

主要做了:

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

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

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

解决的问题:

JavaScript引擎和页面渲染引擎两个线程是互斥的,当其中一个线程执行时,另一个线程只能挂起等待;如果 JavaScript 线程长时间地占用了主线程,那么渲染层面的更新就不得不长时间地等待,界面长时间不更新,会导致页面响应度变差,用户可能会感觉到卡顿

  1. redux中间件的理解 常用的中间件 实现原理

中间件是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的

Redux中,中间件就是放在就是在dispatch过程,在分发action进行拦截处理

本质上一个函数,对store.dispatch方法进行了改造,在发出 Action和执行 Reducer这两步之间,添加了其他功能

常用中间件:

redux-thunk:用于异步操作

redux-logger:用于日志记录

实现原理:

所有中间件被放进了一个数组chain,然后嵌套执行,最后执行store.dispatch。可以看到,中间件内部(middlewareAPI)可以拿到getState和dispatch这两个方法内部会将dispatch进行一个判断,然后执行对应操作

  1. react性能优化的手段有哪些

React中如何避免不必要的render (opens new window)中,我们了解到如何避免不必要的render来应付上面的问题,主要手段是通过shouldComponentUpdate、PureComponent、React.memo,这三种形式这里就不再复述

除此之外, 常见性能优化常见的手段有如下:

  • 避免使用内联函数

  • 使用 React Fragments 避免额外标记

  • 使用 Immutable

  • 懒加载组件

  • 事件绑定方式

  • 服务端渲染

  1. 事件循环 event loop的理解

为了解决单线程运行阻塞问题,JavaScript用到了计算机系统的一种运行机制,这种机制就叫做事件循环(Event Loop)

在JavaScript中,所有的任务都可以分为:

同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行

异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等

同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就是事件循环

  1. 前端跨域的解决方案

通过jsonp跨域

document.domain + iframe跨域

location.hash + iframe window.name + iframe跨域

postMessage跨域

跨域资源共享(CORS)

nginx代理跨域

nodejs中间件代理跨域

WebSocket协议跨域

  1. 数组常用方法及作用

  1. Array.length:返回或设置一个数组中的元素个数

  1. Array.from() :对伪数组或可迭代对象(包括arguments,Array,Map,Set,String…)转换成数组对象

  1. Array.isArray():用于确定传递的值是否是一个 Array

  1. concat():方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

  1. every(callback):方法测试数组的所有元素是否都通过了指定函数的测试

  1. filter():创建一个新数组, 其包含通过所提供函数实现的测试的所有元素

  1. find():返回数组中满足提供的测试函数的第一个元素的值

  1. forEach():方法对数组的每个元素执行一次提供的函数

  1. includes():用来判断一个数组是否包含一个指定的值,如果是,酌情返回 true或 false

  1. indexOf():返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1

  1. join():将数组(或一个类数组对象)的所有元素连接到一个字符串中

  1. lastIndexOf():返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果 不存在则返回 -1。从数组的后面向前查找

  1. map():创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果

  1. pop():从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度

  1. push():将一个或多个元素添加到数组的末尾

  1. reduce():累加器和数组中的每个元素(从左到右)应用一个函数

  1. shift():从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度

  1. slice():返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象

  1. some():测试数组中的某些元素是否通过由提供的函数实现的测试。

  1. sort():当的位置对数组的元素进行排序,并返回数组。

  1. splice():通过删除现有元素和/或添加新元素来更改一个数组的内容

  1. toString():返回一个字符串,表示指定的数组及其元素

  1. unshift():将一个或多个元素添加到数组的开头,并返回新数组的长度

  1. toLocaleString():返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 “,”)隔开

  1. react render方法的原理 在什么时候会触发

  1. 原理

首先,人的人函数在react中有两种形式:

在类组件中,指的是render方法:

class Foo extends React.Component {
    render() {
        return <h1> Foo </h1>;
    }
}

在函数组件中指的是函数本身:

function Foo() {
    return <h1> Foo </h1>;
}

在render中,我们会编写jsx,jsx通过babel编译后就会转化成我们熟悉的js格式,如下:

return (
  <div className='cn'>
    <Header> hello </Header>
    <div> start </div>
    Right Reserve
  </div>
)

babel编译后:

return (
  React.createElement(
    'div',
    {
      className : 'cn'
    },
    React.createElement(
      Header,
      null,
      'hello'
    ),
    React.createElement(
      'div',
      null,
      'start'
    ),
    'Right Reserve'
  )
)

从名字上看 createElement方法用来创建元素

在react中 这个元素就是虚拟DOM树的节点,接收三个参数:

  • type:标签

  • attributes:标签属性,若无则为null

  • children:标签的子节点

这些虚拟DOM树最终会渲染成真实DOM

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

  1. 触发时机

render的执行时机主要分成了两部分:

  • 类组件中调用setState修改状态

  • 函数组件通过 useState hook 修改状态(函数组件通过useState形式更新数据,当数组的值不发成改变了,就不会触发render)

  • 类组件重新渲染

  • 函数组件重新渲染

  1. 对vue中mixin的理解

Mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类

mixin类同城作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂

Vue中的mixin

官网定义:mixin(混入),提供了一种非常灵活的方式,类分发vue组件中的可复用功能。

本质其实就是一个js对象,它可以包含我们组件中任意功能的选项,如data、components、methods、created、computed等等

我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来

在Vue中我们可以局部混入全局混入

局部混入

定义一个mixin对象,有组件options的data、methods属性

var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

组件通过mixins属性调用mixin对象

Vue.component('componentA',{
  mixins: [myMixin]
})

该组件在使用的时候,混合了mixin里面的方法,在自动执行created生命钩子,执行hello方法

全局混入

通过Vue.mixin()进行全局的混入

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

使用全局混入需要特别注意,因为它会影响到每一个组件实例(包括第三方组件)

PS:全局混入常用于插件的编写

注意事项:

当组件存在与mixin对象相同的选项的时候,进行递归合并的时候组件的选项会覆盖mixin的选项

但是如果相同选项为生命周期钩子的时候,会合并成一个数组,先执行mixin的钩子,再执行组件的钩子

  1. for...in 循环和for...of循环的区别

for...in 循环:只能获得对象的键名,不能获得键值

for…in循环有几个缺点

  ①数组的键名是数字,但是for…in循环是以字符串作为键名“0”、“1”、“2”等等。

  ②for…in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。

  ③某些情况下,for…in循环会以任意顺序遍历键名。

  for…in循环主要是为遍历对象而设计的,不适用于遍历数组。

for...of 循环:允许遍历获得键值

for…of循环

  ①有着同for…in一样的简洁语法,但是没有for…in那些缺点。

  ②不同于forEach方法,它可以与break、continue和return配合使用。

  ③提供了遍历所有数据结构的统一操作接口

  1. js数据类型判断有哪几种方式 他们的区别是什么

  1. typeof判断

typeof返回的类型都是字符串形式

  1. Constructor

实例constructor属性指向构造函数本身

constructor 判断方法跟instanceof相似,但是constructor检测Object与instanceof不一样,constructor还可以处理基本数据类型的检测,不仅仅是对象类型

  1. Instanceof

instanceof可以判类型是否是实例的构造函数

instanceof 后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。

  1. Object.prototype.toString.call()

判断类型的原型对象是否在某个对象的原型链上

  1. 通过object原型上的方法判断

比如array.isArray()来判断是不是一个数组

  1. ===(严格运算符)

通常出现在我们的条件判断中,用来判断数据类型的话就会非常的有局限性,比如判断一个变量是否为空,变量是否为数据等

  1. 对Object.defineProperty()的理解

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

该方法接受三个参数

  • 第一个参数是 obj:要定义属性的对象,

  • 第二个参数是 prop:要定义或修改的属性的名称或 Symbol

  • 第三个参数是 descriptor:要定义或修改的属性描述符

函数的第三个参数 descriptor 所表示的属性描述符有两种形式:数据描述符存取描述符

  • 数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。

  • 存取描述符是由 getter 函数和 setter 函数所描述的属性。

一个描述符只能是这两者其中之一;不能同时是两者。

这两种同时拥有下列两种键值:

configurable: 是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable)。设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。

enumerable: 当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。默认为 false。

  1. 对webSocket的理解

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

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

从上图可见,websocket服务器与客户端通过握手连接,连接成功后,两者都能主动的向对方发送或接受数据

而在websocket出现之前,开发实时web应用的方式为轮询

不停地向服务器发送 HTTP 请求,问有没有数据,有数据的话服务器就用响应报文回应。如果轮询的频率比较高,那么就可以近似地实现“实时通信”的效果

轮询的缺点也很明显,反复发送无效查询请求耗费了大量的带宽和 CPU资源

特点:

双全工

二进制帧

协议名

握手

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值