前端面试题 四

10 阅读8分钟

一、Redux

  1. 是什么?
  • redux是一个使用叫做‘action'的事件来管理和更新应用状态的模式和工具库。它以集中式store的方式对整个应用中使用的状态进行集中管理,其规则确保状态只能以可预测的方式更新。
  • 而在整个应用中会存在很多个组件,每个组件的state是由自身进行管理,包括组件定义自身的state、组件之前的通信通过props传递、使用Context实现数据共享。
  • 如果让每个组件都存储自身相关的状态,理论上来讲不会影响应用的运行,但在开发及后续维护阶段,我们将花费大量精力去查询状态的变化过程。
  • 这种情况下,如果将所有的状态进行集中管理,当需要更新状态的时候,仅需要对这个管理集中处理,而不用去关系状态是如何分发到每一个组件内部的。
  • redux就是一个实现上述集中管理的容器,遵循三大基本原则:
    • 单一数据源
    • state是只读的
    • 使用纯函数来执行修改

注意:redux并不是只应用在react中,还与其他界面库一起使用,如vue

  1. 什么情况下建议使用redux
    • 应用中有很多state在多个组件中需要使用
    • 应用state会随着时间的推移而频繁更新
    • 更新state的逻辑很复杂
    • 中型和大型代码量的应用,很多人协同开发
    • 有很多数据随时间而变化
    • 希望状态有一个唯一确定的来源
    • 将所有状态放在顶层组件中管理已不可维护
  2. 工作原理
  • redux要求我们把数据都放在store公共存储空间
  • 一个组件改变了store里的数据内容,其他组件就能感知到store的变化,再来取数据,从而间接的实现了这些数据传递的功能。
  1. 步骤
  • 初始启动
    • 使用最顶层的root reducer函数创建redux store
    • store调用一次root reducer,并将返回值保存为它的初始值
    • 当视图首次渲染时,视图组件访问Redux store的当前state,并使用该数据来决定要呈现的内容。同时监听store的更新,以便它们可以知道state是否已更改。
  • 更新环节
    • 应用程序中发生了某些事情,例如用户单击按钮
    • dispatch一个action到Redux store,例如dispatch({ type: 'counter/increment' })
    • store用之前的state和当前的action再次运行reducer函数,并将返回值保存为新的state
    • store通知所有订阅过的视图,通知它们store发生更新
    • 每个订阅过store数据的视图,组件都会检查它们需要的state部分是否被更新
    • 发现数据被更新的每个组件都强制使用新数据重新渲染,紧接着更新网页
  1. 一些概念
  • Redux是一个管理全局应用状态的库
    • Redux通常与React-Redux库一起使用,把Redux和React集成在一起
    • Redux Toolkit是编写Redux逻辑的推荐方式
  • Redux使用”单项数据流“
    • State描述了应用程序在某个时间点的状态,视图基于该state渲染
    • 当应用程序中发生某些事情时:
      • 视图dispatch一个action
      • store调用reducer,随后根据发生的事情来更新state
      • store将state发生了变化的情况通知UI
    • 视图基于新state重新渲染
  • Redux有这几种类型的代码
    • Action是有type字段的纯对象,描述发生了什么
    • Reducer是纯函数,基于先前的state和action来计算新的state
    • 每当dispatch一个action后,store就会调用root reducer
  1. 规则
    • 仅使用state和action参数计算新的状态值
    • 禁止直接修改state。必须通过复制现有的state并对复制的值进行更改的方式来做不可变更新
    • 禁止任何异步逻辑、依赖随机值或导致其他“副作用”的代码
  2. 在Redux中,永远不允许在reducer中更改state的原始对象

二、js函数和箭头函数有什么区别

  • 语法更加简洁、清晰。箭头函数省去了function关键字,采用箭头=>来定义函数。
  • 箭头函数不会创建自己的this
    • 箭头函数没有自己的this,它会捕获自己在定义时(注意: 是定义时,不是调用时)所处的外层执行环境的this,并继承这个this值。所以,箭头函数中this的指向在它被定义时就已经确定了,之后永远不会改变。
  • 箭头函数继承而来的this指向永远不变
  • .call()|.apply()|.bind()无法改变箭头函数中this的指向
  • 箭头函数不能作为构造函数使用
  • 箭头函数没有自己的arguments
    • 可以在箭头函数中使用rest参数代替arguments对象,来访问箭头函数的参数列表??
  • 箭头函数没有原型prototype
  • 箭头函数不能用作Generator函数,不能使用yeild关键字

三、海量数据显示:

分页、数据懒加载

四、echarts常用的api?

  • 常用的图标类型
    • 柱状图
    • 折线图
    • 饼图
    • 散点图

五、浏览器缓存

浏览器缓存是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档。
  • 强缓存(本地缓存)
    • 当请求资源的时候,如果是之前请求过的并使用强缓存,那么在过期时间内将不会发送本次请求向服务器获取资源,而是直接从浏览器缓存中获取(不管资源是否改动)。过期了将重新从服务器获取,并再次强缓存。
  • 协商缓存(弱缓存)
    • 当请求资源的时候,如果是之前请求过的并使用协商缓存,还是发送请求到服务器,服务器通过逻辑判断确认资源没有修改返回304,本次的资源从缓存中读取;如果经过判断确认资源有被修改过,则重新发送资源到客户端,并且客户端更新缓存。
  • 优点:
    • 减少加载时间: 通过使用缓存, 浏览器可以重用已下载的资源, 而不必每次都从服务器重新请求。这减少了页面加载时间, 提高了用户体验, 尤其是在较慢的网络连接下。
    • 降低服务器负载: HTTP缓存可以减少服务器的负载, 因为不再需要为相同的资源处理大量重复请求。这有助于减少服务器资源的使用, 降低运营成本。
    • 减少网络流量: HTTP缓存可以减少不必要的网络流量, 因为浏览器可以从本地缓存中加载资源, 而不必每次都从服务器下载。这有助于减少带宽成本, 尤其是对于大型网站来说。
    • 提高用户体验: 快速加载的网页提供更好的用户体验, 吸引更多的访问者, 并增加用户留存率。缓存使用户能够更快地访问网站内容, 从而提高了他们的满意度。

六、浏览器插件如何开发

一个 Chrome 插件通常由以下几个基本文件组成:

manifest.json:插件的配置文件,定义插件的基本信息和权限。 background.js:插件的后台脚本,负责执行后台任务。 popup.html:用户点击插件图标时显示的界面。 style.css:用于美化插件界面的样式表。

七、组件封装、插件封装、性能优化、打包优化

八、webpack打包相关

  • 通过webpack.base.js提供基础配置,分别创建webpack.dev.js和webpack.prod.js实现开发和生产环境的差异化配置
  • 在开发环境中引入webpack-hot-middleware实现热更新
  • 通过webpack-merge插件合并基础配置与环境特定配置,提升代码可维护性

九、ts基础知识

  • 类型系统
    • 强类型与弱类型
      • 强类型:不允许隐式类型转换
    • 静态类型与动态类型
      • 动态类型:运行阶段才能够明确变量类型,变量类型能随时发生变化(变量本身无类型,变量值有类型)
    • JavaScript
      • 弱类型、动态类型
      • 常见问题
        • 运行时才报错
        • 类型不明确,造成函数功能发生改变
        • 对象索引用法错误
    • TypeScript
      • JavaScript + ES6 + 类型系统
      • 强类型优势
        • 编译时报错
        • 更加智能,编码更准确
        • 重构更加牢靠
        • 减少代码层面不必要的类型判断
      • 缺点
        • 语言本身多了很多概念,增加了学习成本
        • 项目初期需要写很多类型声明