前端面试题整理

1、说说你对react的理解?有哪些特性?

react是一个用于构建用户界面的JavaScript库,它是由Facebook开发并开源的,现在已经成为前端开发中最受欢迎和广泛使用的框架之一。

react的核心思想是组件化。他将用户用户界面拆分成独立的可复用组件,每个组件都有自己的状态(state)和属性(props),并通过组件间的数据传递来构建复杂的用户界面。

以下是react的一些主要特性:

  • 虚拟dom(virtual dom):react使用虚拟dom来高效的更新和渲染用户界面。虚拟dom是react自己实现的一种轻量级的dom对象,它在内存中维护了一个虚拟dom树,通过比较前后两次状态的差异,只更新需要更新的部分,从而减少了对真实dom的操作,提高了性能。
  • 组件化开发:react鼓励用户将页面拆分成独立的可复用组件。每个组件都有自己的状态(state)和属性(props),可以通过组件间的数据传递来实现复杂的交互和数据流动。组件化开发使得代码更加模块化、可维护性更高,并且可以提高开发效率。
  • 单向数据流:react推崇单向数据流的开发模式,即数据的流动是单向的,从父组件传递给子组件。子组件通过接收父组件传递的属性(props)来渲染自己的界面,当子组件内部的状态发生变化时,通过回调函数将变化的数据传递给父组件进行更新。通过这些单向数据流的模式使得数据流动更可控,易于追踪和调试
  • jsx语法:react使用jsx语法来描述用户界面的结构和交互。jsx是一种JavaScript的语法扩展,它允许我们在JavaScript代码中编写类似于HTML的结构。jsx代码会被react转换成对应的JavaScript对象,然后进行渲染和更新。
  • 强大的生命周期方法:react组件有一系列的生命周期方法,可以在组件的不同阶段执行特定的操作。例如:组件的挂载、更新和卸载等阶段都有对应的生命周期方法,我们可以在这些方法中处理数据的初始化、网络请求、事件绑定等操作,以及做一些清理工作
  • 丰富的生态系统:react生态系统非常丰富,有大量的第三方库和工具可以于react配合使用,会帮助我们构建更好的用户界面,例如:react router可以用于处理路由,redux可以用于状态处理,axios可以用于网络请求等

2 、说说Real DOM和Virtual DOM的区别?优缺点

Real DOM(真实 DOM)和 Virtual DOM(虚拟 DOM)是两种不同的 DOM 抽象概念,用于表示和管理网页的结构和内容。

Real DOM 是浏览器中实际存在的 DOM 结构,它是由浏览器解析 HTML 代码生成的,包括所有的 HTML 元素、属性和它们的关系。当网页的状态发生变化时,我们需要直接操作 Real DOM 来更新界面,例如通过修改元素的属性、添加或删除元素等。然而,直接操作 Real DOM 的成本很高,因为每次操作都会触发浏览器的重新渲染和重排,这对性能有很大的影响。

Virtual DOM 是 React 自己实现的一种轻量级的 DOM 抽象,它是一个 JavaScript 对象,类似于 Real DOM 的一种内存表示。当状态发生变化时,React 会使用 Virtual DOM 来计算出前后两次状态的差异,并将差异应用到 Real DOM 上,从而更新界面。通过比较和更新差异,Virtual DOM 可以减少对 Real DOM 的操作次数,提高性能。

下面是 Real DOM 和 Virtual DOM 的一些区别:

**Real DOM:**
- 操作成本高:直接操作 Real DOM 的成本很高,因为每次操作都会触发浏览器的重新渲染和重排,这对性能有很大的影响。
- 完全渲染:当状态发生变化时,需要手动更新 Real DOM 的相应部分,包括添加、删除和修改元素的属性等。
- 实时反映:Real DOM 是实际在浏览器中呈现的,它实时反映了网页的结构和内容。

Virtual DOM:
- 操作成本低:通过比较前后两次状态的差异,并将差异应用到 Real DOM 上,Virtual DOM 可以减少对 Real DOM 的操作次数,提高性能。
- 高效更新:Virtual DOM 可以批量更新 Real DOM,减少了多次更新的开销。
- 抽象层:Virtual DOM 是一个轻量级的 JavaScript 对象,它抽象了 Real DOM 的概念,使得操作更加简单和高效。
- 跨平台:由于 Virtual DOM 是 JavaScript 对象,它可以在不同的平台上使用,例如服务器端渲染(Server-side Rendering)和移动端开发等。

优点和缺点:
- Real DOM 的优点是它是实际在浏览器中呈现的,能够实时反映网页的结构和内容。然而,它的缺点是操作成本高,每次操作都会触发浏览器的重新渲染和重排,对性能有影响。
- Virtual DOM 的优点是操作成本低,通过比较和更新差异,可以减少对 Real DOM 的操作次数,提高性能。它还具有高效更新和跨平台的特点。然而,使用 Virtual DOM 会增加一定的内存消耗,并且在某些特定场景下可能会引入一些额外的复杂性。

总的来说,Virtual DOM 通过抽象和优化 DOM 操作,提高了前端应用的性能和开发效率。它是 React 框架的核心特性之一,但也并非适用于所有情况。在开发过程中,我们需要根据具体的场景和需求来选择使用 Real DOM 还是 Virtual DOM。

3、说说React生命周期有哪些不同的阶段?每个阶段对应的方法是

在 React 中,组件的生命周期可以分为三个主要阶段:挂载阶段(Mounting Phase)、更新阶段(Updating Phase)和卸载阶段(Unmounting Phase)。每个阶段都有对应的生命周期方法,用于在不同的阶段执行特定的操作。

**挂载阶段(Mounting Phase):**
1. `constructor()`:组件的构造函数,在组件被创建时调用。通常用于初始化组件的状态(state)和绑定事件处理函数。
2. `static getDerivedStateFromProps(props, state)`:静态方法,用于根据新的属性(props)计算并返回新的状态(state)。在组件初始化和接收新的属性时调用。
3. `render()`:必需的方法,用于渲染组件的界面。返回一个 React 元素或 null。
4. `componentDidMount()`:在组件被插入到 DOM 树中后调用。通常用于进行异步请求、添加事件监听等副作用操作。

**更新阶段(Updating Phase):**
1. `static getDerivedStateFromProps(props, state)`:同挂载阶段。
2. `shouldComponentUpdate(nextProps, nextState)`:在组件更新之前调用,用于判断是否需要进行组件的重新渲染。返回 true 表示需要重新渲染,返回 false 表示跳过渲染。
3. `render()`:同挂载阶段。
4. `getSnapshotBeforeUpdate(prevProps, prevState)`:在更新 DOM 之前调用,用于获取当前 DOM 的快照信息。返回的值将作为第三个参数传递给 `componentDidUpdate()`。
5. `componentDidUpdate(prevProps, prevState, snapshot)`:在组件更新完成后调用。通常用于处理更新后的副作用操作,比如更新后的 DOM 操作、网络请求等。

**卸载阶段(Unmounting Phase):**
1. `componentWillUnmount()`:在组件从 DOM 中移除之前调用。通常用于进行一些清理操作,如取消定时器、移除事件监听等。

除了上述生命周期方法,在 React 16.3 版本之后,还引入了一些新的生命周期方法,用于替代一些过时的方法。这些新的方法包括 `static getDerivedStateFromProps()` 和 `getSnapshotBeforeUpdate()`。

需要注意的是,在将来的 React 版本中,一些生命周期方法可能会被废弃或改变用法,因此在使用时要查阅官方文档以获取最新的信息。

总的来说,React 的生命周期方法提供了在组件不同阶段执行操作的钩子,可以用于处理数据初始化、网络请求、事件绑定和一些清理工作等。通过合理使用这些生命周期方法,可以更好地控制组件的行为和实现一些高级功能。

4、说说react中setState执行机制?

在 React 中,setState() 是用于更新组件状态(state)的方法。当调用 setState() 时,React 会触发一系列的更新机制来更新组件的状态和重新渲染组件。

setState() 的执行机制如下:

  1. 状态合并(State Merging)setState() 可以接收一个对象或一个函数作为参数。如果传递的是一个对象,React 会将该对象与当前状态进行浅合并(shallow merge)。如果传递的是一个函数,React 会调用该函数,并将当前状态作为参数传递给该函数,然后使用函数的返回值进行状态合并。

  2. 状态队列(State Queue):React 使用一种队列机制来管理状态更新。当调用 setState() 时,React 会将更新请求添加到状态队列中,而不是立即执行更新操作。

  3. 批量更新(Batch Updates):为了提高性能,React 会将多个状态更新请求合并为单个更新操作。在一个事件循环(Event Loop)内,如果有多个 setState() 调用,React 会将它们合并为一个更新操作,只触发一次重新渲染。

  4. 异步更新(Asynchronous Updates)setState() 的更新操作是异步的。这意味着在调用 setState() 后,React 不会立即执行更新操作,而是将更新放入异步队列中,等待合适的时机进行更新。这样可以提高性能,避免不必要的重复渲染。

  5. 更新队列(Update Queue):React 使用一种高效的数据结构来存储状态更新请求,称为更新队列(Update Queue)。更新队列记录了所有待处理的状态更新操作。

  6. 调度更新(Scheduling Updates):React 使用调度器(Scheduler)来处理状态更新。调度器会根据一定的策略,决定何时执行状态更新操作。它会根据当前的执行环境、浏览器的空闲时间等因素来决定何时触发更新操作,以达到最佳的性能和用户体验。

  7. 重新渲染(Reconciliation):当状态更新被触发时,React 会进行一次重新渲染。React 使用 Virtual DOM 来计算前后两次状态的差异,并将差异应用到实际的 DOM 上,更新界面。

需要注意的是,由于 setState() 的更新操作是异步的,所以不能立即获取到更新后的状态。如果需要在更新后执行一些操作,可以使用 componentDidUpdate() 生命周期方法来处理。

另外,setState() 也可以接收一个回调函数作为第二个参数,在状态更新完成后执行。这个回调函数会在组件完成重新渲染后被调用。

5、说说react的事件机制

React 的事件机制包括以下几个方面:

  1. 事件绑定:在 React 中,通过使用特定的语法将事件处理函数绑定到组件的元素上。通常,在 JSX 中使用 onClickonChange 等属性来绑定事件。例如,<button onClick={handleClick}>Click me</button>

  2. 事件处理函数:事件处理函数是一个普通的 JavaScript 函数,用于处理特定的事件。它可以是组件的方法,也可以是函数组件中的函数。事件处理函数接收一个事件对象作为参数,可以在函数体内进行相应的处理逻辑。

  3. 事件合成(Synthetic Events):React 提供了一种事件合成机制,将原生浏览器事件进行封装,使得事件处理逻辑更加一致和跨浏览器兼容。合成事件提供了与原生事件相似的属性和方法,如 event.targetevent.preventDefault() 等。

  4. 事件传递参数:在事件处理函数中,可以通过使用箭头函数或 bind() 方法来传递额外的参数。这样可以在事件处理函数中访问传递的参数,实现更灵活的事件处理逻辑。

  5. 事件冒泡和捕获:React 的事件机制遵循事件冒泡和捕获的原则。当触发一个事件时,React 会先触发事件在组件树中的捕获阶段,然后再触发冒泡阶段。可以通过在事件处理函数中调用 event.stopPropagation() 来停止事件的传播。

  6. 事件委托:在 React 中,可以将事件处理函数绑定到父组件的元素上,通过事件冒泡机制来处理子组件的事件。这种方式称为事件委托,可以减少事件处理函数的数量,提高性能。

  7. 异步事件处理:与 setState() 的异步更新类似,React 的事件处理函数也是异步执行的。这意味着在事件处理函数中调用 setState() 并不会立即更新组件的状态,而是将更新操作放入异步队列中,等待合适的时机进行更新。

6、React组件之间如何通信

  1. Props(属性):通过使用组件的属性(props)来传递数据和配置信息。父组件可以通过设置子组件的属性来将数据传递给子组件,子组件可以通过 this.props 来访问传递的属性值。这是 React 中最常用的一种组件通信方式。

  2. State(状态):每个组件都有自己的状态(state),可以通过 this.state 来访问和修改组件的状态。父组件可以通过将状态作为属性传递给子组件来实现状态的传递。子组件也可以通过调用父组件传递的回调函数来修改父组件的状态。

  3. Context(上下文):Context 是一种跨组件层级传递数据的方式。通过创建一个 Context 对象,可以在组件树中的任何地方访问和更新该对象中的数据。父组件可以通过设置 Context 的值,然后子组件可以通过 this.context 来访问该值。Context 提供了一种方便的方式来在组件之间共享数据,但在使用时需要小心,避免滥用。

  4. Redux 或其他状态管理库:Redux 是一种流行的状态管理库,可以用于管理应用的全局状态。通过将状态存储在一个全局的状态树中,各个组件可以通过连接(connect)机制来访问和更新状态。Redux 提供了一种可预测的状态管理方式,适用于较大型的应用。除了 Redux,还有其他类似的状态管理库可供选择。

  5. 事件发布订阅(Pub/Sub)模式:通过使用事件发布订阅模式,组件可以在需要的时候发布事件,其他组件可以订阅这些事件并执行相应的处理逻辑。这种方式可以实现组件之间的解耦和灵活的通信。可以使用现有的事件库,如 EventEmitter 或自定义的事件管理器来实现事件发布订阅。

  6. React Router:React Router 是用于处理路由的库,可以在不同的路由之间进行导航和页面切换。通过 React Router,可以在不同的路由组件之间进行通信和传递参数。React Router 提供了一种方便的方式来实现页面间的导航和通信。

7、说说你对受控组件和非受控组件的理解?应用场景

受控组件:

受控组件是指由 React 组件来管理表单元素的状态和值的方式。在受控组件中,表单元素的值被存储在组件的状态(state)中,并且通过事件处理函数来更新状态。每当表单元素的值发生变化时,都会触发事件处理函数来更新组件的状态,从而保持组件和表单元素的值同步。受控组件将表单元素的值作为组件的状态的一部分,使得 React 可以完全控制表单元素的行为。

受控组件的优点是:

  • 可以对表单元素的值进行验证和处理,从而实现更精细的控制和逻辑。
  • 可以方便地对表单元素的值进行修改、重置和提交等操作。
  • 可以将表单元素的值与其他组件的状态进行关联,实现组件之间的数据同步。

受控组件的缺点是:

  • 需要编写更多的代码来处理表单元素的状态和事件。
  • 在处理大型表单时,可能会导致代码变得冗长和复杂。

非受控组件:

非受控组件是指由 DOM 自身来管理表单元素的状态和值的方式。在非受控组件中,表单元素的值由 DOM 直接管理,而不受 React 组件的控制。通常是通过使用 ref 来获取表单元素的引用,然后通过原生 JavaScript 来访问和操作表单元素的值。

非受控组件的优点是:

  • 编写更少的代码,因为不需要处理表单元素的状态和事件。
  • 适用于简单的表单,可以快速地获取和提交表单元素的值。

非受控组件的缺点是:

  • 难以对表单元素的值进行验证和处理,需要手动编写验证逻辑。
  • 难以与其他组件的状态进行同步,可能导致数据不一致。

应用场景:

  • 受控组件适用于需要对表单元素进行精细控制和逻辑处理的情况,如表单验证、条件渲染、动态修改等。受控组件提供了更灵活和可控的方式来处理表单元素的值和状态。

  • 非受控组件适用于简单的表单场景,特别是当表单只包含少量的输入字段时。非受控组件可以减少代码量,快速获取和提交表单元素的值,适合快速原型开发或简单的表单需求。

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

 理解:
        React fiber 是对react做出地一个重大改变与优化,对react核心算法地一次重新实现。
    解决问题:
        JavaScript引擎和页面渲染引擎两个线程是互斥的,当其中一个线程执行时,另一个线程只能挂起等待;如果JavaScript线程长时间地占用了主线程,那么渲染层面的更新就不得不长时间地等待,界面长时间不更新,会导致页面响应速度变差,用户会感到卡顿。
 

9、说说react diff的原理是什么

 diff算法(差异化算法)是虚拟DOM的一个必然结果。
    当程序发生变化时,架构会比较前后两次的虚拟DOM的差异来确定更新部分,从而对整个DOM树进行重新渲染,提升性能和响应速度。
    react中diff算法遵循三个层级的策略:tree层级、component层级、element层级
    tree层不会做任何修改,如果不一样,直接删除创建
    component层从父级往子级查找,如果发现不一致,直接删除创建
    element层又key值作为比较,如果发现key值可以复用的话,将会进行位置的移动,如果没有则执行删除创建
 

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

理解:
        dispatch方法进行了改造,在发出action和执行reducer这两步之间,添加了其他功能。
    常用中间件:
        redux-thunk:用于异步操作。
        redux-logger:用于日志记录
        redux-promise:用于异步操作
    实现原理:
        1、创建一个中间件函数,它接收redux store的dispatch方法作为参数,并返回一个新的dispatch方法
        2、在中间件函数内部创建一个闭包,将原始的dispatch方法保存起来
        3、在新的dispatch方法内部定义一个next函数,它用于执行下一个中间件或者最终派发action到reducer
        4、在新的dispatch方法内部定义一个action函数,用于处理当前中间件的逻辑,并可以选择是否调用next函数将action传递给下一个中间件
        5、将action函数作为参数传递给原始的dispatch方法

11、如何使用css实现一个三角形,写出两种以上方案得满分

  • 方案一: 使用border属性实现一个三角形,设置一个宽高为0的元素,然后通过设置边框的宽度和颜色来实现三角形的效果。

    .triangle {
      width: 0;
      height: 0;
      border-left: 50px solid transparent;
      border-right: 50px solid transparent;
      border-bottom: 100px solid red;
    }
    

    方案二: 使用伪元素before或after结合transform属性实现一个三角形,通过设置伪元素的宽高为0,然后通过设置边框的宽度和颜色来实现三角形的效果。

    .triangle {
      position: relative;
      width: 100px;
      height: 100px;
    }
    
    .triangle:before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      width: 0;
      height: 0;
      border-left: 50px solid transparent;
      border-right: 50px solid transparent;
      border-bottom: 100px solid red;
    }
    

    方案三: 使用clip-path属性实现一个三角形,通过设置一个多边形的路径来裁剪元素,实现三角形的效果。

    .triangle {
      width: 100px;
      height: 100px;
      background-color: red;
      clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
    }
    

12、什么是强缓存和协商缓存

  强缓存:它不用向服务器发送请求,他直接可以从缓存里面读取资源,在chrome的控制台的network选项中可以看到该请求返回的200状态码
    协商缓存:它会向服务器发送请求,服务器会根据这个请求的request header的一些参数判断是不是协商缓存,如果是它会带新的response header通知浏览器再去通过浏览器从本地缓存中读取资源;协商缓存最终由服务器决定是否使用缓存
    相同点:
        都是从缓存中读取资源
    不同点:
        强缓存:不会向后端发送请求
        协商缓存:会向后端发送请求
   

13、说说React jsx转换成真实DOM的过程

  • React JSX转换成真实DOM的过程可以分为以下几个步骤:

    需要注意的是,React使用了一种称为"协调更新"的机制,它会将多个更新操作合并为一个批量更新,从而提高性能。同时,React还会对事件处理、生命周期等进行管理,以保证组件的正确渲染和更新。

  • 解析JSX:React会使用Babel等工具将JSX代码转换为JavaScript对象。

  • 创建虚拟DOM:React会根据解析后的JavaScript对象创建一个虚拟DOM树。虚拟DOM是一个轻量级的JavaScript对象,它描述了真实DOM的结构和属性。

  • Diff算法:React会将新旧虚拟DOM进行比较,找出需要更新的部分。这个过程称为Diff算法,它能够高效地找出需要更新的节点,减少对真实DOM的操作。

  • 更新真实DOM:根据Diff算法的结果,React会生成一系列需要更新的操作,然后将这些操作应用到真实DOM上,从而更新页面的显示。

  • 渲染:最后,React会将更新后的虚拟DOM渲染到真实DOM上,用户就可以看到页面的变化。

14、说说你对@reduxjs/toolkit的理解?和react-redux有什么区别

@redux.js/toolkit是开箱即用的一个高效的redux开发工具集,提供了一些简化的API和默认约定,可以优化代码,使其更可维护。
    react-redux是一个独立的第三方库,用于在react中使用redux,提供了一些react组件和hooks,使得在react组件使用redux更加方便
 

15、React render方法的原理,在什么时候会触发

原理:
        在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件
        render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新dom树
    触发时机:
        类组件调用 setState 修改状态
        函数组件通过useState hook修改状态
        一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染

16、React性能优化的手段有哪些

    1、使用函数组件代替类组件
    2、使用React.memo()包裹组件,进行组件记忆,减少子组件的渲染次数,从而提升性能。
    3、使用路由懒加载
    4、使用useMome 父组件向子组件传值的时候使用,用来包裹向子组件传递的变量,变量不发生变化,子组件不会重新进行渲染,减少子组件渲染次数,提升性能。
    5、使用usecallback 用于包裹父组件向子组件传递的函数,对函数进行缓存,函数不重新进行定义子组件不会进行重新渲染,减少子组件的渲染次数,提升性能。
    6、渲染列表时使用key

17、如何通过原生js实现一个节流函数和防抖函数,写出核心代码,不是简单的思路

防抖

 节流

18、说说webpack中代码分割如何实现

  1. 使用动态导入(Dynamic Import):通过使用import()函数来动态导入模块,Webpack会将导入的模块单独打包成一个文件。例如:

import('./module').then(module => {
  // 使用导入的模块
});

2、使用SplitChunksPlugin插件:Webpack提供了SplitChunksPlugin插件,可以将公共的模块提取出来,形成一个单独的文件。可以通过在Webpack配置文件中进行配置,例如:
module.exports = {
  // ...
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

3、使用动态导入和React.lazy()(适用于React项目):React提供了React.lazy()函数,可以实现组件的动态导入。结合Webpack的代码分割功能,可以将组件单独打包成一个文件。例如:

const MyComponent = React.lazy(() => import('./MyComponent'));

4、使用require.ensure():这是Webpack早期版本中的一种代码分割方式,现在已经不推荐使用。通过使用require.ensure()函数来异步加载模块,Webpack会将模块单独打包成一个文件。例如:

require.ensure([], function(require) {
  const module = require('./module');
  // 使用导入的模块
});

以上是几种常见的Webpack中实现代码分割的方式,可以根据具体的项目需求选择适合的方式进行配置和使用。

19、说说如何借助webpack来优化前端性能?

    1、压缩代码:删除多余的代码、注释、简化代码的写法等方式。
    2、利用CDN加速:在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。
    3、Tree Shaking:将代码中永远不会执行的代码删除掉
    4、Code Splitting:将代码按路由维度或者组件分块,这样做到按需加载,同时可以充分利用浏览器缓存
    5、提取公共第三方库SplitChunksPlugin插件来进行公共模块抽取,利用浏览器缓存可以长期缓存这些无需频繁变动的公共代码

20、说说javascript内存泄漏的几种情况

    1、意外的全局变量(另一种意外的全局变量可能由this创建)
    2、定时器也会造成内存泄露
    3、没有清理对DOM元素的引用也会造成内存泄漏
    4、闭包也会造成内存泄漏

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值