4 月 24 号面试题
深圳中科德能(复试)
1. 什么是 React?
React
- 基于状态的声明式渲染
- 支持组件化开发
React 是用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案。
遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效。
使用虚拟 DOM 来有效的操作 DOM,遵循从高阶组件到低阶组件的单向数据流。
将页面划分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌入,构成整体页面。
react 类组件使用名为 render() 的方法或者函数组件 return,接收输入的数据并返回需要展示的内容。
2. React 中的状态
状态(state):React 组件的可变数据,用于存储组件内部的状态信息。状态可以通过 setState 方法进行更新,并且只能在组件内部访问和修改。
3. React 中的 props
是 React 组件的外部输入,用于传递数据和配置信息给组件。属性是可变的,只能由父组件传递给子组件,子组件不能直接修改父组件传递的属性。
4. 受控组件和非受控组件
受控组件:是由 React 控制并管理其内部状态的组件。它的状态通过 props 传递给子组件,并通过事件处理程序进行更新。受控组件提供了更精确的控制和验证,但需要更多的代码来处理状态更新。
非受控组件:是由组件本身管理其内部状态的组件。它的状态通常通过 ref 从 DOM 获取,并且不依赖于 React 来处理状态的更新。非受控组件通常在处理表单和第三方 DOM 集成时使用。
5. React 中的合成事件
React 合成事件是指将 原生事件合成一个 React 事件,之所以要封装自己的一套事件机制,目的是为了实现全浏览器的一致性,抹平不同浏览器之间的差异性。比如原生 onclick 事件对应 React 中的 onClick 合成事件。
onclick => onClick;
onfoucs => onFoucs;
onblur => onBlur;
更多文章:浅谈 React 合成事件
6. React 中 key
识别每个列表项的唯一性,提高列表更新的性能,保持元素的稳定性
React 可以根据 key 来跟踪列表中的每个元素,从而准确的识别出每个元素需要进行什么样的渲染,是新添加的还是删除的,是已存在的还是已删除的。
7. React 中的虚拟 DOM
虚拟 DOM 最早是由 React 团队提出来的,是一种编程思想,指的是针对真实 UI DOM 的一种描述能力。在 React 中,使用了 JS 对象来描述真实的 DOM 结构。虚拟 DOM 和 JS 对象之间的关系:前者是一种思想,后者是一种思想的具体实现。
在 React 中通过 JSX 来描述 UI,JSX 仅仅是一个语法糖,会被 Babel 编译为 createElement 方法的调用。该方法调用之后会返回一个 JSX 对象,该对象就是虚拟 DOM 对象,官方更倾向于称之为一个 React 对象。
优点: 减少实际的 dom 操作 批量更新 跨平台的兼容性 更好的开发体验
8. 什么是高阶组件
高阶组件是一种函数,接受一个组件作为参数并返回一个新的组件。高阶组件可以用于封装通用的逻辑和行为,以便在多个组件中重复使用。
可以用于实现组件的复用、逻辑的抽象和代码的组合
9. 常用的 hooks
10. useEffect 可以接受哪些参数,分别有什么作用?
方式一:useEffect(effect, [deps])
effect:一个回调函数,在组件挂载、更新和卸载时执行。
deps:一个数组,指定 effect 的依赖项。当依赖项发生变化时,effect 会重新执行。
11. ref 的作用
ref 是用于访问组件或 DOM 元素的方法
- 访问组件实例:通过 ref 可以获取到组件的实例,从而可以直接调用组件的方法或访问组件的属性。
- 访问 DOM 元素:通过 ref 可以获取到 DOM 元素。从而直接操作 DOM。
使用场景: 处理焦点、文本控制或媒体控制 触发强制动画 集成第三方 DOM 库
12. input 聚焦的方法是否可以用 ref 实现
可以
13. 深浅拷贝是什么?怎么实现深拷贝?
浅拷贝:
浅拷贝是指创建新的数据,这个数据有着原始数据属性值的一份精确拷贝
如果属性是基本数据类型,拷贝的是值,如果是引用数据类型,拷贝的是内存地址
浅拷贝是拷贝一层,深层次的引用数据类型则共享内存地址
深拷贝:
深拷贝开辟一个新的栈,两个对象属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
实现深拷贝的方法:
JSON.parse(JSON.stringify(obj))
lodash 的 cloneDeep 方法
手动遍历对象或数组,逐个赋值(循环递归)
14. 怎么样有条件的渲染组件
- 方式一:和 js 中一样是用 if else 语句。
function MyComponent() {
const isLogin = Math.random() > 0.5;
if (isLogin) {
return <div>已登录</div>;
} else {
return <div>未登录</div>;
}
}
- 方式二:使用 && 与运算符
isLogin && <div>已登录</div>;
- 方式三:使用三目运算符 ?:
isLogin ? <div>已登录</div> : <div>未登录</div>;
- 方式四:使用元素变量
function LoginButton(props) {
return <button onClick={props.onClick}>Login</button>;
}
function LogoutButton(props) {
return <button onClick={props.onClick}>Logout</button>;
}
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = { isLoggedIn: false };
}
handleLoginClick() {
this.setState({ isLoggedIn: true });
}
handleLogoutClick() {
this.setState({ isLoggedIn: false });
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<LoginControl />);
15. 什么是解构
解构赋值语法是一种 JavaScript 表达式。可以将数组中的值或对象中的属性取出,赋值给其他变量。
16. 什么是动态导入
动态导入是 JavaScript ES10 中新增的语法特性。它可以通过将代码按需导入,从而实现更加高效的加载方式。动态导入允许用户在运行时动态的加载所需模块,而不是将所有的模块一次性的加入。这是 ES6 中静态导入所无法实现的。
静态导入:静态 import 语句用于导入由另一个模块导出的绑定。无论是否声明了严格模式,导入的模块都运行在严格模式下。在浏览器中,impport 语句只能使用在声明了
type=module
的 script 标签中。
17. react 常用的库
Ant Design
18. 怎么实现响应式布局
媒体查询 @media()
使用流式布局,通过设置百分比
弹性布局,设置 display: flex;
19. 什么是闭包
闭包是指引用了另一个函数作用域中变量的函数。通常是在嵌套函数中实现的。闭包可以保留其被定义时的作用域,这意味着闭包内部可以访问外部函数的局部变量,即使外部函数已经执行完毕。 如果不注意管理,可能会导致内存泄露问题
内存泄漏是指应用程序中的内存不再使用但仍然被占有,导致内存消耗逐渐增加,最终可能导致应用程序性能下降或崩溃。也就是,程序对内存失去控制。
20. 箭头函数 和 function 函数
箭头函数是 ES6 引入的一种函数声明方式,它具有更短的语法和词法作用域
区别:
- 箭头函数都是匿名函数,普通函数可以是匿名函数,也可以是具名函数
- 普通函数的 this 是指向调用它的对象,箭头函数没有自己的 this,它会在声明时捕获其所在上下文 this 以供自己使用
- 箭头函数不能做构造函数,箭头函数没有 constructor,不能使用 new 关键字,没有 arguments 参数
21. 怎么批量更新状态
React 通过合成事件来完成批量更新。也就是对我们写的事件处理函数或者生命周期函数进行了二次封装,在函数调用之前加入了一个变量:isBatchingUpdate=true,代表为批量处理和更新。然后在函数调用完成后重置为 false。
如果事件处理函数里面带有微任务或者宏任务,因为是在事件处理函数执行完成之后再去执行的,这时批量更新的状态 isBatchingUpdate 已经是 false 了,所以里面的更新是理解更新且不是批量的。
做合成事件的另一个作用是为了处理浏览器的兼容
22. Promise 请求顺序执行,请求数量不固定
使用 async 和 awiat 实现
23. Promise 是什么?怎么使用?
Promise 是 JavaScript 中处理异步操作的一种模式和对象。它代表了一个异步操作的最终完成或失败,并允许在异步操作完成后执行相关的代码。它可以通过链式调用 .then() 方法来处理回调嵌套的问题。
new Promise(resolve, reject)
Promise.resolve()
24. async/await
async/await 是 ES6 的异步处理方式,它允许使用类似同步代码的方式来处理异步操作。async 函数返回一个 Promise,运行在函数内使用 await 关键字等待异步操作完成。
25. 在普通组件可以使用 async/await 吗
不可以
26. 怎么在 React 中创建事件
这道题中的“创建”我理解的是,如果在 React 中声明一个事件,而非原生的 CustomEvent 自定义事件的创建与触发,因为这在 React 中存在的意义不大。 React 中事件是直接绑定在标签上的,如果是 HTML 原生标签,则可以用 on 前缀,后加事件类型的形式进行声明,用的是小驼峰的命名,如<div onClick={this.handleClick}></div>;
需要注意的是,在类组件中的事件函数要注意 this 的绑定,可以在 JSX 中绑定,可以在 constructor 中绑定,可以用 public class field 的语法让事件中的 this 指向组件实例,推荐后两种方式.
20. 什么是类组件和函数组件
类组件:
通过继承 React.Component 类来定义组件
可以包含自己的状态(state)和生命周期方法
可以使用 this 关键字来访问组件的状态和 props
可以使用 ref 来访问 DOM 元素或子组件
可以使用 setState 方法来更新组件的状态,触发组件的重新渲染
通常用于复杂的组件,需要管理自己的状态和响应生命周期事件
函数组件:
通过函数来定义组件,接收 props 作为参数,返回 JSX 对象
没有自己的状态和生命周期方法
不能使用 this 关键字来访问组件的状态和 props
通常用于简单的展示组件,只关注 UI 的呈现和展示,不需要管理状态和响应生命周期事件
React 的 hook 解决了什么问题
Component 非 UI 逻辑复用困难
组件的生命周期函数不适合 side effect 逻辑
旨在解决函数组件无法存在内部状态、提供完整生命周期的问题
(一面)
1. 什么是盒子模型,有哪几种盒模型
盒模型就是定义了元素周围的一个区域,这个盒子由四部分组成:内容(content)、内边距(padding)、边框(border)和外边距(margin)。盒模型可以分为两种盒模型:W3C 盒模型和 IE 盒模型(标准盒模型和怪异盒模型)。
区别在于盒子的宽高是否包括元素的边框和外边距:IE 盒模型的宽高包括了内边距和边框,而 W3C 盒模型没有包含
2. 块盒跟行盒
块盒:
独占一行,从上到下顺序垂直排列 可以设置宽高、内外边距,并且会自动换行 会产生换行,width 和 height 属性可以发挥作用
如 <h1>
, <p>
, <div>
等
行盒: 不会独占一行,在同一水平排列,直到一行不足以容纳它们,然后换行 不会产生换行,width 和 height 属性不起作用,尺寸由内容决定
如 <span>
, <a>
, <em>
, <strong>
等
3. 三栏布局的实现方式
flex 弹性布局 float 浮动布局 grid 网格布局 position 绝对定位布局
4. 数组常用的方法
push:添加数据到数组末尾 unshift:在数组开头添加数据 splice:删除数组中的数据,传入三个参数,分别是开始位置,要删除的元素数量,插入的元素,对原数组产生影响 concat:合并数组
pop:删除数组的最后一项 shift:删除数组的第一项 slice:截取数组的一部分,生成新的数组,不改变原数组
indexOf:查找元素在数组中的位置,返回索引值,没有返回 -1 includes:元素是否存在在数组中,找到了返回 true,没有则 false find:返回第一个匹配的元素
reverse:反转数组,改变原数组 sort:排序数组,改变原数组
join:使用字符串分割符分割数组,返回字符串
filter:数组过滤 map:遍历数组,返回新数组 forEach:遍历数组,不改变原数组
5. 前端的加密方式
- md5 加密
加密位数由两种:16 位和 32 位,一般使用 32 位加密。
base64 加密
res 加密
使用 jsencrypt 库
RSA 加密 非对称加密 用公钥加密,私钥解密
6. 判断数据类型的方法
7. 深浅拷贝?怎么实现深拷贝
8. 本地存储方法有哪些?项目中的使用场景有哪些
Cookie:用于在 web 中维护状态和用户身份,可以存储一些信息,主要目的是为了解决 Http 协议无状态的问题 具有持久性,可以设置过期时间 存储数据量小,一般在 4k 左右 存储在客户端,不太安全 每次请求会携带 cookie
WebStorage:localStorage 和 sessionStorage
localStorage: 存储在 5M 左右 键值对存储,数据以字符串形式存储 数据永久保存
sessionStorage: 存储在 5M 左右 键值对存储,数据以字符串形式存储 数据在会话期间有效,关闭浏览器或会话窗口,数据会被删除
IndexedDB: 存储量大 数据持久 支持更复杂的数据模型,可以存储结构话数据,如对象、数组等
9. 数字精度丢失
计算机将数据存储为二进制
计算机的存储是有限的,但是对于无限循环的小数点是无法全部存下的,它会存储一个近似值,这样也就造成了精度丢失。
toPrecision:返回一个字符串,表示一个数字的指定精度的近似值
解决思想:将小数先转换两个字符串,然后计算小数部分的字符串长度,利用这个长度将小数变成整数
可以使用第三方库:
Decimal
x = new Decimal(0.1);
y = x.plus(0.2);
bignumber
x = new BigNumber(0.1);
y = x.plus(0.2);
toFixed parseFloat parseInt
10. 什么是防抖和节流?项目中的案例
防抖:n 秒后执行事件,在 n 秒内被重复处罚,则重新计时 节流:以 n 秒进行一个阻隔,事件触发后,n 秒内重新触发,不执行新的事件
11. 父子组件通信方法
props:父组件向子组件传递数据,子组件通过 props 接收数据
12. 什么是类组件,什么是函数组件
13. 什么是高阶组件
14. 什么是受控组件,什么是非受控组件
15. React 常用的 hook
16. hook 解决了什么问题
17. 项目中使用了哪些中间件?状态管理的
react-redux