react常用的hooks

1
2
3
4
5
6
7
8
9
10
useState:用于在函数组件中添加状态管理能力。
useEffect:用于在函数组件中执行副作用操作,比如数据获取、订阅或手动 DOM 操作。
useContext:用于在函数组件中访问 React 上下文。
useReducer:类似于 Redux 中的 reducer,用于在函数组件中管理复杂的状态逻辑。
useCallback:用于在函数组件中缓存回调函数,以避免不必要的重新渲染。
useMemo:类似于 useCallback,用于在函数组件中进行性能优化,缓存计算结果。
useRef:用于在函数组件中创建可变的 ref 对象。
useImperativeHandle:用于在函数组件中自定义对外暴露的实例值。
useLayoutEffect:类似于 useEffect,但在浏览器执行绘制之前同步触发效果。
useDebugValue:用于在自定义 hooks 中显示调试信息。

vue2和vue3的区别

性能优化:

Vue 3引入了更好的虚拟DOM算法(Fragment:碎片化节点 Patching减少不必要的开销,提升性能),使得更新速度更快。 Vue 3使用了Proxy代替Object.defineProperty来实现响应式数据,提高了性能。 Tree-shaking支持有助于减小打包体积(将没有使用的模块代码移除掉,这样来达到删除无用代码的目的。)。

Composition API:

Vue 3引入了Composition API,使得代码组织更加灵活和可复用,尤其适用于大型项目。 Composition API可以更好地组织逻辑和状态,避免了Vue 2中逻辑难以维护的问题。

Typescript支持:

Vue 3对Typescript的支持更加友好,提供了更好的类型推断和类型检查。

响应式系统:

Vue 3 引入了 Proxy 来替代 Object.defineProperty 实现响应式,提供了 Composition API、setup 函数等新特性,优化了响应式数据缓存机制,使得开发体验更好,性能更高效。

编译优化:

Vue 3 在编译优化方面引入了静态树提升、事件侦听器缓存等新特性,生成的代码更精简、包体积更小、性能更高,相比 Vue 2 有明显提升。

get函数

一、react 实现 get() 函数的示例 👇🏻👇🏻👇🏻👇🏻👇🏻👇🏻

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
import React from 'react';

function get(obj, chain, defaultVal) {
// 将链式属性路径拆分成数组
const keys = chain.split('.');

// 初始化结果为传入的对象
let result = obj;

// 遍历属性路径数组,并逐层获取属性值
for (let i = 0; i < keys.length; i++) {
// 如果当前属性值为 undefined,则返回默认值
if (result[keys[i]] === undefined) {
return defaultVal;
}

// 否则,将结果更新为当前属性值
result = result[keys[i]];
}

// 返回最终结果
return result;
}

function GetExample() {
const data = {
name: 'John',
age: 30,
address: {
city: 'New York',
country: 'USA'
}
};

// 测试 get 函数
const name = get(data, 'name'); // 'John'
const city = get(data, 'address.city'); // 'New York'
const zip = get(data, 'address.zip', 'N/A'); // 'N/A'

return (
<div>
<h1>get() 函数示例</h1>
<p>Name: {name}</p>
<p>City: {city}</p>
<p>Zip: {zip}</p>
</div>
);
}

export default GetExample;

二、vue2 实现 get() 函数的示例 👇🏻👇🏻👇🏻👇🏻👇🏻👇🏻

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
javascript
// 在 main.js 中注册全局函数
import Vue from 'vue';

Vue.prototype.$get = function(obj, chain, defaultVal) {
try {
const value = chain.split('.').reduce((acc, key) => acc[key], obj);
return value !== undefined ? value : defaultVal;
} catch (e) {
return defaultVal;
}
};

// 在组件中使用 $get 函数
export default {
mounted() {
const obj = {
a: {
b: {
c: 'Hello World'
}
}
};

const value = this.$get(obj, 'a.b.c', 'Default Value');
console.log(value); // 输出 'Hello World'

const nonExistentValue = this.$get(obj, 'x.y.z', 'Default Value');
console.log(nonExistentValue); // 输出 'Default Value'
}
};

三、vue3 实现 get() 函数的示例 👇🏻👇🏻👇🏻👇🏻👇🏻👇🏻

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
<template>
<div>
<button @click="getValue">Get Value</button>
<p>Result: {{ result }}</p>
</div>
</template>

<script>
import { ref, onMounted } from 'vue';

export default {
setup() {
const getValue = () => {
const obj = {
a: {
b: {
c: 'Hello World'
}
}
};
const value = get(obj, 'a.b.c', 'Default Value');
console.log(value); // 输出 'Hello World'
};

const result = ref('');

const get = (obj, chain, defaultVal) => {
try {
const value = chain.split('.').reduce((acc, key) => acc[key], obj);
return value !== undefined ? value : defaultVal;
} catch (e) {
return defaultVal;
}
};

onMounted(() => {
getValue();
});

return {
result
};
}
};
</script>

解决循环输出问题

案例:

1
2
3
4
5
for(var i = 1; i <= 5; i ++){
setTimeout(function() {
console.log(i)
}, 0)
} // 输出结果:6 6 6 6 6

如何实现打印结果为 1,2,3,4,5 呢?
1、setTimeout 为宏任务,由于 JS 中单线程 eventLoop 机制,在主线程同步任务执行完后才去执行宏任务,因此循环结束后 setTimeout 中的回调才依次执行
2、因为 setTimeout 函数也是一种闭包,往上找它的父级作用域链就是 window,变量 i 为 window 上的全局变量,开始执行 setTimeout 之前变量 i 已经就是 6 了,因此最后输出的连续就都是 6。

解决方法一:IIFE 立即执行函数
利用 IIFE(立即执行函数),当每次 for 循环时,把此时的变量 i 传递到定时器中,然后执行。

1
2
3
4
5
6
7
for(var i = 1;i <= 5;i++){
(function(j){
setTimeout(function timer(){
console.log(j)
}, 0)
})(i)
} // 输出结果:1 2 3 4 5

解决方法二:使用 ES6 中的 let
ES6 中新增的 let 定义变量的方式,使得 ES6 之后 JS 发生革命性的变化,让 JS 有了块级作用域,代码的作用域以块级为单位进行执行。

1
2
3
4
5
for(let i = 1; i <= 5; i++){
setTimeout(function() {
console.log(i);
},0)
} // 输出结果:1 2 3 4 5

解决方法三:定时器传入第三个参数
setTimeout 作为经常使用的定时器,它是存在第三个参数的,日常工作中我们经常使用的一般是前两个,一个是回调函数,另外一个是时间,而第三个参数用得比较少。而第三个参数的传递,可以改变 setTimeout 的执行逻辑,从而实现我们想要的结果

1
2
3
4
5
for(var i=1;i<=5;i++){
setTimeout(function(j) {
console.log(j)
}, 0, i)
} // 输出结果:1 2 3 4 5

promise

Promise 是 ES6 新增的语法,解决了回调地狱的问题。

一般 Promise 在执行过程中,必然会处于以下几种状态之一。
· 待定(pending):初始状态,既没有被完成,也没有被拒绝。
· 已完成(fulfilled):操作成功完成。
· 已拒绝(rejected):操作失败。

实例:then catch finally
静态:all race resolve reject
· resolve:将其他数据类型转为 Promise 并将状态改为成功态
· reject:将其他数据类型转为 Promise 并将状态改为失败态
· all:参数所有返回结果为成功才返回
· allSettled: 参数不论返回结果是否成功,都返回每个参数执行状态
· any: 参数中只要有一个成功,就返回该成功的执行结果
· race:参数数组中所有 Promise 实例中最快的那个成功即为成功态,失败即为失败态
案例:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
const PENDING = 'pending'  // 声明一个常量PENDING,表示Promise的初始状态
const FULFILLED = 'fulfilled' // 声明一个常量FULFILLED,表示Promise的成功状态
const REJECTED = 'rejected' // 声明一个常量REJECTED,表示Promise的失败状态

class MyPromise {
constructor(executor) {
this.state = PENDING // 初始化Promise的状态为PENDING
this.value = undefined // 初始化Promise的值为undefined
this.reason = undefined // 初始化Promise的失败原因为undefined
this.onFulfilledCallbacks = [] // 存储Promise成功状态下的回调函数
this.onRejectedCallbacks = [] // 存储Promise失败状态下的回调函数

// 定义resolve函数,用于将Promise状态改为FULFILLED,并执行成功状态下的回调函数
const resolve = (value) => {
if (this.state = PENDING) {
this.state = FULFILLED // 将Promise状态改为FULFILLED
this.value = value // 存储Promise成功时的值
this.onFulfilledCallbacks.forEach(fn => fn()) // 执行所有成功状态下的回调函数
}
}

// 定义reject函数,用于将Promise状态改为REJECTED,并执行失败状态下的回调函数
const reject = (reason) => {
if (this.state === PENDING) {
this.state = REJECTED // 将Promise状态改为REJECTED
this.reason = reason // 存储Promise失败时的原因
this.onRejectedCallbacks.forEach(fn => fn()) // 执行所有失败状态下的回调函数
}
}

try {
executor(resolve, reject) // 执行executor函数,并传入resolve和reject参数
} catch (err) {
reject(err) // 捕获错误,并将Promise状态改为REJECTED
}
}

// 静态方法resolve,返回一个状态为FULFILLED的Promise实例
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}

// 静态方法reject,返回一个状态为REJECTED的Promise实例
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}

// 静态方法all,接收一个包含多个Promise实例的数组,返回一个新的Promise实例
static all(promises) {
return new Promise((resolve, reject) => {
if (promises.length === 0) {
resolve([]) // 如果传入的数组为空,则直接返回一个状态为FULFILLED的Promise实例
} else {
let result = [] // 存储每个Promise实例的执行结果
let count = 0 // 计数器
for (let i = 0;i < promises.length; i++) {
promises[i].then(
data => {
result[i] = data // 将每个Promise实例的执行结果存入result数组中
count++
if (count === promises.length) {
resolve(result) // 当所有Promise实例都执行完毕时,返回包含所有结果的新的Promise实例
}
},
err => {
// 如果其中一个Promise实例执行失败,则将新的Promise实例的状态改为REJECTED,并返回失败原因
reject(err)
return
}
)
}
}
})
}

// 静态方法race,接收一个包含多个Promise实例的数组,返回一个新的Promise实例
static race(promises) {
return new Promise((resolve, reject) => {
if (promises.length === 0) {
resolve() // 如果传入的数组为空,则直接返回一个状态为FULFILLED的Promise实例
} else {
for (let i = 0; i < promises.length; i++) {
promises[i].then(
data => {
resolve(data) // 返回第一个执行完毕的Promise实例的结果
},
(err) => {
// 如果其中一个Promise实例执行失败,则将新的Promise实例的状态改为REJECTED,并返回失败原因
reject(err)
return
}
)
}
}
})
}

// then方法,用于在Promise的成功和失败状态下执行回调函数,返回一个新的Promise实例
then(onFulfilled, onRejected) {
// 如果onFulfilled不是一个函数,则将其更改为返回接收到的值的函数
if (typeof onFulfilled !== 'function') {
onFulfilled = function (value) {
return value
}
}

// 如果onRejected不是一个函数,则将其更改为抛出接收到的原因的函数
if (typeof onRejected !== 'function') {
onRejected = function (reason) {
throw reason
}
}

let promise2 = new MyPromise((resolve, reject) => {
switch (this.state) {
// 如果Promise当前的状态是PENDING,则将回调函数添加到对应的回调数组中
case PENDING:
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const value = onFulfilled(this.value)
if (value instanceof MyPromise) {
value.then(resolve, reject)
} else {
resolve(value)
}
} catch (err) {
reject(err)
}
}, 0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const value = onRejected(this.reason)
resolve(value)
} catch (err) {
reject(err)
}
}, 0)
})
break
// 如果Promise当前的状态是FULFILLED,则直接执行成功回调函数
case FULFILLED:
setTimeout(() => {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (err) {
reject(err)
}
}, 0)
break
// 如果Promise当前的状态是REJECTED,则直接执行失败回调函数
case REJECTED:
setTimeout(() => {
try {
const value = onRejected(this.reason)
resolve(value)
} catch (err) {
reject(err)
}
}, 0)
break
}
})
return promise2
}

// catch方法,用于捕获Promise的失败状态,并执行回调函数
catch(onRejected) {
return this.then(null, onRejected)
}

// finally方法,无论Promise状态是成功还是失败,都会执行回调函数
finally(fn) {
return this.then(
(value) => {
fn()
return value
},
(reason) => {
fn()
throw reason
}
)
}
}