「每周前端面试题专栏」- 滴水之功,开拓大厂之路(第六周)

340 阅读13分钟

写在前面

本周有位群友说我不应该为了面试而背题,我很认同他的说法,这里想表达下我建立这个专栏的初衷吧。

  1. 前端领域知识点繁杂分散,我认为再基础的点,不回顾也有可能忘记,所以我希望这个专栏可以像基地一样,我们常回来看看
  2. 大家也能发现,我这里主要是收集或修改网络上的回答,是因为我真的觉得这些回答很好,这也引出第二点:看看别人是怎么表述这个观点的。
  3. emm...确实也在背题

当然,以上只是我个人观点。

值新的一岁之际,希望自己可以:勤思考,多动手,善总结,能坚持

建了一个公众号,每周周一 至 周五,每天发布若干道面试题,并奉上个人觉得还行的解答,周五(周末发好像点击率真的有点低)、周六或周天发一遍汇总~

希望大家有所得,希望自己有所得。 下面是本周的汇总(2020.08.10 - 2020.08.14)。

目录

  1. 说一下前端优化吧
  2. 「react」什么是 JSX
  3. React 中 fiber 是什么
  4. state 和 props 的区别是啥
  5. 什么是高阶组件
  6. 受控组件 && 非受控组件
  7. 「react」在构造函数调用 super 并将 props 作为参数传入的作用是啥
  8. React 和原生事件的执行顺序是什么?可以混用吗?
  9. react 中的方法使用 bind 和箭头函数的区别
  10. 为何 react 事件要自己绑定 this
  11. 「react」setState 更新是同步的还是异步的
  12. 「react」什么是 prop drilling?如何避免?
  13. 描述 Flux 与 MVC
  14. 说一下 Redux 的原理,介绍下整体的一个工作流程
  15. 说一下 redux 的设计思想(理念、原则)
  16. 说一下 redux 有哪些优缺点?

详情

一、说一下前端优化吧

欢迎补充 ~

webpack 优化
  1. 打包公共代码 code-spliting

  2. 动态导入和按需加载 require.ensure

  3. 删除无用代码 tree shaking

  4. 长缓存优化,正确使用 hash

    例如: 将 hash 替换为 chunkhash,这样当 chunk 不变时,缓存依然有效

减小资源大小
  1. 图片压缩
  2. 其他资源通过 gzip 压缩
优化网络连接
  1. cdn

  2. DNS 预解析(一般可以通过 webpack 的一些插件自动添加)

    <link rel="dns-prefecth" href="http://www.google.com">
    
优化资源加载
  1. 资源加载位置

    • CSS 文件放在 head 中,先外链,后本页
    • JS 文件放在 body 底部,先外链,后本页
    • 处理页面、处理页面布局的 JS 文件放在 head 中,如 babel-polyfill.js 文件、flexible.js 文件
    • body 中间尽量不写 style 标签和 script 标签
  2. 资源加载时机

    • 异步 script 标签

      defer: 异步加载,在 HTML 解析完成后执行。defer 的实际效果与将代码放在 body 底部类似

      async: 异步加载,加载完成后立即执行

  3. 模块按需加载

  4. 使用资源预加载 preload 和资源预读取 prefect

    • preload 让浏览器提前加载指定资源,需要执行时再执行,可以加速本页面的加载速度
    • prefetch 告诉浏览器加载下一页面可能会用到的资源,可以加速下一个页面的加载速度
  5. 资源懒加载与资源预加载

    • 资源延迟加载也称为懒加载,延迟加载资源或符合某些条件时才加载某些资源
    • 资源预加载是提前加载用户所需的资源,保证良好的用户体验
    • 资源懒加载和资源预加载都是一种错峰操作,在浏览器忙碌的时候不做操作,浏览器空间时,再加载资源,优化了网络性能
其他:
  1. 请求数据持久化
  2. 服务端渲染
  3. 骨架图
  4. 不合理的业务主动退回修改

二、「react」什么是 JSX

  • JSX 是 JavaScript XML,是 React 提供的一种语法糖,可以让我们在 JS 中写 html 标记语言。
  • JSX 本身不能被浏览器读取,需要使用 babel + webpack 将其转换为传统的 JS。

三、React 中 fiber 是什么

  • Fiber 是 React 16 中新的协调引擎或者说是重新实现核心算法,我理解为一种任务分割调度的算法。
  • React Fiber 能够将渲染工作分割成块,并将其分散到多个帧中。
  • 它的主要目标是支持虚拟 DOM 的增量渲染。 React Fiber 的目标是提高其在动画、布局、手势、暂停、中止或重用等方面的适用性,并为不同类型的更新分配优先级,以及新的并发单元。

四、state 和 props 的区别是啥

state 和 props 都是普通的 JS 对象,虽然他们都包含影响渲染输出的信息,但是他们在组件方面的功能是不同的

  • state 是组件自己管理数据,控制自己的状态,可变
  • props 是外部传入的数据参数,不可变
  • 没有 state 的叫做无状态组件,有 state 的叫做有状态组件
  • 多用 props,少用 state,也就是多写无状态组件

五、什么是高阶组件

  • 高阶组件(HOC)是接收一个组件并返回一个新组件的函数
  • 是从 React 的组合特性中衍生出来的,称其为纯组件。因为它们可以接收任何动态提供的组件,但不会修改或者复制输入组件的任何行为

HOC 可以用于以下许多用例

  • 代码重写、引导和逻辑抽象
  • 渲染劫持
  • state 抽象和操作
  • props 处理

六、受控组件 && 非受控组件

受控组件 和 非受控组件 主要取决于组件是否受父级传入的 props 控制

受控组件:受 React 控制的组件,是表单数据真实的唯一来源

受控组件更新 state 流程:

  1. 可以通过在初始 state 中设置表单的默认值
  2. 每当表单的值发生变化时,调用 onChange 事件处理器。
  3. 事件处理器通过合成事件对象 e 拿到改变后的状态,并更新 state
  4. setState 触发视图的重新渲染,完成表单组件值的更新。

非受控组件:由 DOM 处理表单数据。

  • 非受控组件的值不受自身的 state 或者 props 控制,通常需要为其添加 ref 来访问它的地城 DOM

一般建议优先选择受控组件:1. 支持即时字段校验 2. 允许有条件的禁用/启动按钮 3. 强制输入格式

七、「react」在构造函数调用 super 并将 props 作为参数传入的作用是啥

  • 在调用 super 之前,子类构造函数无法使用 this 引用, ES6 子类也是这样
  • super() 可以让我们使用 this 来调用各种东西
  • 而 super(props) 可以让我们在 this 的基础上使用构造函数里面的东西, 或者从父元素那边传过来的一些属性
  • 如果只调用了 super(),那么 this.props 在 super() 和构造函数结束之间仍是 undefined

参考 / 来源:

github fe-interview

八、React 和原生事件的执行顺序是什么?可以混用吗?

React 的事件处理程序要等到事件冒泡到 document 后才能捕获。

所以原生的事件会先执行,在事件流的最后冒泡结束后,才执行 React 的合成事件,然后触发真正在 document 上挂载的事件。

最好不要混用,因为如果在原生事件中执行 stopPropagation,会导致后续不能冒泡,最终导致所有的 React 事件都无法被触发。

参考 / 来源: React高频面试题梳理,看看面试怎么答?

九、react 中的方法使用 bind 和箭头函数的区别

bind 有两种方式,一种是在 constructor 中 bind ,另外一种是在调用也就是 render 里面 bind

箭头函数也有两种:

  • 一种是在定义的时候就用箭头函数:handleClick = () => {}
  • 第二种是在调用的时候使用 <button onClick={() => this.handleClick}/>

箭头函数的原理就是借助 箭头函数自身没有 this,要往定义时候的上层找, class Component 又是被 new 出来的,所以箭头函数可以保证方法可以通过 this 找到。

箭头函数的第二种使用方法有一个缺点,每次调用会产生一个新的方法,这样导致你对子组件做的 memo 优化没有效果。

参考 / 来源: React高频面试题梳理,看看面试怎么答?

十、为何 react 事件要自己绑定 this

在 react 的事件处理流程中,React 在 document 上进行统一的事件分发,dispatchEvent 通过循环调用所有层级的事件来模拟事件冒泡和捕获。

在 React 源码中,当具体到某一事件处理函数将要调用时,将调用 invokeGuardedCallback 方法。

function invokeGuardedCallback(name, func, a) {
  try {
    func(a);
  } catch (x) {
    if (caughtError === null) {
      caughtError = x;
    }
  }
}

可见,事件处理函数是直接调用的,并没有指定调用的组件,所以不进行手动绑定的情况下直接获取到的 this 是不准确的,所以我们需要手动将当前组件绑定到 this 上。

参考 / 来源: React高频面试题梳理,看看面试怎么答?

十一、「react」setState 更新是同步的还是异步的

  • 如果是正常情况下,也就是没有使用 Concurrent 组件(React16 新加的)的情况下,setState 是同步更新的,但是不会立即获取到最新的 state 的值,因为调用 setState 只是单纯的将你传进来的新的 state 放入 updateQueue 这条链表上,等这个点击事件(react 叫这类事件为合成事件,只有合成事件会触发回调事件进行更新 state)结束后,会触发内部的一个回调函数,在这个回调函数中,才会真正的去更新 State 以及重新渲染

  • 当使用了 Concurrent 组件的时候,这种情况下才是真正的异步更新模式,同样的没法立即获取最新的状态,并且在执行 React 的更新和渲染(这个渲染是创建 Fiber 的过程)的过程中,使用了真正的异步方式(API:postMessage),会将 Fiber 的更新过程放在 eventLoop 里面进行

  • 当使用了 flushSync(React 新版本提供的)这个 API 的时候,React 的更新渲染完全是同步的,React 会立即触发更新 state 以及渲染的过程,这种情况是可以获取到最新状态的

十二、「react」什么是 prop drilling?如何避免?

在 React 组件中,在多层嵌套组件中需要使用另一个嵌套组件提供的数据,一般使用 props 从父级组件一层层将数据传递下去。

将 props 从源组件传递到深层嵌套组件,叫做 prop drilling

  1. 缺点:原本不需要该数据的组件变得复杂,难以维护
  2. 如何避免: React Context、 Redux 或者 Hooks 进行数据管理

十三、描述 Flux 与 MVC

传统的 MVC 模式在分离数据(Model)、UI(View)和逻辑(Controller)方面工作得很好,但是 MVC 架构经常遇到两个主要问题:

  1. 数据流不够清晰:跨视图发生的级联更新常常会导致混乱的事件网络,难于调试
  2. 缺乏数据完整性:模型数据可以在任何地方发生突变,从而在整个 UI 中产生不可预测的结果

使用 Flux 模式的复杂用户界面不再遭受级联更新,任何给定的 React 组件都能够根据 store 提供的数据重建其状态。 Flux 模式还通过限制对共享数据的直接访问来加强数据完整性

十四、说一下 Redux 的原理,介绍下整体的一个工作流程

redux 本身只是一个状态管理库,它只有三个核心概念:state、action 和 reducer。

使用流程:

  1. 将需要修改的 state 都存入到 state 里,
  2. 发起一个 action 用来描述发生了什么
  3. 用 reducers 描述 action 如何改变 state tree。

工作流程:

  1. 用户触发某种操作,发送一个 action
  2. redux 接收到这个 action 后通过 reducer 函数获取到下一个状态
  3. 将新状态更新进 store

redux 核心就是一个 发布-订阅 模式,一旦 store 发生了变化就会通知所有的订阅者,订阅者一般是接到通知后进行重新渲染。

十五、说一下 redux 的设计思想(理念、原则)

  1. 单一事实来源:整个应用的状态存储在单个 store 中的对象/状态树里。单一状态树可以更容易地追踪数据随时间的变化,并调试或检查应用程序。
  2. 状态只读:改变状态的唯一方法是去触发一个动作。动作是描述变化的普通 JS 对象。
  3. 使用纯函数进行更改

Redux 由一下组件组成:Store、Action、Reducer、View

十六、说一下 redux 有哪些优缺点?

优点:

  • 结果的可预测性 - 由于总是存在一个真实来源,即 store ,因此不存在如何将当前状态与动作和应用的其他部分同步的问题。
  • 可维护性 - 代码变得更容易维护,具有可预测的结果和严格的结构。
  • 便于服务器端渲染 - 你只需将服务器上创建的 store 传到客户端即可。这对初始渲染非常有用,并且可以优化应用性能,从而提供更好的用户体验。
  • 便于调试 - 从操作到状态更改,开发人员可以实时跟踪应用中发生的所有事情。
  • 便于测试 - Redux 的代码主要是小巧、纯粹和独立的功能。这使代码可测试且独立。
  • 社区和生态系统 - Redux 背后有一个巨大的社区,这使得它更加迷人。一个由才华横溢的人组成的大型社区为库的改进做出了贡献,并开发了各种应用。
  • 组织 - Redux 准确地说明了代码的组织方式,这使得代码在团队使用时更加一致和简单。

缺点:

  • 应用中,很多状态需要抽象到 store,没有统一标准何时使用 local states 何时接入 redux store
  • 流程太繁琐,需要用各种 action,reducer
  • 想获取异步数据,需要配合其他库

总结缺点:它没有成熟到自己阻止不需要用它的人 用它!

写在最后

前端的世界纷繁复杂,远非笔者所能勾画,部分面试题不是靠背诵记忆就能掌握的,希望我摘录的、总结的简单答案可以引起读者的兴趣,闲暇时可以自己深入总结,如果读者有更好的答案,或有想了解的题目,欢迎留言。

笔者新建了一个 github 仓库,对公众号内发布的面试题做进一步分类,同时也会在周六同步本周题目、公布下周问题,欢迎大家关注~

想要实时关注笔者最新的文章和最新的文档更新请关注公众号前端地基,后续的文章会优先在公众号更新.

github:关注笔者最新的仓库