面试题3333

1.props和state相同点和不同点?render 方法在哪些情况下会执行?
props和state是React组件中用于存储和管理数据的两个重要概念。

相同点:

    1.都是用于存储组件的数据。

    2.当数据更新时,都会触发组件从新渲染。

不同点:

    1.来源:props是由父组件传递给子组件的,而state是组件自身进行管理的。

    2.可变性:props是只读的,不能再子组件中直接修改,而state可以通过setState方法进行修改

    3.更新方式:props的更新是由父组件控制,而state的更新由组件自身控制。

render方法在以下情况下会执行:

    1.组件首次挂载在页面上时,会执行一次render方法进行一次渲染。

    2.当组件的props或state发生变化时,render方法会重新调用进行渲染。

    3.当父组件重新渲染时,包含的子组件也会相应的重新渲染,子组件的render也会被调用

    4.在使用React Router等路由库时,路由的切换也会导致组件重新渲染。

2.说说你对Object.defineProperty()的理解
Object.defineProperty() 是 JavaScript 中用来定义对象属性的方法。它允许我们定义或修改对象的属性特性(如可写、可枚举、可配置等)以及属性值。

Object.defineProperty(obj, prop, descriptor)
其中,obj 是要定义属性的对象,prop 是要定义或修改的属性名,descriptor 是一个描述符对象,用于定义或修改属性的特性。

描述符对象 descriptor 可以包含以下可选的属性:

value: 设置属性的值。
writable: 如果为 true,属性的值可以被修改;默认为 false。
enumerable: 如果为 true,属性可以通过 for…in 或 Object.keys() 枚举;默认为 false。
configurable: 如果为 true,属性的特性可以被修改,也可以被删除;默认为 false。
get: 一个函数,在访问属性时被调用,返回属性的值。
set: 一个函数,在设置属性值时被调用。
使用 Object.defineProperty() 可以实现以下功能:

定义新属性:通过传递具有相应特性的 descriptor 对象,可以定义新的属性并赋予初始值。
修改属性特性:如果对象已经存在该属性,可以通过传递修改后的 descriptor 对象来修改属性的特性,如可写性、可枚举性和可配置性。
创建只读属性:将 writable 特性设置为 false,可以创建只读属性,后续的赋值操作将被忽略。
创建访问器属性:通过指定 get 和 set 方法,可以创建访问器属性,它们在读取和写入属性时会触发相应的函数。
3.说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系?
在 React 中,虚拟 DOM(Virtual DOM)是一种以 JavaScript 对象的形式表示真实 DOM 树的概念。它是为了提高性能而引入的一种优化手段。

虚拟 DOM 是 React 在更新页面时的重要机制。当状态发生变化时,React 会重新计算整个虚拟 DOM 树,然后将之前的虚拟 DOM 树与新计算的虚拟 DOM 树进行比较,找出差异,并最终只更新差异部分对应的真实 DOM。这样可以避免直接操作真实 DOM 导致的性能问题,使得页面更新更加高效。

在虚拟 DOM 计算过程中,diff 算法和 key 属性之间有一定的关系:

diff 算法用于比较两棵树的差异。当新旧虚拟 DOM 树进行比较时,如果节点类型、属性或顺序发生变化,diff 算法会标记这些变化,然后将其应用到真实 DOM 树上。通过 diff 算法可以减少对真实 DOM 的操作次数,从而提高性能。
key 属性是为了给虚拟 DOM 的每个节点分配一个唯一标识符。在新旧虚拟 DOM 进行比较时,React 使用 key 属性来判断某个节点是否是同一个节点。通过 key 属性,React 可以快速定位并更新相应的节点,避免重新创建和销毁节点,提高页面更新的效率。
具体来说,key 属性在虚拟 DOM 比较中的作用如下:

提供唯一标识符:每个列表项或动态生成的元素都需要一个唯一的 key 值,这样 React 才能准确地判断哪些节点发生了变化。
优化更新策略:当列表项顺序发生变化或新旧列表项不一致时,React 可以通过 key 值快速定位节点差异,避免全量比较,提高更新效率。
节点复用:使用 key 值可以保证在列表中移动节点时不会导致节点的重新创建和销毁,从而节省开销。
4.react新出来两个钩子函数是什么?和删掉的will系列有什么区别?
在 React 中,新增的两个钩子函数是 useEffect 和 useLayoutEffect。这两个钩子函数可以用于处理组件的副作用操作和生命周期相关的逻辑。

useEffect

作用:useEffect 用于执行副作用操作,例如订阅事件、请求数据、处理 DOM 操作等。
触发时机:useEffect 在每次渲染后都会执行,包括首次渲染和每次更新。
默认行为:useEffect 中定义的副作用操作是异步执行的,不会阻塞页面渲染。
注意事项:可能会导致延迟执行,不适用于需要立即同步执行的操作。
useLayoutEffect

作用:useLayoutEffect 也用于执行副作用操作,但其调度优先级和时间点与 DOM 更新同步。
触发时机:useLayoutEffect 在浏览器执行绘制之前同步执行,即在 DOM 更新前触发。
默认行为:useLayoutEffect 中定义的副作用操作是同步执行的,并会阻塞页面渲染。
注意事项:需要考虑副作用操作对页面渲染性能的影响,在此钩子中执行耗时操作可能导致页面卡顿。
相比于被删除的 will 系列生命周期函数(如 componentWillMount、componentWillUpdate 等),新增的钩子函数有以下区别:

触发时机:will 系列生命周期函数在组件的生命周期中具有特定的触发时机,而钩子函数可以在每次渲染后都执行。
代码分离:使用钩子函数,副作用操作可以更好地与相关逻辑代码分离,使组件更加清晰和易于维护。
异步执行:useEffect 默认异步执行副作用操作,而 will 系列生命周期函数是同步执行的。
性能影响:由于 useLayoutEffect 在 DOM 更新前同步执行,可能会对页面渲染性能产生影响。因此,在使用 useLayoutEffect 时需要谨慎处理,避免造成性能问题。
5.React的props.children使用map函数来遍历会收到异常显示,为什么?应该如何遍历
当使用 map 函数遍历 props.children 时,需要注意以下几点可能导致异常显示的原因:

非数组类型的 props.children:如果 props.children 不是一个数组类型,而是一个单个元素或者是 null,则 map 函数无法正确工作。因为 map 函数仅适用于数组类型数据的遍历。

未处理 key 错误:在使用 map 函数遍历 props.children 时,必须为每个生成的元素提供一个唯一的 key 属性。如果没有为遍历的子元素提供 key,React 会给出警告信息。确保为每个遍历的子元素提供唯一的 key。

无效的子元素类型:有时 props.children 可能包含非 React 组件(例如字符串、数字等)或者是虚拟 DOM 元素(例如 Fragments),直接对这些非 React 组件应用 map 函数会导致异常。在遍历之前,可以使用 React.Children 工具函数中的 toArray 方法将子元素转换为数组。

为了正确地遍历 props.children,可以使用以下方法:

将 props.children 转换为数组:使用 React.Children.toArray() 将 props.children 转换为数组形式,以确保可以正确遍历。

为遍历的元素提供唯一的 key:在遍历时,为每个生成的元素提供一个唯一的 key 属性。可以使用数组索引作为 key,但最好使用稳定的唯一标识符。

import React from “react”;

const MyComponent = (props) => {
const childrenArray = React.Children.toArray(props.children);

return (


{childrenArray.map((child, index) => (
{child}

))}

);
};

export default MyComponent;

6.ts中抽象类的理解?
在 TypeScript 中,抽象类(Abstract Class)是一种特殊类型的类,它用于作为其他类的基类,并且不能直接被实例化。抽象类可以包含抽象方法、非抽象方法和属性。

抽象类通过 abstract 关键字进行声明,使用抽象方法和抽象属性对功能进行建模,而具体的实现则延迟到继承的子类中。抽象类的主要目的是为了定义共享的行为和约束,以及提供一个通用的接口,子类必须根据需求来实现抽象类中定义的抽象方法。

以下是对抽象类的一些理解:

不能实例化:抽象类不能直接实例化,只能继承使用。即使抽象类中没有抽象方法,也不能通过 new 关键字创建抽象类的实例。

包含抽象方法:抽象类可以包含抽象方法,抽象方法没有具体的实现,只有方法签名。抽象方法使用 abstract 关键字声明,并且必须在派生类中被实现。

可以有具体的实现:抽象类可以包含非抽象方法和具体的属性实现。这些方法和属性可以直接在抽象类中定义,并且可以在派生类中继承或者覆盖。

作为基类:抽象类经常用作其他类的基类,它提供了一种模板或蓝图的概念,子类需要实现抽象类中定义的抽象方法来完成自己的功能。

强制实现:抽象类可以强制子类实现一些特定的方法,从而确保子类具有一致的行为接口。如果子类没有实现抽象类中的抽象方法,TypeScript 编译器会报错。

可以被继承:抽象类本身可以继承其他抽象类,这样就可以形成一个继承层次结构。

8.redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的 实现原理是什么?
Redux 最初设计为同步的状态管理库,但在实际开发中,异步操作(如网络请求)是非常常见的需求。为了支持异步操作,Redux 可以通过中间件来扩展其功能,实现异步代码的执行。

中间件是 Redux 的扩展机制,它可以拦截和处理 Redux 的 action,提供额外的逻辑处理能力。通过中间件,可以在 action 被派发到 reducer 之前或之后执行自定义的代码,包括异步操作。

Redux 异步代码的执行原理如下:

在传统的 Redux 中,当派发一个 action 时,该 action 会直接发送给 reducer 进行状态更新。
引入中间件后,当派发一个 action 时,中间件可以先拦截这个 action,进行一些额外的处理,例如发起异步请求,再决定是否将 action 继续发送给 reducer。
中间件可以在异步操作完成后,创建一个新的 action 并将其发送给 reducer,从而更新状态。
常用的 Redux 异步中间件有 Redux Thunk、Redux Saga 和 Redux Observable 等。它们的实现原理略有不同:

Redux Thunk:Thunk 中间件允许 action 创建函数返回一个函数而不是一个普通对象。这个返回的函数可以在内部进行异步操作,并且可以在操作完成后手动派发一个新的 action 给 reducer。Redux Thunk 使用了函数柯里化来实现这一功能。

Redux Saga:Saga 是一个通过 Generator 函数来处理异步操作的中间件。它会监听指定的 action,并在匹配到相应的 action 时执行特定的异步操作,例如发起 API 请求。Saga 使用了 ES6 的 Generator 函数和 yield 关键字,以及 redux-saga 库提供的效果(effect)来实现异步操作的控制流程。

Redux Observable:Observable 是一个用于处理异步操作的概念。Redux Observable 中间件使用 RxJS 库来实现,它将 action 流转换成一个可观察对象,然后利用 RxJS 的操作符来处理异步操作,最终将结果派发给 reducer。

9.redux中同步action与异步action最大的区别是什么?
同步 action: 同步 action 是指在 Redux 中被派发并立即执行的 action。它是一个普通的 JavaScript 对象,包含一个 type 字段来描述 action 类型,并可以附带其他的数据字段。同步 action 主要用于描述需要立即进行的操作,例如更新状态或触发一些简单的计算。同步 action 的执行是立即的,不涉及任何异步操作。
异步 action: 异步 action 是指在 Redux 中被派发但不立即执行的 action。它通常用于处理需要进行异步操作的场景,如发送网络请求、获取数据等。与同步 action 不同,异步 action 可能会经历多个阶段,例如发送请求、等待响应、处理响应等。常见的处理异步操作的方式是使用中间件(如 Redux Thunk 或 Redux Saga)来处理异步 action。
10.redux-saga和redux-thunk的区别与使用场景?
Redux-Saga 和 Redux-Thunk 是两个常用的 Redux 中间件,用于处理异步操作和副作用。它们在处理异步逻辑的方式、语法和使用场景上有一些区别。

Redux-Thunk: Redux-Thunk 是 Redux 的默认中间件之一。它通过允许 action 创建函数返回一个函数而不是一个普通的 action 对象来处理异步操作。这个返回的函数接受 dispatch 方法作为参数,可以在函数内部进行异步操作,并根据需要派发其他的 action。
Redux-Thunk 的使用场景主要包括简单的异步操作,如发送网络请求或定时器等。它的优点在于简单易用,语法相对简单,非常适合处理一些基本的异步场景。

    2.Redux-Saga: Redux-Saga 是一个功能强大的 Redux 中间件,它使用了 ES6 的 Generator 函数来处理异步逻辑。通过创建 Sagas(Generator 函数),Redux-Saga 可以让我们以一种声明式的方式处理复杂的异步操作和副作用。

Redux-Saga 的使用场景主要包括更复杂的异步场景,例如处理连续的、有条件的异步操作、取消异步操作、处理 WebSocket 连接等。它的优点在于具有灵活性和可测试性,可以更好地管理和控制应用程序中的异步流程。

11.在使用redux过程中,如何防止定义的action-type的常量重复?
在 Redux 中,定义 action-type 的常量是一个常见的做法,以确保 action-type 的唯一性。避免定义的 action-type 常量重复可以采取以下几种方式:

使用独立的文件或模块:将 action-type 的常量定义放在单独的文件或模块中,并导出这些常量供其他地方使用。这样可以确保常量的定义集中管理,减少重复定义的可能性。
例如,可以创建一个名为 ActionTypes.js 的文件,将所有的 action-type 常量定义在其中:

export const FETCH_DATA_REQUEST = ‘FETCH_DATA_REQUEST’;
export const FETCH_DATA_SUCCESS = ‘FETCH_DATA_SUCCESS’;
export const FETCH_DATA_FAILURE = ‘FETCH_DATA_FAILURE’;
// 其他常量定义…
然后,在需要使用这些常量的地方,通过导入来引用它们:

import { FETCH_DATA_REQUEST, FETCH_DATA_SUCCESS } from ‘./ActionTypes’;
2.使用辅助函数生成常量:可以编写一个辅助函数,用于生成唯一的 action-type 常量。这样可以在定义 action-type 常量时避免手动输入,减少了人为错误的可能性。

例如,可以创建一个名为 createActionType 的辅助函数:

const createActionType = (prefix, name) => ${prefix}/${name};

// 使用示例
const FETCH_DATA_REQUEST = createActionType(‘DATA’, ‘FETCH_REQUEST’);
const FETCH_DATA_SUCCESS = createActionType(‘DATA’, ‘FETCH_SUCCESS’);
const FETCH_DATA_FAILURE = createActionType(‘DATA’, ‘FETCH_FAILURE’);
3.使用第三方库:还可以使用第三方库来帮助管理 action-type 的常量。这些库提供了更高级的功能,例如自动生成唯一的常量、定义多个常量等

    例如,redux-actions 是一个流行的 Redux 工具库,它提供了 createAction 函数来创建 action,并自动为它生成唯一的常量。

12.CDN的特点及意义?
CDN(Content Delivery Network,内容分发网络)是一种广泛应用于互联网的技术架构,它通过部署在全球各地的边缘节点服务器来提供高效快速的内容传输和分发服务。CDN 的特点和意义如下:

提高访问速度和用户体验:CDN 可以将内容缓存到离用户最近的边缘节点服务器上,当用户请求访问内容时,可以从最近的服务器返回内容,减少了数据传输的延迟和网络拥塞,大大提高了网页加载速度和用户访问体验。

降低网络负载:CDN 的分布式架构可以将流量分散到不同的服务器上,分担了源站服务器的负载压力。这样可以降低源站服务器的带宽使用和硬件性能需求,提高源站服务器的稳定性和可靠性。

提高容错和可用性:CDN 分布在全球范围的边缘节点服务器之间相互镜像和同步内容,当某个节点服务器出现故障时,其他节点可以接替其服务,保证内容的可用性和持续访问。

应对突发流量和大规模并发:CDN 可以根据用户的地理位置、网络状况和访问需求,动态调整内容分发策略,使得流量能够智能地被导向最优的节点服务器,应对突发的大规模并发请求,确保网络的稳定性和可扩展性。

提供安全防护和加密传输:CDN 可以实施一些安全措施,保护网站免受恶意攻击和网络威胁。例如,通过缓存和代理服务器来过滤非法请求和恶意流量,提供 HTTPS 加密协议,增强数据传输的安全性。

13.为什么for循环比forEach性能高?
在讨论 for 循环和 forEach 的性能差异时,需要考虑一些因素。

遍历速度:for 循环通常比 forEach 循环快,原因是 for 循环是基于索引的循环,通过使用索引直接访问数组元素,而 forEach 循环需要迭代整个数组并对每个元素调用回调函数。相比之下,使用索引访问数组元素的操作更加高效。

回调函数调用开销:forEach 循环中的回调函数每次循环都会被调用,这可能会导致执行上下文的创建和销毁,以及函数调用的开销。而 for 循环没有这个额外的开销,只是简单地执行指定的循环体。

可中断性:for 循环具有更多的控制性,可以使用 break、continue 等关键字来中断或跳过特定的迭代。而 forEach 循环在内部调用回调函数时无法中断,即使在回调函数中使用了 return 语句也只是跳出了当前回调函数,并不能中断整个迭代过程。

需要注意的是,性能差异并不总是明显的,而且在大多数情况下,两者之间的性能差异可能是微小的,难以察觉。因此,在实际开发中,应该根据具体的需求和上下文选择合适的循环方式,而不仅仅考虑性能因素。

14.redux实现原理?

Redux 是一个用于管理应用程序状态的JavaScript库。它的实现原理可以分为以下几个关键概念:

状态(State):Redux 的核心是一个单一的状态树(state tree),即应用程序的所有状态被存储在一个对象中。这个状态对象是只读的,不能直接修改,只能通过发起一个动作(Action)来描述状态的变化。

动作(Action):动作是一个包含 type 字段的普通 JavaScript 对象,它描述了发生的事件或用户行为。通过 dispatch 函数将动作发送到 Redux,Redux 会根据动作的类型来更新状态。

修改器(Reducer):修改器是一个纯函数,它接收当前状态和一个动作作为参数,并返回一个新的状态。它负责根据动作的类型来修改状态树。Redux 中的修改器需要遵循 “无副作用” 的原则,即不应该修改传入的状态对象,而是要返回一个新的状态对象。

存储(Store):存储是将状态、动作和修改器联系在一起的对象。它有以下职责:

持有状态树
提供 getState 方法获取当前状态
提供 dispatch 方法用于派发动作
注册修改器函数,以响应动作并更新状态
订阅(Subscribe):通过 subscribe 方法,可以注册一个监听函数,当状态发生变化时,Redux 会自动调用这个监听函数。

整个 Redux 的数据流向如下:

应用程序通过调用 store.dispatch(action) 发起一个动作。
Redux 的存储接收到动作并将其转发给修改器。
修改器根据动作的类型和当前状态来生成新的状态。
Redux 存储更新状态,并触发订阅函数。
订阅函数被调用,应用程序可以通过 store.getState() 获取新的状态,然后进行相应的更新。
15.React render方法的原理,在什么时候会触发?
React 的 render 方法是用于生成虚拟 DOM(Virtual DOM)并进行渲染的核心方法。它的原理和触发时机如下所述:

原理:

render 方法接收到组件的状态和属性作为输入。
它会根据输入的状态和属性生成一个新的虚拟 DOM 树(Virtual DOM Tree)。
React 会将新的虚拟 DOM 树与之前的虚拟 DOM 树进行比较,找出差异(Diffing)。
根据差异,React 会更新真实 DOM,只修改需要改变的部分,从而最小化 DOM 操作的开销。
触发时机:

当组件的状态(state)发生变化时,会触发 render 方法重新渲染组件。
当组件的属性(props)发生变化时,也会触发 render 方法重新渲染组件。
当父组件的 render 方法被调用并返回新的虚拟 DOM 时,子组件的 render 方法也会被触发。
需要注意的是,React 在处理多个 setState 调用或父组件的 render 调用时可能会对 render 方法进行合并和批处理,以优化性能。因此,并不是每次状态或属性的变化都会立即触发 render 方法的执行,而是在适当的时机进行批量更新。

此外,对于函数组件(Function Components),render 方法实际上是函数组件本身,而不是类组件中的实例方法。每当函数组件被调用时,render 方法会被执行并返回虚拟 DOM,然后交由 React 进行渲染和更新。

16.谈谈你是如何做移动端适配的?
在移动端适配中,常用的方法包括使用响应式设计、媒体查询、视口设置和使用 REM 或者百分比单位等。下面是我介绍的一种常见的移动端适配方案:这样的设置可以让网页根据设备的宽度自动进行缩放,以适应不同的屏幕大小。

1.使用视口设置:通过设置 标签中的 viewport 属性来控制网页在移动设备上的显示效果

2.使用媒体查询:媒体查询是CSS3中的一个功能,它能够根据设备的特性(如屏幕宽度、高度、颜色、分辨率等)来应用不同的样式。通过响应不同的媒体查询规则,可以根据设备屏幕的大小和方向来选择合适的样式。

3.使用 REM 或百分比单位:相对单位可以根据根元素的字体大小或父元素的尺寸进行相对计算,适应不同的屏幕尺寸。其中,REM 单位相对于根元素(通常是 标签)的字体大小设置,而百分比单位相对于父元素的尺寸设置。

17.移动端1像素的解决方案?
在移动端开发中,由于设备像素和物理像素的差异,经常会遇到在高像素密度的屏幕上显示1像素边框或线条模糊或变粗的问题。为了解决这个问题,可以采用以下几种方案:

使用 CSS 缩放:通过将元素的尺寸放大相应的倍数,然后通过 CSS 缩放将其还原到正常大小。例如,将一个1像素的边框放大到2倍,然后使用 transform: scale(0.5) 将其缩小回来。这样在高像素密度屏幕上显示的就是真正的1像素边框。

使用伪元素和背景渐变:通过创建伪元素,并利用线性渐变背景来模拟1像素边框的效果。通过调整背景渐变的尺寸和方向,可以实现细线条的效果。

使用第三方库:有一些专门用于解决移动端1像素问题的第三方库,例如 border.css、postcss-plugin-1px2rem 等。这些库可以简化开发流程,提供便捷的1像素解决方案。

18.弹性盒中的缩放机制是怎样的
弹性盒布局(Flexbox)中的缩放机制是指在容器内部如何分配和调整弹性子项的尺寸。弹性盒布局通过指定容器和子项的属性来实现灵活的布局和自适应的缩放。

以下是弹性盒布局中的主要缩放机制:

主轴尺寸分配:弹性容器具有一个主轴和一个交叉轴。根据在容器上设置的 flex-direction 属性,主轴可以是水平或垂直方向。在主轴上,容器根据子项的设置来分配可用空间。子项的 flex-grow 属性决定了子项在主轴上的拉伸能力,即它们是否可以增加尺寸以填充容器的空白区域。如果子项具有相同的 flex-grow 值,则它们会平均分配剩余的空间。如果某个子项的 flex-grow 值为0,则该子项不会增加尺寸。

子项尺寸调整:在弹性盒布局中,子项的尺寸可以根据需要进行调整。子项的 flex-shrink 属性决定了子项在尺寸不足时是否可以缩小。如果容器空间不足以容纳所有子项,具有较大 flex-shrink 值的子项会优先缩小,以便适应容器。如果所有子项的 flex-shrink 值都为0,则它们不会缩小。

子项的最小和最大尺寸限制:通过设置子项的 min-width、max-width、min-height、max-height 等属性,可以对子项的尺寸进行限制。这些限制将在布局过程中考虑,并确保子项的尺寸在指定范围内。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值