前端面试题—面试题整理(7)

一 面试题汇总(Boss直聘分享-百安居一面)

  1. 项目中遇到的难点
  2. 说说自己做的比较好的项目
  3. react种有对状态管理做进一步封装吗
  4. react中在父组件中如何获取子组件的方法
  5. 低代码和微前端有了解吗?
  6. useCallback使用过没?
  7. 函数组件和类组件处理重复渲染有什么区别?
  8. 封装的按钮权限组件怎么实现的?
  9. 数据什么时候定义在组件里面,什么时候定义在状态管理里面?
  10. 方法什么时候写在父组件里,什么时候写在子组件中?

二 面试题解答(仅供参考)

2.1 项目中遇到的难点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
在项目开发中,可能会遇到各种各样的难点,具体的难点会根据项目的特点和需求而有所不同。
以下是一些常见的项目开发中可能遇到的难点:

1-技术选型:在项目开始阶段,需要选择合适的技术栈和框架,
可能会因为技术的广泛性、成熟度、社区支持等因素而面临选择困难。

2-需求变更:随着项目的进行,客户或产品经理可能会提出新的需求或修改已有的需求,
需要及时调整项目的计划和开发方向。

3-性能优化:对于大型项目或数据量较大的系统,性能优化是一个重要的挑战,
需要通过合理的架构设计和代码优化来提升系统的性能和响应速度。

4-跨平台兼容性:如果项目需要在多个平台(如 PC、移动端、不同浏览器)上运行,
需要考虑不同平台的兼容性和适配性,确保在不同环境下都能正常运行。

5-安全性:安全性是一个重要的考量因素,需要防范各种安全攻击(如 XSS、CSRF、SQL 注入等),
保护用户和系统的数据安全。

6-团队协作:如果是多人协作的项目,需要考虑团队成员之间的沟通协作、代码管理和版本控制等问题,
确保团队的效率和项目的顺利进行。

7-第三方服务集成:如果项目需要集成第三方服务(如支付接口、地图服务、社交平台等),
可能会面临接口文档不清晰、权限验证等问题,需要耗费一定的时间和精力来解决。

8-项目部署和维护:项目开发完成后,还需要考虑项目的部署和运维问题,
包括服务器环境的搭建、域名配置、备份和监控等,确保项目能够稳定运行和持续维护。

面对这些难点,可以通过学习和积累经验、与团队成员和同行交流、查阅文档和资料等方式来解决。
同时,也可以寻求专业的技术支持和咨询,提高项目开发的效率和质量。

2.2 说说自己做的比较好的项目

1
2
3
4
5
6
7
8
9
10
如果你想提及你自己做的比较好的项目,以下是一些可能有助于描述的方面:

1-项目描述:简要介绍你的项目是做什么的,它解决了什么问题,以及它的主要功能和特点是什么。
2-技术栈:说明你在项目中使用了哪些技术和工具,比如编程语言、框架、数据库等。
3-创新点:描述你的项目中的创新之处,可能包括新颖的功能、优化的算法、用户体验改进等方面。
4-团队合作:如果是团队项目,可以提及你与团队成员之间的协作方式和分工情况。
5-挑战和解决方案:谈谈在项目开发过程中遇到的挑战,以及你是如何克服这些挑战的。
6-成果和影响:如果有的话,可以分享一些项目的成果和影响,比如用户数量、用户反馈、商业价值等方面。

在描述自己的项目时,尽量客观、清晰地表达你的想法,让别人能够了解你的项目以及你在项目中的贡献和成就。

2.3 react种有对状态管理做进一步封装吗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
React 社区有许多针对状态管理的进一步封装库,其中最流行和广泛使用的是 Redux 和 MobX。
这些库提供了更高级别的抽象,帮助开发者更轻松地管理应用的状态,
并提供了一些额外的特性和工具,以简化状态管理的复杂性。

以下是两个常见的 React 状态管理库:

1-Redux:

Redux 是一个可预测的状态容器,用于 JavaScript 应用的状态管理。
它将应用的状态存储在一个单一的不可变对象中,并使用纯函数(reducers)来处理状态的变化。
Redux 提供了一组 API 来触发状态变化,以及一些中间件来处理异步操作和副作用。
Redux 的核心概念包括 Store(存储应用的状态)、Actions(描述状态变化的纯对象)、
Reducers(描述状态如何变化的纯函数)和中间件(处理副作用和异步操作)等。
Redux与React结合使用时,通常配合使用react-redux库来将Redux的状态和操作绑定到React组件上。

2-MobX:

MobX 是一个简单、可扩展的状态管理库,它通过使用可观察对象(observable)来自动追踪状态的变化,
并在状态变化时更新相关的组件。
与 Redux 不同,MobX 不需要编写大量的模板代码,它可以更自然地与现有的对象和类一起工作。

MobX 的核心概念包括 Observable(可观察对象,用于描述状态)、Reactions(响应式的副作用)、
Actions(修改状态的函数)和计算属性(根据当前状态自动计算派生值)等。

MobX 与 React 结合使用时,通常可以直接在 React 组件中使用 observable 状态,
并使用 @observer 装饰器来自动更新组件。

这些库都提供了一种在 React 应用中管理状态的方式,并且在实际项目中都有广泛的应用。
选择适合你项目的库取决于项目的需求、团队的经验和个人偏好

2.4 react中在父组件中如何获取子组件的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在 React 中,父组件可以通过以下几种方式获取子组件的方法:

1-使用 Refs:

在父组件中通过 ref 属性创建一个引用,并将其传递给子组件。
然后,可以使用 ref 来访问子组件的实例或 DOM 元素。

2-通过 Props 传递方法:

父组件可以通过 props 将方法传递给子组件,在子组件中调用该方法来与父组件通信。

3-通过 Context API:

父组件可以使用 React 的 Context API 来向子组件提供共享的数据或方法。
子组件可以通过 Context 来访问父组件提供的上下文数据。

这些方法都可以在父组件中获取子组件的实例、访问子组件的属性或方法,并与子组件进行通信。
根据具体的场景和需求,选择适合的方法来实现父子组件之间的交互。

2.5 低代码和微前端有了解吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
低代码(Low-Code)和微前端(Micro Frontends)是两种不同的前端开发和架构概念。

1-低代码:

低代码是一种软件开发方法,旨在通过尽可能少的手动编码来加速应用程序的开发过程。
低代码平台提供了可视化的开发工具和组件,使得开发人员可以使用拖放、配置和少量的代码来创建应用程序。
这种方法可以大大减少传统开发过程中的编码时间和技能要求,提高了开发效率和灵活性。

低代码平台通常包括可视化设计器、预构建的组件库、自动生成的代码、集成开发环境(IDE)等功能,
可以用于快速构建企业应用、移动应用、工作流程应用等各种类型的应用程序。

2-微前端:

微前端是一种架构风格,旨在将前端应用程序拆分为更小、更可管理的部分,
并通过独立开发、部署和维护这些部分来提高应用程序的可扩展性和可维护性。
微前端通过将单个应用程序拆分为多个小型、自治的前端应用(微前端),
使得团队可以独立开发和部署每个微前端,而不会影响整体应用程序的功能和性能。

微前端架构通常包括基于组件的前端框架、模块化的构建和部署系统、
独立的前端团队和项目、跨团队的协作和通信机制等。
微前端可以帮助大型组织解决单体应用程序的复杂性和扩展性问题,实现更灵活、可扩展的前端开发和运维。

虽然低代码和微前端是两种不同的概念,但它们都是为了提高前端开发效率和应用程序质量而提出的解决方案。
在不同的场景和需求下,可以根据具体情况选择适合的方法来进行前端开发和架构设计

2.6 useCallback使用过没?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
useCallback 是 React 提供的一个 Hook,用于优化函数的性能,
特别是在组件重新渲染时避免不必要的函数重新创建。
通常情况下,当父组件重新渲染时,如果传递给子组件的回调函数发生了变化,
子组件也会重新渲染,即使它的其他 props 没有变化。
这可能会导致子组件不必要的重渲染,影响性能。

使用 useCallback 可以解决这个问题,它接收一个回调函数和一个依赖项数组作为参数,
并返回一个 memoized(记忆化)的版本的回调函数。
当依赖项数组发生变化时,useCallback 将返回一个新的回调函数,否则它将返回缓存的回调函数。
这样,即使父组件重新渲染,只有依赖项数组中的值发生变化时,子组件才会重新渲染。

以下是 useCallback 的基本用法示例:

import React, { useCallback } from 'react';

const MyComponent = () => {
const handleClick = useCallback(() => {
console.log('Button clicked!');
}, []); // 空依赖数组表示这个回调函数不依赖于任何变量

return (
<button onClick={handleClick}>Click me</button>
);
};

在上面的示例中,handleClick 回调函数使用 useCallback 进行了优化,
因为它不依赖于任何变量,所以空依赖数组表示它不会因为任何变化而重新创建。
这样,即使父组件重新渲染,handleClick 回调函数也会保持稳定,不会导致子组件不必要的重渲染

2.7 函数组件和类组件处理重复渲染有什么区别?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
函数组件和类组件在处理重复渲染时有一些区别,主要体现在 React 生命周期和 Hook 的使用上:

1-类组件:

在类组件中,可以通过 shouldComponentUpdate 生命周期方法来手动控制是否需要进行重复渲染。
该方法接收 nextProps 和 nextState 作为参数,并返回一个布尔值,表示是否要执行更新。
如果 shouldComponentUpdate 返回 false,React 将不会继续执行更新流程,从而避免不必要的重复渲染。

2-函数组件:

在函数组件中,由于没有生命周期方法,不能像类组件那样手动控制是否进行重复渲染。

但是,可以使用 React 提供的一些 Hook 来优化函数组件的性能。
比如 React.memo、useMemo 和 useCallback 等 Hook 可以帮助函数组件避免不必要的重复渲染。

React.memo:用于包装函数组件,使其在 props 不变的情况下不会重新渲染。
如果 props 没有变化,则会使用 memoized 版本的组件,否则会重新渲染。

useMemo:用于在渲染过程中缓存计算结果,只有在依赖项发生变化时才会重新计算。
可以用于缓存组件渲染结果、计算昂贵的数据转换或处理等。

useCallback:用于缓存回调函数,只有在依赖项发生变化时才会返回新的回调函数。
可以用于避免在每次渲染时都重新创建回调函数,从而避免不必要的重复渲染。

总的来说,虽然函数组件和类组件在处理重复渲染时有些许区别,但通过使用 Hook(如 React.memo、useMemo 和 useCallback)和优化策略,都可以实现性能上的优化,避免不必要的重复渲染

2.8 封装的按钮权限组件怎么实现的?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
实现按钮权限组件的一般思路如下:

1-权限配置:首先,需要定义好按钮的权限配置,即哪些按钮对应哪些权限。
这些配置可以是静态的,也可以从后端动态获取。

2-权限验证:在渲染按钮组件时,需要根据当前用户的权限信息,判断该用户是否有权限访问对应的按钮。
如果用户有权限,则显示按钮;否则,隐藏按钮或者显示为禁用状态。

3-封装组件:将权限验证逻辑封装到按钮组件中,使得使用该组件时可以根据权限自动渲染按钮的显示状态。

下面是一个简单的按钮权限组件的示例实现:


import React from 'react';

const ButtonWithPermission = ({ permission, children }) => {
// 模拟获取当前用户权限的逻辑,这里假设权限信息存储在全局变量中
const userPermissions = ['view', 'edit', 'delete']; // 假设当前用户的权限信息

// 判断当前用户是否有权限访问该按钮
const hasPermission = userPermissions.includes(permission);

// 根据权限信息渲染按钮
return (
<>
{hasPermission ? (
<button>{children}</button>
) : (
<span>没有权限</span>
)}
</>
);
};

// 使用示例
const App = () => {
return (
<div>
<ButtonWithPermission permission="view">查看按钮</ButtonWithPermission>
<ButtonWithPermission permission="edit">编辑按钮</ButtonWithPermission>
<ButtonWithPermission permission="delete">删除按钮</ButtonWithPermission>
</div>
);
};

export default App;

在这个示例中,ButtonWithPermission 组件接收一个 permission 属性,用于指定按钮的权限。
根据当前用户的权限信息,判断用户是否有权限访问该按钮,并相应地渲染按钮的显示状态。
使用时,只需要将权限信息传递给 ButtonWithPermission 组件即可。

2.9 事件循环说说,宏任务和微任务有哪些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
事件循环(Event Loop)是JavaScript运行时环境中的一种机制,用于处理异步任务的执行顺序和调度。
在浏览器环境中,事件循环负责处理事件队列中的任务,确保任务按照一定的顺序执行,
从而保证程序的正确性和可预测性。

事件循环包含了两个主要的概念:宏任务(macrotask)和微任务(microtask)。

1-宏任务(macrotask):

宏任务是由浏览器提供的异步任务,比如setTimeout、setInterval、requestAnimationFrame、I/O 操作等。
宏任务会被放入宏任务队列中,事件循环会从宏任务队列中取出任务并执行,直到队列为空。

2-微任务(microtask):

微任务是在当前任务执行结束后立即执行的任务,不需要等待事件循环的下一个轮次。
微任务主要包括 Promise 的回调函数、MutationObserver 的回调函数等。
微任务会被放入微任务队列中,在当前任务执行完毕后立即执行微任务队列中的所有任务,然后再执行宏任务队列中的任务。

事件循环的执行顺序如下:

首先执行当前的宏任务(如执行一段同步代码)。
当前宏任务执行完毕后,执行微任务队列中的所有微任务。
执行完微任务后,检查是否有新的宏任务加入队列,如果有,则执行新的宏任务。
重复以上步骤,直到宏任务队列和微任务队列都为空。
在每一次事件循环中,微任务的优先级高于宏任务,即微任务会优先于宏任务执行。
这意味着在当前宏任务执行完毕后,会优先执行微任务队列中的任务,然后再执行下一个宏任务。

总的来说,事件循环是 JavaScript 异步编程的核心机制之一,
理解事件循环对于理解 JavaScript 异步编程非常重要。
通过合理地利用宏任务和微任务,可以实现更高效、更可靠的异步代码。

2.10 方法什么时候写在父组件里,什么时候写在子组件中?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
决定将方法写在父组件还是子组件中,通常取决于方法的作用范围和复用性:

1-写在父组件中的情况:

当方法需要被多个子组件共享时,可以将方法写在父组件中,然后通过 props 将方法传递给子组件。
如果方法涉及到多个子组件之间的状态管理或数据传递,
可以将方法提升到共同的父组件中,以便更好地管理状态和数据流。

2-写在子组件中的情况:

当方法只在当前子组件内部使用,并且不需要被其他子组件访问时,可以将方法写在子组件内部。
如果方法与特定的 UI 功能或行为密切相关,并且不需要在其他地方复用,
可以将方法定义在需要使用的子组件中,以提高代码的可读性和可维护性。

3-注意事项:

如果方法涉及到状态管理或数据流管理,应该考虑将其写在具有状态管理能力的组件
(如类组件或使用 Hook 管理状态的函数组件)中,以确保数据的一致性和可控性。
避免过度封装或过度耦合,应根据功能的独立性和复用性来决定方法的位置,尽量保持组件的简洁和清晰。

总的来说,将方法写在父组件或子组件中是一种根据实际情况进行权衡的选择,
应该根据具体的需求和项目的架构来决定方法的位置。

三 图片

四 参考

  • ChatGPT3.5