React Hooks 不能写在条件和循环表达式中的原因主要涉及到 React 的内部工作机制和 Hooks 的设计原则。以下是详细的解释:
React Hooks 必须在函数组件的顶层调用,不能嵌套在条件语句或循环语句中。这是因为 React 依赖于 Hooks 的调用顺序来管理组件的状态和副作用。
状态管理:
副作用管理:
useEffect
和 useLayoutEffect
Hooks 也依赖于固定的调用顺序来管理副作用。React 组件的行为应该是确定性的,即相同的输入应该产生相同的结果。Hooks 的调用顺序保证了这一点。
Hooks 如 useEffect
和 useLayoutEffect
用于处理副作用,如数据获取、订阅和手动 DOM 操作。如果这些 Hooks 被写在条件语句或循环语句中,可能会导致副作用的意外触发。
Hooks 的设计目标是简化函数组件的开发,使其能够处理状态和副作用,而不需要类组件的复杂性。如果 Hooks 可以在条件语句或循环语句中调用,将会增加使用的复杂性和潜在的错误。
React Hooks 不能写在条件和循环表达式中,主要是为了保证 Hooks 的调用顺序一致,确保组件的行为确定性和副作用的可控性。这一设计原则简化了 Hooks 的使用,提升了组件的可维护性和可靠性。
Webpack 和 Vite 都是现代前端开发中常用的构建工具,但它们在不同的应用场景下有不同的优势和适用性。以下是详细的应用场景分析:
大型复杂项目:
多模块项目:
传统开发和生产环境:
需要复杂构建逻辑:
兼容旧版浏览器:
现代 JavaScript 项目:
中小型项目:
现代前端框架:
追求极致开发体验:
需要快速原型开发:
选择 Webpack 还是 Vite 应根据项目的具体需求、团队的技术栈和偏好来决定。两者各有优势,合理选择可以显著提升开发效率和项目性能。
从 Webpack 迁移到 Vite 的决策通常基于以下几个方面的考虑:
现代 JavaScript 项目:
中小型项目:
快速的冷启动和热更新:
简洁的配置:
按需编译:
优化的生产构建:
现代前端框架的支持:
插件生态系统的成熟度:
技术栈的现代化:
团队的技术偏好:
从 Webpack 迁移到 Vite 的决策应综合考虑项目类型和规模、开发体验、性能优化、生态系统的支持以及长期维护和未来规划等因素。对于现代 JavaScript 项目、中小型项目、追求极致开发体验的项目以及对性能有较高要求的项目,迁移到 Vite 可以带来显著的优势。
在 React 中,super()
和 super(props)
主要用于在类组件的构造函数中调用父类的构造函数。以下是它们的区别和使用场景:
super()
基本用法:
super()
是 JavaScript 中用于调用父类构造函数的语法。super()
,可以调用 React.Component 的构造函数。不传递参数:
super()
不传递任何参数给父类的构造函数。super()
后,this.props
是未定义的,无法在构造函数中直接访问 this.props
。适用场景:
this.props
,可以使用 super()
。super(props)
传递参数:
super(props)
在调用父类构造函数时传递了 props
参数。this.props
。适用场景:
this.props
,必须使用 super(props)
。this.props
的可用性:
super()
时,this.props
在构造函数中是未定义的。super(props)
时,this.props
在构造函数中是可用的。最佳实践:
super(props)
,以确保 this.props
在整个构造函数中都是可用的。this.props
时,才可以选择使用 super()
。super()
时,构造函数中无法访问 this.props
。super(props)
时,构造函数中可以直接访问 this.props
。super(props)
。function func(){
var i=0;
/*
*你的代码
*/
}
var funcA = func()
funcA() //1
funcA() //2
funcA() //3
function func(){
var i=0;
return ()=>{
console.log(++i);
}
}
var funcA = func()
funcA() //1
funcA() //2
funcA() //3
const matrix = [
[1,2,3],
[4,5,6],
[7,8,9]
]
实现matrixTrans(matrix)
输出
[
[1,4,7],
[2,5,8],
[3,6,9],
]
const matrixTrans=(matrix:ReadonlyArray<ReadonlyArray<number>>)=>{
const newMatrix:number[][]=[];
for(let i=0;i<matrix.length;i++){
const thisLine=matrix[i]; // 多余
for(let j=0;j<thisLine.length;j++){
if(!newMatrix[j]){
newMatrix[j]=[];
}
newMatrix[j][i]=matrix[i][j];
}
}
return newMatrix;
}
console.log(JSON.stringify(matrixTrans([
[1,2,3],
[4,5,6],
[7,8,9]
])))
请尽可能详细地用TypeScript实现一个Promise类。
在 TypeScript 中实现一个 Promise
类是一项复杂的任务,因为它需要模拟原生 Promise
的行为,包括状态管理、异步操作和错误处理。以下是一个简化的 Promise
类实现,展示了核心概念和功能:
type Executor<T> = (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void;
enum PromiseState {
PENDING,
FULFILLED,
REJECTED
}
class MyPromise<T> {
private state: PromiseState = PromiseState.PENDING;
private value: T | undefined;
private reason: any;
private onFulfilledCallbacks: Array<(value: T) => void> = [];
private onRejectedCallbacks: Array<(reason: any) => void> = [];
constructor(executor: Executor<T>) {
const resolve = (value: T | PromiseLike<T>): void => {
if (this.state === PromiseState.PENDING) {
if (value instanceof MyPromise) {
value.then(resolve, reject);
} else {
this.state = PromiseState.FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback(value));
}
}
};
const reject = (reason: any): void => {
if (this.state === PromiseState.PENDING) {
this.state = PromiseState.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback(reason));
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then<TResult1 = T, TResult2 = never>(
onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
): MyPromise<TResult1 | TResult2> {
return new MyPromise<TResult1 | TResult2>((resolve, reject) => {
const fulfilledHandler = (value: T): void => {
try {
if (onFulfilled) {
resolve(onFulfilled(value));
} else {
resolve(value as unknown as TResult1);
}
} catch (error) {
reject(error);
}
};
const rejectedHandler = (reason: any): void => {
try {
if (onRejected) {
resolve(onRejected(reason));
} else {
reject(reason);
}
} catch (error) {
reject(error);
}
};
if (this.state === PromiseState.FULFILLED) {
setTimeout(() => fulfilledHandler(this.value!), 0);
} else if (this.state === PromiseState.REJECTED) {
setTimeout(() => rejectedHandler(this.reason), 0);
} else {
this.onFulfilledCallbacks.push(fulfilledHandler);
this.onRejectedCallbacks.push(rejectedHandler);
}
});
}
catch<TResult = never>(onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): MyPromise<T | TResult> {
return this.then(undefined, onRejected);
}
static resolve<T>(value: T | PromiseLike<T>): MyPromise<T> {
return new MyPromise<T>(resolve => resolve(value));
}
static reject<T = never>(reason?: any): MyPromise<T> {
return new MyPromise<T>((_, reject) => reject(reason));
}
static all<T>(promises: Array<MyPromise<T>>): MyPromise<Array<T>> {
return new MyPromise<Array<T>>((resolve, reject) => {
const results: Array<T> = [];
let completedCount = 0;
promises.forEach((promise, index) => {
promise.then(
value => {
results[index] = value;
completedCount++;
if (completedCount === promises.length) {
resolve(results);
}
},
reason => {
reject(reason);
}
);
});
});
}
static race<T>(promises: Array<MyPromise<T>>): MyPromise<T> {
return new MyPromise<T>((resolve, reject) => {
promises.forEach(promise => {
promise.then(
value => resolve(value),
reason => reject(reason)
);
});
});
}
}
类型定义:
Executor
是一个函数类型,接受两个参数:resolve
和 reject
。状态管理:
PromiseState
枚举来表示 PENDING
、FULFILLED
和 REJECTED
三种状态。state
属性用于跟踪当前的 Promise 状态。value
和 reason
属性分别用于存储成功和失败的结果。回调函数管理:
onFulfilledCallbacks
和 onRejectedCallbacks
数组用于存储成功和失败的回调函数。构造函数:
executor
函数,并在其中定义 resolve
和 reject
函数。executor
函数,并捕获可能的错误。then 方法:
MyPromise
实例。catch 方法:
then
方法,只传递 onRejected
回调函数。静态方法:
resolve
和 reject
方法用于创建已解决或已拒绝的 Promise。all
方法接受一个 Promise 数组,并在所有 Promise 都成功时返回结果数组,或在任意一个 Promise 失败时返回失败原因。race
方法接受一个 Promise 数组,并返回最先解决或拒绝的 Promise 的结果。这个实现展示了 Promise
的核心功能和基本用法,但并不完全等同于原生的 Promise
,因为它省略了一些边缘情况和优化。
在二叉树中,路径被定义为一组节点的序列,每对相邻节点之间存在一条边。同一个节点只能在路径序列中出现一次。路径必须包含至少一个节点,且不一定经过根节点。
路径和指的是路径中所有节点值的总和。
给定一个二叉树的根节点root,求其最大路径和。
备注
树中节点数目范围是 [1, 3 * 104]
-1000 <= Node.val <= 1000
示例1
输入
root = [1,-2,3,4]
输出
6
解释
最优路径是 4 -> -2 -> 1 -> 3 ,路径和为 4 - 2 + 1 + 3 = 6
示例2
输入
root = [1,-2,3,4,5,6,7]
输出
16
解释
最优路径是 6 -> 3 -> 7 ,路径和为 6 + 3 + 7 = 16
LeetCode hot 150 ——hard
LeetCode 124
https://leetcode.cn/problems/binary-tree-maximum-path-sum/description/?envType=problem-list-v2&envId=binary-tree
// 代码中已指定的类名、方法名、参数名,请勿修改,直接返回方法规定的值即可
/**
* Definition for a binary tree node.
* class TreeNode {
* val: number
* left: TreeNode | null
* right: TreeNode | null
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
* }
**/
class TreeNode {
val: number
left: TreeNode | null
right: TreeNode | null
constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
this.val = (val===undefined ? 0 : val)
this.left = (left===undefined ? null : left)
this.right = (right===undefined ? null : right)
}
}
function maxPathSum(root: TreeNode| null,hasRoot?:boolean): number {
if(!root){
return 0;
}
const leftVal=maxPathSum(root.left);
const rightVal=maxPathSum(root.right);
const leftValHasRoot=maxPathSum(root.left,true);
const rightValHasRoot=maxPathSum(root.right,true);
const hasRootArr=[root.val,
root.val+leftValHasRoot,
root.val+rightValHasRoot,
]
if(hasRoot){
return Math.max(...hasRootArr);
}
return Math.max(...hasRootArr,leftVal,rightVal,root.val+leftValHasRoot+rightValHasRoot);
};
React 错误边界(Error Boundaries)是一种特殊的 React 组件,用于捕获并处理其子组件树中的 JavaScript 错误。它们可以捕获并打印发生在其子组件中的错误,记录这些错误,并显示一个备用 UI,而不是让整个应用崩溃。
捕获子组件错误:
显示备用 UI:
记录错误:
只能捕获子组件错误:
不能捕获异步错误:
setTimeout
、requestAnimationFrame
)或服务端渲染(SSR)中的错误。不能捕获事件处理函数中的错误:
在 React 中,错误边界只能通过类组件来实现,因为错误边界需要维护状态来记录是否发生了错误。函数式组件本身没有状态管理的能力,因此不能直接作为错误边界使用。
虽然函数式组件不能直接作为错误边界,但可以通过以下几种方式在函数式组件中使用错误边界:
包裹在类组件错误边界中:
使用 React 16.6+ 的 ErrorBoundary
高阶组件(HOC):
React 错误边界是一种特殊的类组件,用于捕获并处理其子组件树中的 JavaScript 错误。虽然函数式组件不能直接作为错误边界使用,但可以通过将其包裹在类组件的错误边界中或使用高阶组件(HOC)的方式,在函数式组件中利用错误边界的功能。