@feng3d/reactivity 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +158 -158
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +91 -2
- package/dist/index.umd.cjs.map +1 -1
- package/lib/ReactiveObject.d.ts +101 -0
- package/lib/ReactiveObject.d.ts.map +1 -0
- package/lib/batch.d.ts.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/package.json +69 -69
- package/src/ReactiveObject.ts +131 -0
- package/src/Reactivity.ts +168 -168
- package/src/arrayInstrumentations.ts +801 -801
- package/src/baseHandlers.ts +312 -312
- package/src/batch.ts +134 -118
- package/src/collectionHandlers.ts +486 -486
- package/src/computed.ts +253 -253
- package/src/effect.ts +146 -146
- package/src/effectScope.ts +294 -294
- package/src/index.ts +10 -9
- package/src/property.ts +231 -231
- package/src/reactive.ts +186 -186
- package/src/ref.ts +150 -150
- package/src/shared/constants.ts +41 -41
- package/src/shared/general.ts +109 -109
- package/tsconfig.json +19 -19
- package/dist/assets/RobotoMono-Medium-DVgDz_OO.woff2 +0 -0
- package/dist/assets/RobotoMono-Regular-BPoF81uy.woff2 +0 -0
- package/dist/assets/index-a2qCSG5V.css +0 -629
- package/dist/assets/index.html-Dyp3udP2.js +0 -200
- package/dist/assets/modulepreload-polyfill-DaKOjhqt.js +0 -37
- package/dist/assets/package-DuJynByc.js +0 -2539
- package/dist/assets/src//345/244/215/346/235/202/346/203/205/345/206/265/345/217/226/345/200/274/index.html-C3hbV3IR.js +0 -59
- package/dist/assets/src//346/225/260/347/273/204/index.html-CHK6WEhd.js +0 -43
- package/dist/docs/.nojekyll +0 -1
- package/dist/docs/assets/hierarchy.js +0 -1
- package/dist/docs/assets/highlight.css +0 -92
- package/dist/docs/assets/icons.js +0 -18
- package/dist/docs/assets/icons.svg +0 -1
- package/dist/docs/assets/main.js +0 -60
- package/dist/docs/assets/navigation.js +0 -1
- package/dist/docs/assets/search.js +0 -1
- package/dist/docs/assets/style.css +0 -1640
- package/dist/docs/classes/EffectScope.html +0 -40
- package/dist/docs/functions/batchRun.html +0 -15
- package/dist/docs/functions/computed.html +0 -5
- package/dist/docs/functions/effect.html +0 -11
- package/dist/docs/functions/effectScope.html +0 -5
- package/dist/docs/functions/forceTrack.html +0 -6
- package/dist/docs/functions/getCurrentScope.html +0 -4
- package/dist/docs/functions/isProxy.html +0 -5
- package/dist/docs/functions/isReactive.html +0 -5
- package/dist/docs/functions/isRef.html +0 -5
- package/dist/docs/functions/noTrack.html +0 -6
- package/dist/docs/functions/onScopeDispose.html +0 -6
- package/dist/docs/functions/reactive.html +0 -19
- package/dist/docs/functions/ref.html +0 -13
- package/dist/docs/functions/toRaw.html +0 -4
- package/dist/docs/hierarchy.html +0 -1
- package/dist/docs/index.html +0 -129
- package/dist/docs/interfaces/Computed.html +0 -9
- package/dist/docs/interfaces/Effect.html +0 -8
- package/dist/docs/interfaces/Ref.html +0 -9
- package/dist/docs/modules.html +0 -1
- package/dist/docs/types/Reactive.html +0 -3
- package/dist/docs/types/UnReadonly.html +0 -3
- package/dist/files/RobotoMono-Medium.woff2 +0 -0
- package/dist/files/RobotoMono-Regular.woff2 +0 -0
- package/dist/files/ic_code_black_24dp.svg +0 -4
- package/dist/files/ic_search_black_24dp.svg +0 -4
- package/dist/files/main.css +0 -629
- package/dist/files/thumbnails.svg +0 -7
- package/dist/files.json +0 -7
- package/dist/index.html +0 -84
- package/dist/screenshots//345/244/215/346/235/202/346/203/205/345/206/265/345/217/226/345/200/274.jpg +0 -0
- package/dist/screenshots//346/225/260/347/273/204.jpg +0 -0
- package/dist/src//345/244/215/346/235/202/346/203/205/345/206/265/345/217/226/345/200/274/index.html +0 -70
- package/dist/src//346/225/260/347/273/204/index.html +0 -65
- package/dist/tags.json +0 -2
|
@@ -1,801 +1,801 @@
|
|
|
1
|
-
/* eslint-disable prefer-rest-params */
|
|
2
|
-
|
|
3
|
-
import { batchRun } from './batch';
|
|
4
|
-
import { noTrack } from './Reactivity';
|
|
5
|
-
import { PropertyReactivity } from './property';
|
|
6
|
-
import { isProxy, toReactive } from './reactive';
|
|
7
|
-
import { ARRAY_ITERATE_KEY, TrackOpTypes } from './shared/constants';
|
|
8
|
-
import { isArray, toRaw } from './shared/general';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 数组方法增强对象。
|
|
12
|
-
*
|
|
13
|
-
* 为数组提供响应式增强的方法实现,包括:
|
|
14
|
-
* 1. 迭代器方法:Symbol.iterator、entries、keys、values
|
|
15
|
-
* 2. 查找方法:includes、indexOf、lastIndexOf、find、findIndex、findLast、findLastIndex
|
|
16
|
-
* 3. 遍历方法:forEach、map、filter、some、every、reduce、reduceRight
|
|
17
|
-
* 4. 修改方法:push、pop、shift、unshift、splice、toReversed、toSorted、toSpliced
|
|
18
|
-
* 5. 其他方法:concat、join
|
|
19
|
-
*/
|
|
20
|
-
export const arrayInstrumentations: Record<string | symbol, Function> = <any>{
|
|
21
|
-
__proto__: null,
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* 返回一个迭代器,用于遍历数组的响应式值。
|
|
25
|
-
*
|
|
26
|
-
* 实现了以下功能:
|
|
27
|
-
* 1. 创建数组的迭代器
|
|
28
|
-
* 2. 自动将迭代的值转换为响应式
|
|
29
|
-
* 3. 自动追踪数组的访问
|
|
30
|
-
*
|
|
31
|
-
* @returns 数组的迭代器
|
|
32
|
-
*/
|
|
33
|
-
[Symbol.iterator]()
|
|
34
|
-
{
|
|
35
|
-
return iterator(this, Symbol.iterator, toReactive);
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* 连接数组并返回新数组。
|
|
40
|
-
*
|
|
41
|
-
* 实现了以下功能:
|
|
42
|
-
* 1. 处理响应式数组的连接
|
|
43
|
-
* 2. 自动将参数中的数组转换为响应式
|
|
44
|
-
* 3. 保持原始值的引用
|
|
45
|
-
*
|
|
46
|
-
* @param args 要连接的数组或值
|
|
47
|
-
* @returns 连接后的新数组
|
|
48
|
-
*/
|
|
49
|
-
concat(...args: unknown[])
|
|
50
|
-
{
|
|
51
|
-
return reactiveReadArray(this).concat(
|
|
52
|
-
...args.map((x) => (isArray(x) ? reactiveReadArray(x) : x)),
|
|
53
|
-
);
|
|
54
|
-
},
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* 返回一个迭代器,用于遍历数组的键值对。
|
|
58
|
-
*
|
|
59
|
-
* 实现了以下功能:
|
|
60
|
-
* 1. 创建数组的键值对迭代器
|
|
61
|
-
* 2. 自动将值转换为响应式
|
|
62
|
-
* 3. 自动追踪数组的访问
|
|
63
|
-
*
|
|
64
|
-
* @returns 数组的键值对迭代器
|
|
65
|
-
*/
|
|
66
|
-
entries()
|
|
67
|
-
{
|
|
68
|
-
return iterator(this, 'entries', (value: [number, unknown]) =>
|
|
69
|
-
{
|
|
70
|
-
value[1] = toReactive(value[1]);
|
|
71
|
-
|
|
72
|
-
return value;
|
|
73
|
-
});
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* 测试数组中的所有元素是否都通过了指定函数的测试。
|
|
78
|
-
*
|
|
79
|
-
* 实现了以下功能:
|
|
80
|
-
* 1. 遍历数组元素
|
|
81
|
-
* 2. 对每个元素执行测试函数
|
|
82
|
-
* 3. 自动追踪数组的访问
|
|
83
|
-
* 4. 处理响应式值的测试
|
|
84
|
-
*
|
|
85
|
-
* @param fn 测试函数
|
|
86
|
-
* @param thisArg 测试函数的 this 值
|
|
87
|
-
* @returns 如果所有元素都通过测试则返回 true,否则返回 false
|
|
88
|
-
*/
|
|
89
|
-
every(fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
90
|
-
thisArg?: unknown,
|
|
91
|
-
)
|
|
92
|
-
{
|
|
93
|
-
return apply(this, 'every', fn, thisArg, undefined, arguments);
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* 创建一个新数组,包含通过指定函数测试的所有元素。
|
|
98
|
-
*
|
|
99
|
-
* 实现了以下功能:
|
|
100
|
-
* 1. 遍历数组元素
|
|
101
|
-
* 2. 对每个元素执行测试函数
|
|
102
|
-
* 3. 自动追踪数组的访问
|
|
103
|
-
* 4. 自动将结果转换为响应式
|
|
104
|
-
*
|
|
105
|
-
* @param fn 测试函数
|
|
106
|
-
* @param thisArg 测试函数的 this 值
|
|
107
|
-
* @returns 包含通过测试的元素的新数组
|
|
108
|
-
*/
|
|
109
|
-
filter(fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
110
|
-
thisArg?: unknown,
|
|
111
|
-
)
|
|
112
|
-
{
|
|
113
|
-
return apply(this, 'filter', fn, thisArg, (v) => v.map(toReactive), arguments);
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* 返回数组中满足指定测试函数的第一个元素。
|
|
118
|
-
*
|
|
119
|
-
* 实现了以下功能:
|
|
120
|
-
* 1. 遍历数组元素
|
|
121
|
-
* 2. 对每个元素执行测试函数
|
|
122
|
-
* 3. 自动追踪数组的访问
|
|
123
|
-
* 4. 自动将结果转换为响应式
|
|
124
|
-
*
|
|
125
|
-
* @param fn 测试函数
|
|
126
|
-
* @param thisArg 测试函数的 this 值
|
|
127
|
-
* @returns 第一个满足测试的元素,如果没有则返回 undefined
|
|
128
|
-
*/
|
|
129
|
-
find(fn: (item: unknown, index: number, array: unknown[]) => boolean,
|
|
130
|
-
thisArg?: unknown,
|
|
131
|
-
)
|
|
132
|
-
{
|
|
133
|
-
return apply(this, 'find', fn, thisArg, toReactive, arguments);
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* 返回数组中满足指定测试函数的第一个元素的索引。
|
|
138
|
-
*
|
|
139
|
-
* 实现了以下功能:
|
|
140
|
-
* 1. 遍历数组元素
|
|
141
|
-
* 2. 对每个元素执行测试函数
|
|
142
|
-
* 3. 自动追踪数组的访问
|
|
143
|
-
* 4. 处理响应式值的查找
|
|
144
|
-
*
|
|
145
|
-
* @param fn 测试函数
|
|
146
|
-
* @param thisArg 测试函数的 this 值
|
|
147
|
-
* @returns 第一个满足测试的元素的索引,如果没有则返回 -1
|
|
148
|
-
*/
|
|
149
|
-
findIndex(fn: (item: unknown, index: number, array: unknown[]) => boolean,
|
|
150
|
-
thisArg?: unknown,
|
|
151
|
-
)
|
|
152
|
-
{
|
|
153
|
-
return apply(this, 'findIndex', fn, thisArg, undefined, arguments);
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* 返回数组中满足指定测试函数的最后一个元素。
|
|
158
|
-
*
|
|
159
|
-
* 实现了以下功能:
|
|
160
|
-
* 1. 从后向前遍历数组元素
|
|
161
|
-
* 2. 对每个元素执行测试函数
|
|
162
|
-
* 3. 自动追踪数组的访问
|
|
163
|
-
* 4. 自动将结果转换为响应式
|
|
164
|
-
*
|
|
165
|
-
* @param fn 测试函数
|
|
166
|
-
* @param thisArg 测试函数的 this 值
|
|
167
|
-
* @returns 最后一个满足测试的元素,如果没有则返回 undefined
|
|
168
|
-
*/
|
|
169
|
-
findLast(fn: (item: unknown, index: number, array: unknown[]) => boolean,
|
|
170
|
-
thisArg?: unknown,
|
|
171
|
-
)
|
|
172
|
-
{
|
|
173
|
-
return apply(this, 'findLast', fn, thisArg, toReactive, arguments);
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* 返回数组中满足指定测试函数的最后一个元素的索引。
|
|
178
|
-
*
|
|
179
|
-
* 实现了以下功能:
|
|
180
|
-
* 1. 从后向前遍历数组元素
|
|
181
|
-
* 2. 对每个元素执行测试函数
|
|
182
|
-
* 3. 自动追踪数组的访问
|
|
183
|
-
* 4. 处理响应式值的查找
|
|
184
|
-
*
|
|
185
|
-
* @param fn 测试函数
|
|
186
|
-
* @param thisArg 测试函数的 this 值
|
|
187
|
-
* @returns 最后一个满足测试的元素的索引,如果没有则返回 -1
|
|
188
|
-
*/
|
|
189
|
-
findLastIndex(fn: (item: unknown, index: number, array: unknown[]) => boolean,
|
|
190
|
-
thisArg?: unknown,
|
|
191
|
-
)
|
|
192
|
-
{
|
|
193
|
-
return apply(this, 'findLastIndex', fn, thisArg, undefined, arguments);
|
|
194
|
-
},
|
|
195
|
-
|
|
196
|
-
// flat, flatMap 可以从 ARRAY_ITERATE 中受益,但实现起来不太直接
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* 对数组中的每个元素执行指定函数。
|
|
200
|
-
*
|
|
201
|
-
* 实现了以下功能:
|
|
202
|
-
* 1. 遍历数组元素
|
|
203
|
-
* 2. 对每个元素执行回调函数
|
|
204
|
-
* 3. 自动追踪数组的访问
|
|
205
|
-
* 4. 处理响应式值的遍历
|
|
206
|
-
*
|
|
207
|
-
* @param fn 回调函数
|
|
208
|
-
* @param thisArg 回调函数的 this 值
|
|
209
|
-
*/
|
|
210
|
-
forEach(fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
211
|
-
thisArg?: unknown,
|
|
212
|
-
)
|
|
213
|
-
{
|
|
214
|
-
return apply(this, 'forEach', fn, thisArg, undefined, arguments);
|
|
215
|
-
},
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* 判断数组是否包含指定元素。
|
|
219
|
-
*
|
|
220
|
-
* 实现了以下功能:
|
|
221
|
-
* 1. 处理响应式值的查找
|
|
222
|
-
* 2. 自动追踪数组的访问
|
|
223
|
-
* 3. 处理代理对象的查找
|
|
224
|
-
*
|
|
225
|
-
* @param args 要查找的元素
|
|
226
|
-
* @returns 如果数组包含该元素则返回 true,否则返回 false
|
|
227
|
-
*/
|
|
228
|
-
includes(...args: unknown[])
|
|
229
|
-
{
|
|
230
|
-
return searchProxy(this, 'includes' as any, args);
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* 返回数组中指定元素第一次出现的索引。
|
|
235
|
-
*
|
|
236
|
-
* 实现了以下功能:
|
|
237
|
-
* 1. 处理响应式值的查找
|
|
238
|
-
* 2. 自动追踪数组的访问
|
|
239
|
-
* 3. 处理代理对象的查找
|
|
240
|
-
*
|
|
241
|
-
* @param args 要查找的元素
|
|
242
|
-
* @returns 元素第一次出现的索引,如果没有则返回 -1
|
|
243
|
-
*/
|
|
244
|
-
indexOf(...args: unknown[])
|
|
245
|
-
{
|
|
246
|
-
return searchProxy(this, 'indexOf', args);
|
|
247
|
-
},
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* 将数组的所有元素连接成一个字符串。
|
|
251
|
-
*
|
|
252
|
-
* 实现了以下功能:
|
|
253
|
-
* 1. 处理响应式数组的连接
|
|
254
|
-
* 2. 自动追踪数组的访问
|
|
255
|
-
* 3. 保持原始值的引用
|
|
256
|
-
*
|
|
257
|
-
* @param separator 分隔符
|
|
258
|
-
* @returns 连接后的字符串
|
|
259
|
-
*/
|
|
260
|
-
join(separator?: string)
|
|
261
|
-
{
|
|
262
|
-
return reactiveReadArray(this).join(separator);
|
|
263
|
-
},
|
|
264
|
-
|
|
265
|
-
// keys() 迭代器只读取 length,不需要优化
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* 返回数组中指定元素最后一次出现的索引。
|
|
269
|
-
*
|
|
270
|
-
* 实现了以下功能:
|
|
271
|
-
* 1. 处理响应式值的查找
|
|
272
|
-
* 2. 自动追踪数组的访问
|
|
273
|
-
* 3. 处理代理对象的查找
|
|
274
|
-
*
|
|
275
|
-
* @param args 要查找的元素
|
|
276
|
-
* @returns 元素最后一次出现的索引,如果没有则返回 -1
|
|
277
|
-
*/
|
|
278
|
-
lastIndexOf(...args: unknown[])
|
|
279
|
-
{
|
|
280
|
-
return searchProxy(this, 'lastIndexOf', args);
|
|
281
|
-
},
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* 创建一个新数组,包含对原数组每个元素调用指定函数的结果。
|
|
285
|
-
*
|
|
286
|
-
* 实现了以下功能:
|
|
287
|
-
* 1. 遍历数组元素
|
|
288
|
-
* 2. 对每个元素执行映射函数
|
|
289
|
-
* 3. 自动追踪数组的访问
|
|
290
|
-
* 4. 处理响应式值的映射
|
|
291
|
-
*
|
|
292
|
-
* @param fn 映射函数
|
|
293
|
-
* @param thisArg 映射函数的 this 值
|
|
294
|
-
* @returns 包含映射结果的新数组
|
|
295
|
-
*/
|
|
296
|
-
map(fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
297
|
-
thisArg?: unknown,
|
|
298
|
-
)
|
|
299
|
-
{
|
|
300
|
-
return apply(this, 'map', fn, thisArg, undefined, arguments);
|
|
301
|
-
},
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* 移除数组的最后一个元素并返回该元素。
|
|
305
|
-
*
|
|
306
|
-
* 实现了以下功能:
|
|
307
|
-
* 1. 移除最后一个元素
|
|
308
|
-
* 2. 避免跟踪长度变化
|
|
309
|
-
* 3. 处理响应式值的移除
|
|
310
|
-
*
|
|
311
|
-
* @returns 被移除的元素
|
|
312
|
-
*/
|
|
313
|
-
pop()
|
|
314
|
-
{
|
|
315
|
-
return noTracking(this, 'pop');
|
|
316
|
-
},
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* 向数组末尾添加一个或多个元素。
|
|
320
|
-
*
|
|
321
|
-
* 实现了以下功能:
|
|
322
|
-
* 1. 添加新元素
|
|
323
|
-
* 2. 避免跟踪长度变化
|
|
324
|
-
* 3. 处理响应式值的添加
|
|
325
|
-
*
|
|
326
|
-
* @param args 要添加的元素
|
|
327
|
-
* @returns 数组的新长度
|
|
328
|
-
*/
|
|
329
|
-
push(...args: unknown[])
|
|
330
|
-
{
|
|
331
|
-
return noTracking(this, 'push', args);
|
|
332
|
-
},
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* 对数组中的每个元素执行累加器函数。
|
|
336
|
-
*
|
|
337
|
-
* 实现了以下功能:
|
|
338
|
-
* 1. 从左到右遍历数组元素
|
|
339
|
-
* 2. 对每个元素执行累加器函数
|
|
340
|
-
* 3. 自动追踪数组的访问
|
|
341
|
-
* 4. 处理响应式值的累加
|
|
342
|
-
*
|
|
343
|
-
* @param fn 累加器函数
|
|
344
|
-
* @param args 初始值(可选)
|
|
345
|
-
* @returns 累加的结果
|
|
346
|
-
*/
|
|
347
|
-
reduce(fn: (
|
|
348
|
-
acc: unknown,
|
|
349
|
-
item: unknown,
|
|
350
|
-
index: number,
|
|
351
|
-
array: unknown[],
|
|
352
|
-
) => unknown,
|
|
353
|
-
...args: unknown[]
|
|
354
|
-
)
|
|
355
|
-
{
|
|
356
|
-
return reduce(this, 'reduce', fn, args);
|
|
357
|
-
},
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* 从右到左对数组中的每个元素执行累加器函数。
|
|
361
|
-
*
|
|
362
|
-
* 实现了以下功能:
|
|
363
|
-
* 1. 从右到左遍历数组元素
|
|
364
|
-
* 2. 对每个元素执行累加器函数
|
|
365
|
-
* 3. 自动追踪数组的访问
|
|
366
|
-
* 4. 处理响应式值的累加
|
|
367
|
-
*
|
|
368
|
-
* @param fn 累加器函数
|
|
369
|
-
* @param args 初始值(可选)
|
|
370
|
-
* @returns 累加的结果
|
|
371
|
-
*/
|
|
372
|
-
reduceRight(
|
|
373
|
-
fn: (
|
|
374
|
-
acc: unknown,
|
|
375
|
-
item: unknown,
|
|
376
|
-
index: number,
|
|
377
|
-
array: unknown[],
|
|
378
|
-
) => unknown,
|
|
379
|
-
...args: unknown[]
|
|
380
|
-
)
|
|
381
|
-
{
|
|
382
|
-
return reduce(this, 'reduceRight', fn, args);
|
|
383
|
-
},
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* 移除数组的第一个元素并返回该元素。
|
|
387
|
-
*
|
|
388
|
-
* 实现了以下功能:
|
|
389
|
-
* 1. 移除第一个元素
|
|
390
|
-
* 2. 避免跟踪长度变化
|
|
391
|
-
* 3. 处理响应式值的移除
|
|
392
|
-
*
|
|
393
|
-
* @returns 被移除的元素
|
|
394
|
-
*/
|
|
395
|
-
shift()
|
|
396
|
-
{
|
|
397
|
-
return noTracking(this, 'shift');
|
|
398
|
-
},
|
|
399
|
-
|
|
400
|
-
// slice 可以使用 ARRAY_ITERATE,但似乎也需要范围追踪
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* 测试数组中的某些元素是否通过了指定函数的测试。
|
|
404
|
-
*
|
|
405
|
-
* 实现了以下功能:
|
|
406
|
-
* 1. 遍历数组元素
|
|
407
|
-
* 2. 对每个元素执行测试函数
|
|
408
|
-
* 3. 自动追踪数组的访问
|
|
409
|
-
* 4. 处理响应式值的测试
|
|
410
|
-
*
|
|
411
|
-
* @param fn 测试函数
|
|
412
|
-
* @param thisArg 测试函数的 this 值
|
|
413
|
-
* @returns 如果有元素通过测试则返回 true,否则返回 false
|
|
414
|
-
*/
|
|
415
|
-
some(
|
|
416
|
-
fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
417
|
-
thisArg?: unknown,
|
|
418
|
-
)
|
|
419
|
-
{
|
|
420
|
-
return apply(this, 'some', fn, thisArg, undefined, arguments);
|
|
421
|
-
},
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* 通过删除或替换现有元素或添加新元素来修改数组。
|
|
425
|
-
*
|
|
426
|
-
* 实现了以下功能:
|
|
427
|
-
* 1. 修改数组内容
|
|
428
|
-
* 2. 避免跟踪长度变化
|
|
429
|
-
* 3. 处理响应式值的修改
|
|
430
|
-
*
|
|
431
|
-
* @param args 要删除的起始索引、要删除的元素数量和要添加的元素
|
|
432
|
-
* @returns 包含被删除元素的新数组
|
|
433
|
-
*/
|
|
434
|
-
splice(...args: unknown[])
|
|
435
|
-
{
|
|
436
|
-
return noTracking(this, 'splice', args);
|
|
437
|
-
},
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* 返回一个新数组,包含原数组的反转副本。
|
|
441
|
-
*
|
|
442
|
-
* 实现了以下功能:
|
|
443
|
-
* 1. 创建数组的反转副本
|
|
444
|
-
* 2. 自动将结果转换为响应式
|
|
445
|
-
* 3. 保持原始值的引用
|
|
446
|
-
*
|
|
447
|
-
* @returns 反转后的新数组
|
|
448
|
-
*/
|
|
449
|
-
toReversed()
|
|
450
|
-
{
|
|
451
|
-
// @ts-expect-error user code may run in es2016+
|
|
452
|
-
return reactiveReadArray(this).toReversed();
|
|
453
|
-
},
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* 返回一个新数组,包含原数组的排序副本。
|
|
457
|
-
*
|
|
458
|
-
* 实现了以下功能:
|
|
459
|
-
* 1. 创建数组的排序副本
|
|
460
|
-
* 2. 自动将结果转换为响应式
|
|
461
|
-
* 3. 保持原始值的引用
|
|
462
|
-
*
|
|
463
|
-
* @param comparer 比较函数
|
|
464
|
-
* @returns 排序后的新数组
|
|
465
|
-
*/
|
|
466
|
-
toSorted(comparer?: (a: unknown, b: unknown) => number)
|
|
467
|
-
{
|
|
468
|
-
// @ts-expect-error user code may run in es2016+
|
|
469
|
-
return reactiveReadArray(this).toSorted(comparer);
|
|
470
|
-
},
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* 返回一个新数组,包含原数组的切片副本。
|
|
474
|
-
*
|
|
475
|
-
* 实现了以下功能:
|
|
476
|
-
* 1. 创建数组的切片副本
|
|
477
|
-
* 2. 自动将结果转换为响应式
|
|
478
|
-
* 3. 保持原始值的引用
|
|
479
|
-
*
|
|
480
|
-
* @param args 起始索引和结束索引
|
|
481
|
-
* @returns 切片后的新数组
|
|
482
|
-
*/
|
|
483
|
-
toSpliced(...args: unknown[])
|
|
484
|
-
{
|
|
485
|
-
// @ts-expect-error user code may run in es2016+
|
|
486
|
-
return reactiveReadArray(this).toSpliced(...args);
|
|
487
|
-
},
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* 向数组开头添加一个或多个元素。
|
|
491
|
-
*
|
|
492
|
-
* 实现了以下功能:
|
|
493
|
-
* 1. 添加新元素
|
|
494
|
-
* 2. 避免跟踪长度变化
|
|
495
|
-
* 3. 处理响应式值的添加
|
|
496
|
-
*
|
|
497
|
-
* @param args 要添加的元素
|
|
498
|
-
* @returns 数组的新长度
|
|
499
|
-
*/
|
|
500
|
-
unshift(...args: unknown[])
|
|
501
|
-
{
|
|
502
|
-
return noTracking(this, 'unshift', args);
|
|
503
|
-
},
|
|
504
|
-
|
|
505
|
-
/**
|
|
506
|
-
* 返回一个迭代器,用于遍历数组的值。
|
|
507
|
-
*
|
|
508
|
-
* 实现了以下功能:
|
|
509
|
-
* 1. 创建数组的值迭代器
|
|
510
|
-
* 2. 自动将迭代的值转换为响应式
|
|
511
|
-
* 3. 自动追踪数组的访问
|
|
512
|
-
*
|
|
513
|
-
* @returns 数组的值迭代器
|
|
514
|
-
*/
|
|
515
|
-
values()
|
|
516
|
-
{
|
|
517
|
-
return iterator(this, 'values', toReactive);
|
|
518
|
-
},
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* 创建数组的迭代器。
|
|
523
|
-
*
|
|
524
|
-
* 实现了以下功能:
|
|
525
|
-
* 1. 创建数组的迭代器
|
|
526
|
-
* 2. 自动将迭代的值转换为响应式
|
|
527
|
-
* 3. 自动追踪数组的访问
|
|
528
|
-
*
|
|
529
|
-
* 注意:在这里获取 ARRAY_ITERATE 依赖并不完全等同于在代理数组上调用迭代。
|
|
530
|
-
* 创建迭代器时不会访问任何数组属性:
|
|
531
|
-
* 只有在调用 .next() 时才会访问 length 和索引。
|
|
532
|
-
* 从极端情况来看,迭代器可以在一个 effect scope 中创建,
|
|
533
|
-
* 在另一个 scope 中部分迭代,然后在第三个 scope 中继续迭代。
|
|
534
|
-
* 考虑到 JS 迭代器只能读取一次,这似乎不是一个合理的用例,
|
|
535
|
-
* 所以这种跟踪简化是可以接受的。
|
|
536
|
-
*
|
|
537
|
-
* @param self 目标数组
|
|
538
|
-
* @param method 迭代器方法名
|
|
539
|
-
* @param wrapValue 值包装函数,用于将值转换为响应式
|
|
540
|
-
* @returns 数组的迭代器
|
|
541
|
-
*/
|
|
542
|
-
function iterator(
|
|
543
|
-
self: unknown[],
|
|
544
|
-
method: keyof Array<unknown>,
|
|
545
|
-
wrapValue: (value: any) => unknown,
|
|
546
|
-
)
|
|
547
|
-
{
|
|
548
|
-
const arr = shallowReadArray(self);
|
|
549
|
-
const iter = (arr[method] as any)() as IterableIterator<unknown> & {
|
|
550
|
-
_next: IterableIterator<unknown>['next']
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
if (arr !== self)
|
|
554
|
-
{
|
|
555
|
-
iter._next = iter.next;
|
|
556
|
-
iter.next = () =>
|
|
557
|
-
{
|
|
558
|
-
const result = iter._next();
|
|
559
|
-
|
|
560
|
-
if (result.value)
|
|
561
|
-
{
|
|
562
|
-
result.value = wrapValue(result.value);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
return result;
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
return iter;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* 创建数组的浅层响应式副本。
|
|
574
|
-
*
|
|
575
|
-
* 实现了以下功能:
|
|
576
|
-
* 1. 跟踪数组的迭代操作
|
|
577
|
-
* 2. 返回原始数组的引用
|
|
578
|
-
*
|
|
579
|
-
* 注意:此函数只跟踪数组的迭代操作,不会递归转换数组中的值。
|
|
580
|
-
* 主要用于优化性能,避免不必要的响应式转换。
|
|
581
|
-
*
|
|
582
|
-
* @param arr 目标数组
|
|
583
|
-
* @returns 数组的浅层响应式副本
|
|
584
|
-
*/
|
|
585
|
-
function shallowReadArray<T>(arr: T[]): T[]
|
|
586
|
-
{
|
|
587
|
-
PropertyReactivity.track((arr = toRaw(arr)), TrackOpTypes.ITERATE, ARRAY_ITERATE_KEY);
|
|
588
|
-
|
|
589
|
-
return arr;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
/**
|
|
593
|
-
* 创建数组的深层响应式副本。
|
|
594
|
-
*
|
|
595
|
-
* 实现了以下功能:
|
|
596
|
-
* 1. 跟踪数组的迭代操作
|
|
597
|
-
* 2. 递归转换所有值为响应式
|
|
598
|
-
*
|
|
599
|
-
* 注意:此函数会递归转换数组中的所有值为响应式,
|
|
600
|
-
* 包括嵌套的数组和对象。这可能会导致性能开销,
|
|
601
|
-
* 但确保了所有值都是响应式的。
|
|
602
|
-
*
|
|
603
|
-
* @param array 目标数组
|
|
604
|
-
* @returns 数组的深层响应式副本
|
|
605
|
-
*/
|
|
606
|
-
function reactiveReadArray<T>(array: T[]): T[]
|
|
607
|
-
{
|
|
608
|
-
const raw = toRaw(array);
|
|
609
|
-
|
|
610
|
-
if (raw === array) return raw;
|
|
611
|
-
PropertyReactivity.track(raw, TrackOpTypes.ITERATE, ARRAY_ITERATE_KEY);
|
|
612
|
-
|
|
613
|
-
return raw.map(toReactive);
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
/**
|
|
617
|
-
* 数组方法类型。
|
|
618
|
-
*
|
|
619
|
-
* 包括所有需要增强的数组方法。
|
|
620
|
-
* 注意:在代码库中我们强制使用 es2016,但用户代码可能在更高版本的环境中运行。
|
|
621
|
-
*/
|
|
622
|
-
type ArrayMethods = keyof Array<any> | 'findLast' | 'findLastIndex';
|
|
623
|
-
|
|
624
|
-
/**
|
|
625
|
-
* 应用数组方法。
|
|
626
|
-
*
|
|
627
|
-
* 实现了以下功能:
|
|
628
|
-
* 1. 调用数组方法
|
|
629
|
-
* 2. 自动追踪数组的访问
|
|
630
|
-
* 3. 处理回调函数的执行
|
|
631
|
-
* 4. 处理返回值的转换
|
|
632
|
-
*
|
|
633
|
-
* 注意:如果调用的方法来自用户扩展的 Array,参数将是未知的
|
|
634
|
-
* (未知顺序和未知参数类型)。在这种情况下,我们跳过 shallowReadArray
|
|
635
|
-
* 处理,直接使用 self 调用 apply。
|
|
636
|
-
*
|
|
637
|
-
* @param self 目标数组
|
|
638
|
-
* @param method 方法名
|
|
639
|
-
* @param fn 回调函数
|
|
640
|
-
* @param thisArg 回调函数的 this 值
|
|
641
|
-
* @param wrappedRetFn 返回值包装函数,用于将返回值转换为响应式
|
|
642
|
-
* @param args 方法参数
|
|
643
|
-
* @returns 方法的执行结果
|
|
644
|
-
*/
|
|
645
|
-
function apply(
|
|
646
|
-
self: unknown[],
|
|
647
|
-
method: ArrayMethods,
|
|
648
|
-
fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
649
|
-
thisArg?: unknown,
|
|
650
|
-
wrappedRetFn?: (result: any) => unknown,
|
|
651
|
-
args?: IArguments,
|
|
652
|
-
)
|
|
653
|
-
{
|
|
654
|
-
const arr = shallowReadArray(self);
|
|
655
|
-
const needsWrap = arr !== self;
|
|
656
|
-
const methodFn = arr[method];
|
|
657
|
-
|
|
658
|
-
// #11759
|
|
659
|
-
// If the method being called is from a user-extended Array, the arguments will be unknown
|
|
660
|
-
// (unknown order and unknown parameter types). In this case, we skip the shallowReadArray
|
|
661
|
-
// handling and directly call apply with self.
|
|
662
|
-
if (methodFn !== Array.prototype[method as any])
|
|
663
|
-
{
|
|
664
|
-
const result = methodFn.apply(self, args);
|
|
665
|
-
|
|
666
|
-
return needsWrap ? toReactive(result) : result;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
let wrappedFn = fn;
|
|
670
|
-
|
|
671
|
-
if (arr !== self)
|
|
672
|
-
{
|
|
673
|
-
if (needsWrap)
|
|
674
|
-
{
|
|
675
|
-
wrappedFn = function (this: unknown, item, index)
|
|
676
|
-
{
|
|
677
|
-
return fn.call(this, toReactive(item), index, self);
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
else if (fn.length > 2)
|
|
681
|
-
{
|
|
682
|
-
wrappedFn = function (this: unknown, item, index)
|
|
683
|
-
{
|
|
684
|
-
return fn.call(this, item, index, self);
|
|
685
|
-
};
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
const result = methodFn.call(arr, wrappedFn, thisArg);
|
|
689
|
-
|
|
690
|
-
return needsWrap && wrappedRetFn ? wrappedRetFn(result) : result;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* 应用数组的归约方法。
|
|
695
|
-
*
|
|
696
|
-
* 实现了以下功能:
|
|
697
|
-
* 1. 调用数组的归约方法
|
|
698
|
-
* 2. 自动追踪数组的访问
|
|
699
|
-
* 3. 处理回调函数的执行
|
|
700
|
-
* 4. 处理响应式值的归约
|
|
701
|
-
*
|
|
702
|
-
* 注意:此函数用于处理 reduce 和 reduceRight 方法,
|
|
703
|
-
* 确保在归约过程中正确处理响应式值。
|
|
704
|
-
*
|
|
705
|
-
* @param self 目标数组
|
|
706
|
-
* @param method 方法名('reduce' 或 'reduceRight')
|
|
707
|
-
* @param fn 归约函数
|
|
708
|
-
* @param args 方法参数,包括初始值(可选)
|
|
709
|
-
* @returns 归约的结果
|
|
710
|
-
*/
|
|
711
|
-
function reduce(
|
|
712
|
-
self: unknown[],
|
|
713
|
-
method: keyof Array<any>,
|
|
714
|
-
fn: (acc: unknown, item: unknown, index: number, array: unknown[]) => unknown,
|
|
715
|
-
args: unknown[],
|
|
716
|
-
)
|
|
717
|
-
{
|
|
718
|
-
const arr = shallowReadArray(self);
|
|
719
|
-
let wrappedFn = fn;
|
|
720
|
-
|
|
721
|
-
if (arr !== self)
|
|
722
|
-
{
|
|
723
|
-
wrappedFn = function (this: unknown, acc, item, index)
|
|
724
|
-
{
|
|
725
|
-
return fn.call(this, acc, toReactive(item), index, self);
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
return (arr[method] as any)(wrappedFn, ...args);
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
/**
|
|
733
|
-
* 在数组中搜索元素。
|
|
734
|
-
*
|
|
735
|
-
* 实现了以下功能:
|
|
736
|
-
* 1. 处理响应式值的搜索
|
|
737
|
-
* 2. 自动追踪数组的访问
|
|
738
|
-
* 3. 处理代理对象的搜索
|
|
739
|
-
*
|
|
740
|
-
* 注意:我们首先使用原始参数(可能是响应式的)运行方法。
|
|
741
|
-
* 如果那不起作用,我们再次使用原始值运行。
|
|
742
|
-
* 这确保了在搜索响应式值时能够正确处理。
|
|
743
|
-
*
|
|
744
|
-
* @param self 目标数组
|
|
745
|
-
* @param method 方法名('includes'、'indexOf' 或 'lastIndexOf')
|
|
746
|
-
* @param args 搜索参数
|
|
747
|
-
* @returns 搜索的结果(布尔值或索引)
|
|
748
|
-
*/
|
|
749
|
-
function searchProxy(
|
|
750
|
-
self: unknown[],
|
|
751
|
-
method: keyof Array<any>,
|
|
752
|
-
args: unknown[],
|
|
753
|
-
)
|
|
754
|
-
{
|
|
755
|
-
const arr = toRaw(self) as any;
|
|
756
|
-
|
|
757
|
-
PropertyReactivity.track(arr, TrackOpTypes.ITERATE, ARRAY_ITERATE_KEY);
|
|
758
|
-
// we run the method using the original args first (which may be reactive)
|
|
759
|
-
const res = arr[method](...args);
|
|
760
|
-
|
|
761
|
-
// if that didn't work, run it again using raw values.
|
|
762
|
-
if ((res === -1 || res === false) && isProxy(args[0]))
|
|
763
|
-
{
|
|
764
|
-
args[0] = toRaw(args[0]);
|
|
765
|
-
|
|
766
|
-
return arr[method](...args);
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
return res;
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
/**
|
|
773
|
-
* 执行不跟踪的数组操作。
|
|
774
|
-
*
|
|
775
|
-
* 实现了以下功能:
|
|
776
|
-
* 1. 执行数组操作
|
|
777
|
-
* 2. 避免跟踪长度变化
|
|
778
|
-
* 3. 在批处理中执行操作
|
|
779
|
-
*
|
|
780
|
-
* 注意:这用于避免在某些情况下(#2137)由于跟踪长度变化而导致的无限循环。
|
|
781
|
-
* 通过使用批处理和禁用跟踪,我们可以安全地执行这些操作。
|
|
782
|
-
*
|
|
783
|
-
* @param self 目标数组
|
|
784
|
-
* @param method 方法名('push'、'pop'、'shift'、'unshift' 或 'splice')
|
|
785
|
-
* @param args 方法参数
|
|
786
|
-
* @returns 操作的执行结果
|
|
787
|
-
*/
|
|
788
|
-
function noTracking(
|
|
789
|
-
self: unknown[],
|
|
790
|
-
method: keyof Array<any>,
|
|
791
|
-
args: unknown[] = [],
|
|
792
|
-
)
|
|
793
|
-
{
|
|
794
|
-
const res = batchRun(() =>
|
|
795
|
-
noTrack(() =>
|
|
796
|
-
(toRaw(self) as any)[method].apply(self, args),
|
|
797
|
-
),
|
|
798
|
-
);
|
|
799
|
-
|
|
800
|
-
return res;
|
|
801
|
-
}
|
|
1
|
+
/* eslint-disable prefer-rest-params */
|
|
2
|
+
|
|
3
|
+
import { batchRun } from './batch';
|
|
4
|
+
import { noTrack } from './Reactivity';
|
|
5
|
+
import { PropertyReactivity } from './property';
|
|
6
|
+
import { isProxy, toReactive } from './reactive';
|
|
7
|
+
import { ARRAY_ITERATE_KEY, TrackOpTypes } from './shared/constants';
|
|
8
|
+
import { isArray, toRaw } from './shared/general';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 数组方法增强对象。
|
|
12
|
+
*
|
|
13
|
+
* 为数组提供响应式增强的方法实现,包括:
|
|
14
|
+
* 1. 迭代器方法:Symbol.iterator、entries、keys、values
|
|
15
|
+
* 2. 查找方法:includes、indexOf、lastIndexOf、find、findIndex、findLast、findLastIndex
|
|
16
|
+
* 3. 遍历方法:forEach、map、filter、some、every、reduce、reduceRight
|
|
17
|
+
* 4. 修改方法:push、pop、shift、unshift、splice、toReversed、toSorted、toSpliced
|
|
18
|
+
* 5. 其他方法:concat、join
|
|
19
|
+
*/
|
|
20
|
+
export const arrayInstrumentations: Record<string | symbol, Function> = <any>{
|
|
21
|
+
__proto__: null,
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 返回一个迭代器,用于遍历数组的响应式值。
|
|
25
|
+
*
|
|
26
|
+
* 实现了以下功能:
|
|
27
|
+
* 1. 创建数组的迭代器
|
|
28
|
+
* 2. 自动将迭代的值转换为响应式
|
|
29
|
+
* 3. 自动追踪数组的访问
|
|
30
|
+
*
|
|
31
|
+
* @returns 数组的迭代器
|
|
32
|
+
*/
|
|
33
|
+
[Symbol.iterator]()
|
|
34
|
+
{
|
|
35
|
+
return iterator(this, Symbol.iterator, toReactive);
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 连接数组并返回新数组。
|
|
40
|
+
*
|
|
41
|
+
* 实现了以下功能:
|
|
42
|
+
* 1. 处理响应式数组的连接
|
|
43
|
+
* 2. 自动将参数中的数组转换为响应式
|
|
44
|
+
* 3. 保持原始值的引用
|
|
45
|
+
*
|
|
46
|
+
* @param args 要连接的数组或值
|
|
47
|
+
* @returns 连接后的新数组
|
|
48
|
+
*/
|
|
49
|
+
concat(...args: unknown[])
|
|
50
|
+
{
|
|
51
|
+
return reactiveReadArray(this).concat(
|
|
52
|
+
...args.map((x) => (isArray(x) ? reactiveReadArray(x) : x)),
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 返回一个迭代器,用于遍历数组的键值对。
|
|
58
|
+
*
|
|
59
|
+
* 实现了以下功能:
|
|
60
|
+
* 1. 创建数组的键值对迭代器
|
|
61
|
+
* 2. 自动将值转换为响应式
|
|
62
|
+
* 3. 自动追踪数组的访问
|
|
63
|
+
*
|
|
64
|
+
* @returns 数组的键值对迭代器
|
|
65
|
+
*/
|
|
66
|
+
entries()
|
|
67
|
+
{
|
|
68
|
+
return iterator(this, 'entries', (value: [number, unknown]) =>
|
|
69
|
+
{
|
|
70
|
+
value[1] = toReactive(value[1]);
|
|
71
|
+
|
|
72
|
+
return value;
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 测试数组中的所有元素是否都通过了指定函数的测试。
|
|
78
|
+
*
|
|
79
|
+
* 实现了以下功能:
|
|
80
|
+
* 1. 遍历数组元素
|
|
81
|
+
* 2. 对每个元素执行测试函数
|
|
82
|
+
* 3. 自动追踪数组的访问
|
|
83
|
+
* 4. 处理响应式值的测试
|
|
84
|
+
*
|
|
85
|
+
* @param fn 测试函数
|
|
86
|
+
* @param thisArg 测试函数的 this 值
|
|
87
|
+
* @returns 如果所有元素都通过测试则返回 true,否则返回 false
|
|
88
|
+
*/
|
|
89
|
+
every(fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
90
|
+
thisArg?: unknown,
|
|
91
|
+
)
|
|
92
|
+
{
|
|
93
|
+
return apply(this, 'every', fn, thisArg, undefined, arguments);
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 创建一个新数组,包含通过指定函数测试的所有元素。
|
|
98
|
+
*
|
|
99
|
+
* 实现了以下功能:
|
|
100
|
+
* 1. 遍历数组元素
|
|
101
|
+
* 2. 对每个元素执行测试函数
|
|
102
|
+
* 3. 自动追踪数组的访问
|
|
103
|
+
* 4. 自动将结果转换为响应式
|
|
104
|
+
*
|
|
105
|
+
* @param fn 测试函数
|
|
106
|
+
* @param thisArg 测试函数的 this 值
|
|
107
|
+
* @returns 包含通过测试的元素的新数组
|
|
108
|
+
*/
|
|
109
|
+
filter(fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
110
|
+
thisArg?: unknown,
|
|
111
|
+
)
|
|
112
|
+
{
|
|
113
|
+
return apply(this, 'filter', fn, thisArg, (v) => v.map(toReactive), arguments);
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 返回数组中满足指定测试函数的第一个元素。
|
|
118
|
+
*
|
|
119
|
+
* 实现了以下功能:
|
|
120
|
+
* 1. 遍历数组元素
|
|
121
|
+
* 2. 对每个元素执行测试函数
|
|
122
|
+
* 3. 自动追踪数组的访问
|
|
123
|
+
* 4. 自动将结果转换为响应式
|
|
124
|
+
*
|
|
125
|
+
* @param fn 测试函数
|
|
126
|
+
* @param thisArg 测试函数的 this 值
|
|
127
|
+
* @returns 第一个满足测试的元素,如果没有则返回 undefined
|
|
128
|
+
*/
|
|
129
|
+
find(fn: (item: unknown, index: number, array: unknown[]) => boolean,
|
|
130
|
+
thisArg?: unknown,
|
|
131
|
+
)
|
|
132
|
+
{
|
|
133
|
+
return apply(this, 'find', fn, thisArg, toReactive, arguments);
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 返回数组中满足指定测试函数的第一个元素的索引。
|
|
138
|
+
*
|
|
139
|
+
* 实现了以下功能:
|
|
140
|
+
* 1. 遍历数组元素
|
|
141
|
+
* 2. 对每个元素执行测试函数
|
|
142
|
+
* 3. 自动追踪数组的访问
|
|
143
|
+
* 4. 处理响应式值的查找
|
|
144
|
+
*
|
|
145
|
+
* @param fn 测试函数
|
|
146
|
+
* @param thisArg 测试函数的 this 值
|
|
147
|
+
* @returns 第一个满足测试的元素的索引,如果没有则返回 -1
|
|
148
|
+
*/
|
|
149
|
+
findIndex(fn: (item: unknown, index: number, array: unknown[]) => boolean,
|
|
150
|
+
thisArg?: unknown,
|
|
151
|
+
)
|
|
152
|
+
{
|
|
153
|
+
return apply(this, 'findIndex', fn, thisArg, undefined, arguments);
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 返回数组中满足指定测试函数的最后一个元素。
|
|
158
|
+
*
|
|
159
|
+
* 实现了以下功能:
|
|
160
|
+
* 1. 从后向前遍历数组元素
|
|
161
|
+
* 2. 对每个元素执行测试函数
|
|
162
|
+
* 3. 自动追踪数组的访问
|
|
163
|
+
* 4. 自动将结果转换为响应式
|
|
164
|
+
*
|
|
165
|
+
* @param fn 测试函数
|
|
166
|
+
* @param thisArg 测试函数的 this 值
|
|
167
|
+
* @returns 最后一个满足测试的元素,如果没有则返回 undefined
|
|
168
|
+
*/
|
|
169
|
+
findLast(fn: (item: unknown, index: number, array: unknown[]) => boolean,
|
|
170
|
+
thisArg?: unknown,
|
|
171
|
+
)
|
|
172
|
+
{
|
|
173
|
+
return apply(this, 'findLast', fn, thisArg, toReactive, arguments);
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* 返回数组中满足指定测试函数的最后一个元素的索引。
|
|
178
|
+
*
|
|
179
|
+
* 实现了以下功能:
|
|
180
|
+
* 1. 从后向前遍历数组元素
|
|
181
|
+
* 2. 对每个元素执行测试函数
|
|
182
|
+
* 3. 自动追踪数组的访问
|
|
183
|
+
* 4. 处理响应式值的查找
|
|
184
|
+
*
|
|
185
|
+
* @param fn 测试函数
|
|
186
|
+
* @param thisArg 测试函数的 this 值
|
|
187
|
+
* @returns 最后一个满足测试的元素的索引,如果没有则返回 -1
|
|
188
|
+
*/
|
|
189
|
+
findLastIndex(fn: (item: unknown, index: number, array: unknown[]) => boolean,
|
|
190
|
+
thisArg?: unknown,
|
|
191
|
+
)
|
|
192
|
+
{
|
|
193
|
+
return apply(this, 'findLastIndex', fn, thisArg, undefined, arguments);
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
// flat, flatMap 可以从 ARRAY_ITERATE 中受益,但实现起来不太直接
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 对数组中的每个元素执行指定函数。
|
|
200
|
+
*
|
|
201
|
+
* 实现了以下功能:
|
|
202
|
+
* 1. 遍历数组元素
|
|
203
|
+
* 2. 对每个元素执行回调函数
|
|
204
|
+
* 3. 自动追踪数组的访问
|
|
205
|
+
* 4. 处理响应式值的遍历
|
|
206
|
+
*
|
|
207
|
+
* @param fn 回调函数
|
|
208
|
+
* @param thisArg 回调函数的 this 值
|
|
209
|
+
*/
|
|
210
|
+
forEach(fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
211
|
+
thisArg?: unknown,
|
|
212
|
+
)
|
|
213
|
+
{
|
|
214
|
+
return apply(this, 'forEach', fn, thisArg, undefined, arguments);
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 判断数组是否包含指定元素。
|
|
219
|
+
*
|
|
220
|
+
* 实现了以下功能:
|
|
221
|
+
* 1. 处理响应式值的查找
|
|
222
|
+
* 2. 自动追踪数组的访问
|
|
223
|
+
* 3. 处理代理对象的查找
|
|
224
|
+
*
|
|
225
|
+
* @param args 要查找的元素
|
|
226
|
+
* @returns 如果数组包含该元素则返回 true,否则返回 false
|
|
227
|
+
*/
|
|
228
|
+
includes(...args: unknown[])
|
|
229
|
+
{
|
|
230
|
+
return searchProxy(this, 'includes' as any, args);
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* 返回数组中指定元素第一次出现的索引。
|
|
235
|
+
*
|
|
236
|
+
* 实现了以下功能:
|
|
237
|
+
* 1. 处理响应式值的查找
|
|
238
|
+
* 2. 自动追踪数组的访问
|
|
239
|
+
* 3. 处理代理对象的查找
|
|
240
|
+
*
|
|
241
|
+
* @param args 要查找的元素
|
|
242
|
+
* @returns 元素第一次出现的索引,如果没有则返回 -1
|
|
243
|
+
*/
|
|
244
|
+
indexOf(...args: unknown[])
|
|
245
|
+
{
|
|
246
|
+
return searchProxy(this, 'indexOf', args);
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* 将数组的所有元素连接成一个字符串。
|
|
251
|
+
*
|
|
252
|
+
* 实现了以下功能:
|
|
253
|
+
* 1. 处理响应式数组的连接
|
|
254
|
+
* 2. 自动追踪数组的访问
|
|
255
|
+
* 3. 保持原始值的引用
|
|
256
|
+
*
|
|
257
|
+
* @param separator 分隔符
|
|
258
|
+
* @returns 连接后的字符串
|
|
259
|
+
*/
|
|
260
|
+
join(separator?: string)
|
|
261
|
+
{
|
|
262
|
+
return reactiveReadArray(this).join(separator);
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
// keys() 迭代器只读取 length,不需要优化
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* 返回数组中指定元素最后一次出现的索引。
|
|
269
|
+
*
|
|
270
|
+
* 实现了以下功能:
|
|
271
|
+
* 1. 处理响应式值的查找
|
|
272
|
+
* 2. 自动追踪数组的访问
|
|
273
|
+
* 3. 处理代理对象的查找
|
|
274
|
+
*
|
|
275
|
+
* @param args 要查找的元素
|
|
276
|
+
* @returns 元素最后一次出现的索引,如果没有则返回 -1
|
|
277
|
+
*/
|
|
278
|
+
lastIndexOf(...args: unknown[])
|
|
279
|
+
{
|
|
280
|
+
return searchProxy(this, 'lastIndexOf', args);
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* 创建一个新数组,包含对原数组每个元素调用指定函数的结果。
|
|
285
|
+
*
|
|
286
|
+
* 实现了以下功能:
|
|
287
|
+
* 1. 遍历数组元素
|
|
288
|
+
* 2. 对每个元素执行映射函数
|
|
289
|
+
* 3. 自动追踪数组的访问
|
|
290
|
+
* 4. 处理响应式值的映射
|
|
291
|
+
*
|
|
292
|
+
* @param fn 映射函数
|
|
293
|
+
* @param thisArg 映射函数的 this 值
|
|
294
|
+
* @returns 包含映射结果的新数组
|
|
295
|
+
*/
|
|
296
|
+
map(fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
297
|
+
thisArg?: unknown,
|
|
298
|
+
)
|
|
299
|
+
{
|
|
300
|
+
return apply(this, 'map', fn, thisArg, undefined, arguments);
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* 移除数组的最后一个元素并返回该元素。
|
|
305
|
+
*
|
|
306
|
+
* 实现了以下功能:
|
|
307
|
+
* 1. 移除最后一个元素
|
|
308
|
+
* 2. 避免跟踪长度变化
|
|
309
|
+
* 3. 处理响应式值的移除
|
|
310
|
+
*
|
|
311
|
+
* @returns 被移除的元素
|
|
312
|
+
*/
|
|
313
|
+
pop()
|
|
314
|
+
{
|
|
315
|
+
return noTracking(this, 'pop');
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* 向数组末尾添加一个或多个元素。
|
|
320
|
+
*
|
|
321
|
+
* 实现了以下功能:
|
|
322
|
+
* 1. 添加新元素
|
|
323
|
+
* 2. 避免跟踪长度变化
|
|
324
|
+
* 3. 处理响应式值的添加
|
|
325
|
+
*
|
|
326
|
+
* @param args 要添加的元素
|
|
327
|
+
* @returns 数组的新长度
|
|
328
|
+
*/
|
|
329
|
+
push(...args: unknown[])
|
|
330
|
+
{
|
|
331
|
+
return noTracking(this, 'push', args);
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* 对数组中的每个元素执行累加器函数。
|
|
336
|
+
*
|
|
337
|
+
* 实现了以下功能:
|
|
338
|
+
* 1. 从左到右遍历数组元素
|
|
339
|
+
* 2. 对每个元素执行累加器函数
|
|
340
|
+
* 3. 自动追踪数组的访问
|
|
341
|
+
* 4. 处理响应式值的累加
|
|
342
|
+
*
|
|
343
|
+
* @param fn 累加器函数
|
|
344
|
+
* @param args 初始值(可选)
|
|
345
|
+
* @returns 累加的结果
|
|
346
|
+
*/
|
|
347
|
+
reduce(fn: (
|
|
348
|
+
acc: unknown,
|
|
349
|
+
item: unknown,
|
|
350
|
+
index: number,
|
|
351
|
+
array: unknown[],
|
|
352
|
+
) => unknown,
|
|
353
|
+
...args: unknown[]
|
|
354
|
+
)
|
|
355
|
+
{
|
|
356
|
+
return reduce(this, 'reduce', fn, args);
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* 从右到左对数组中的每个元素执行累加器函数。
|
|
361
|
+
*
|
|
362
|
+
* 实现了以下功能:
|
|
363
|
+
* 1. 从右到左遍历数组元素
|
|
364
|
+
* 2. 对每个元素执行累加器函数
|
|
365
|
+
* 3. 自动追踪数组的访问
|
|
366
|
+
* 4. 处理响应式值的累加
|
|
367
|
+
*
|
|
368
|
+
* @param fn 累加器函数
|
|
369
|
+
* @param args 初始值(可选)
|
|
370
|
+
* @returns 累加的结果
|
|
371
|
+
*/
|
|
372
|
+
reduceRight(
|
|
373
|
+
fn: (
|
|
374
|
+
acc: unknown,
|
|
375
|
+
item: unknown,
|
|
376
|
+
index: number,
|
|
377
|
+
array: unknown[],
|
|
378
|
+
) => unknown,
|
|
379
|
+
...args: unknown[]
|
|
380
|
+
)
|
|
381
|
+
{
|
|
382
|
+
return reduce(this, 'reduceRight', fn, args);
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* 移除数组的第一个元素并返回该元素。
|
|
387
|
+
*
|
|
388
|
+
* 实现了以下功能:
|
|
389
|
+
* 1. 移除第一个元素
|
|
390
|
+
* 2. 避免跟踪长度变化
|
|
391
|
+
* 3. 处理响应式值的移除
|
|
392
|
+
*
|
|
393
|
+
* @returns 被移除的元素
|
|
394
|
+
*/
|
|
395
|
+
shift()
|
|
396
|
+
{
|
|
397
|
+
return noTracking(this, 'shift');
|
|
398
|
+
},
|
|
399
|
+
|
|
400
|
+
// slice 可以使用 ARRAY_ITERATE,但似乎也需要范围追踪
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* 测试数组中的某些元素是否通过了指定函数的测试。
|
|
404
|
+
*
|
|
405
|
+
* 实现了以下功能:
|
|
406
|
+
* 1. 遍历数组元素
|
|
407
|
+
* 2. 对每个元素执行测试函数
|
|
408
|
+
* 3. 自动追踪数组的访问
|
|
409
|
+
* 4. 处理响应式值的测试
|
|
410
|
+
*
|
|
411
|
+
* @param fn 测试函数
|
|
412
|
+
* @param thisArg 测试函数的 this 值
|
|
413
|
+
* @returns 如果有元素通过测试则返回 true,否则返回 false
|
|
414
|
+
*/
|
|
415
|
+
some(
|
|
416
|
+
fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
417
|
+
thisArg?: unknown,
|
|
418
|
+
)
|
|
419
|
+
{
|
|
420
|
+
return apply(this, 'some', fn, thisArg, undefined, arguments);
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* 通过删除或替换现有元素或添加新元素来修改数组。
|
|
425
|
+
*
|
|
426
|
+
* 实现了以下功能:
|
|
427
|
+
* 1. 修改数组内容
|
|
428
|
+
* 2. 避免跟踪长度变化
|
|
429
|
+
* 3. 处理响应式值的修改
|
|
430
|
+
*
|
|
431
|
+
* @param args 要删除的起始索引、要删除的元素数量和要添加的元素
|
|
432
|
+
* @returns 包含被删除元素的新数组
|
|
433
|
+
*/
|
|
434
|
+
splice(...args: unknown[])
|
|
435
|
+
{
|
|
436
|
+
return noTracking(this, 'splice', args);
|
|
437
|
+
},
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* 返回一个新数组,包含原数组的反转副本。
|
|
441
|
+
*
|
|
442
|
+
* 实现了以下功能:
|
|
443
|
+
* 1. 创建数组的反转副本
|
|
444
|
+
* 2. 自动将结果转换为响应式
|
|
445
|
+
* 3. 保持原始值的引用
|
|
446
|
+
*
|
|
447
|
+
* @returns 反转后的新数组
|
|
448
|
+
*/
|
|
449
|
+
toReversed()
|
|
450
|
+
{
|
|
451
|
+
// @ts-expect-error user code may run in es2016+
|
|
452
|
+
return reactiveReadArray(this).toReversed();
|
|
453
|
+
},
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* 返回一个新数组,包含原数组的排序副本。
|
|
457
|
+
*
|
|
458
|
+
* 实现了以下功能:
|
|
459
|
+
* 1. 创建数组的排序副本
|
|
460
|
+
* 2. 自动将结果转换为响应式
|
|
461
|
+
* 3. 保持原始值的引用
|
|
462
|
+
*
|
|
463
|
+
* @param comparer 比较函数
|
|
464
|
+
* @returns 排序后的新数组
|
|
465
|
+
*/
|
|
466
|
+
toSorted(comparer?: (a: unknown, b: unknown) => number)
|
|
467
|
+
{
|
|
468
|
+
// @ts-expect-error user code may run in es2016+
|
|
469
|
+
return reactiveReadArray(this).toSorted(comparer);
|
|
470
|
+
},
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* 返回一个新数组,包含原数组的切片副本。
|
|
474
|
+
*
|
|
475
|
+
* 实现了以下功能:
|
|
476
|
+
* 1. 创建数组的切片副本
|
|
477
|
+
* 2. 自动将结果转换为响应式
|
|
478
|
+
* 3. 保持原始值的引用
|
|
479
|
+
*
|
|
480
|
+
* @param args 起始索引和结束索引
|
|
481
|
+
* @returns 切片后的新数组
|
|
482
|
+
*/
|
|
483
|
+
toSpliced(...args: unknown[])
|
|
484
|
+
{
|
|
485
|
+
// @ts-expect-error user code may run in es2016+
|
|
486
|
+
return reactiveReadArray(this).toSpliced(...args);
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* 向数组开头添加一个或多个元素。
|
|
491
|
+
*
|
|
492
|
+
* 实现了以下功能:
|
|
493
|
+
* 1. 添加新元素
|
|
494
|
+
* 2. 避免跟踪长度变化
|
|
495
|
+
* 3. 处理响应式值的添加
|
|
496
|
+
*
|
|
497
|
+
* @param args 要添加的元素
|
|
498
|
+
* @returns 数组的新长度
|
|
499
|
+
*/
|
|
500
|
+
unshift(...args: unknown[])
|
|
501
|
+
{
|
|
502
|
+
return noTracking(this, 'unshift', args);
|
|
503
|
+
},
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* 返回一个迭代器,用于遍历数组的值。
|
|
507
|
+
*
|
|
508
|
+
* 实现了以下功能:
|
|
509
|
+
* 1. 创建数组的值迭代器
|
|
510
|
+
* 2. 自动将迭代的值转换为响应式
|
|
511
|
+
* 3. 自动追踪数组的访问
|
|
512
|
+
*
|
|
513
|
+
* @returns 数组的值迭代器
|
|
514
|
+
*/
|
|
515
|
+
values()
|
|
516
|
+
{
|
|
517
|
+
return iterator(this, 'values', toReactive);
|
|
518
|
+
},
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* 创建数组的迭代器。
|
|
523
|
+
*
|
|
524
|
+
* 实现了以下功能:
|
|
525
|
+
* 1. 创建数组的迭代器
|
|
526
|
+
* 2. 自动将迭代的值转换为响应式
|
|
527
|
+
* 3. 自动追踪数组的访问
|
|
528
|
+
*
|
|
529
|
+
* 注意:在这里获取 ARRAY_ITERATE 依赖并不完全等同于在代理数组上调用迭代。
|
|
530
|
+
* 创建迭代器时不会访问任何数组属性:
|
|
531
|
+
* 只有在调用 .next() 时才会访问 length 和索引。
|
|
532
|
+
* 从极端情况来看,迭代器可以在一个 effect scope 中创建,
|
|
533
|
+
* 在另一个 scope 中部分迭代,然后在第三个 scope 中继续迭代。
|
|
534
|
+
* 考虑到 JS 迭代器只能读取一次,这似乎不是一个合理的用例,
|
|
535
|
+
* 所以这种跟踪简化是可以接受的。
|
|
536
|
+
*
|
|
537
|
+
* @param self 目标数组
|
|
538
|
+
* @param method 迭代器方法名
|
|
539
|
+
* @param wrapValue 值包装函数,用于将值转换为响应式
|
|
540
|
+
* @returns 数组的迭代器
|
|
541
|
+
*/
|
|
542
|
+
function iterator(
|
|
543
|
+
self: unknown[],
|
|
544
|
+
method: keyof Array<unknown>,
|
|
545
|
+
wrapValue: (value: any) => unknown,
|
|
546
|
+
)
|
|
547
|
+
{
|
|
548
|
+
const arr = shallowReadArray(self);
|
|
549
|
+
const iter = (arr[method] as any)() as IterableIterator<unknown> & {
|
|
550
|
+
_next: IterableIterator<unknown>['next']
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
if (arr !== self)
|
|
554
|
+
{
|
|
555
|
+
iter._next = iter.next;
|
|
556
|
+
iter.next = () =>
|
|
557
|
+
{
|
|
558
|
+
const result = iter._next();
|
|
559
|
+
|
|
560
|
+
if (result.value)
|
|
561
|
+
{
|
|
562
|
+
result.value = wrapValue(result.value);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return result;
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return iter;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* 创建数组的浅层响应式副本。
|
|
574
|
+
*
|
|
575
|
+
* 实现了以下功能:
|
|
576
|
+
* 1. 跟踪数组的迭代操作
|
|
577
|
+
* 2. 返回原始数组的引用
|
|
578
|
+
*
|
|
579
|
+
* 注意:此函数只跟踪数组的迭代操作,不会递归转换数组中的值。
|
|
580
|
+
* 主要用于优化性能,避免不必要的响应式转换。
|
|
581
|
+
*
|
|
582
|
+
* @param arr 目标数组
|
|
583
|
+
* @returns 数组的浅层响应式副本
|
|
584
|
+
*/
|
|
585
|
+
function shallowReadArray<T>(arr: T[]): T[]
|
|
586
|
+
{
|
|
587
|
+
PropertyReactivity.track((arr = toRaw(arr)), TrackOpTypes.ITERATE, ARRAY_ITERATE_KEY);
|
|
588
|
+
|
|
589
|
+
return arr;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* 创建数组的深层响应式副本。
|
|
594
|
+
*
|
|
595
|
+
* 实现了以下功能:
|
|
596
|
+
* 1. 跟踪数组的迭代操作
|
|
597
|
+
* 2. 递归转换所有值为响应式
|
|
598
|
+
*
|
|
599
|
+
* 注意:此函数会递归转换数组中的所有值为响应式,
|
|
600
|
+
* 包括嵌套的数组和对象。这可能会导致性能开销,
|
|
601
|
+
* 但确保了所有值都是响应式的。
|
|
602
|
+
*
|
|
603
|
+
* @param array 目标数组
|
|
604
|
+
* @returns 数组的深层响应式副本
|
|
605
|
+
*/
|
|
606
|
+
function reactiveReadArray<T>(array: T[]): T[]
|
|
607
|
+
{
|
|
608
|
+
const raw = toRaw(array);
|
|
609
|
+
|
|
610
|
+
if (raw === array) return raw;
|
|
611
|
+
PropertyReactivity.track(raw, TrackOpTypes.ITERATE, ARRAY_ITERATE_KEY);
|
|
612
|
+
|
|
613
|
+
return raw.map(toReactive);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* 数组方法类型。
|
|
618
|
+
*
|
|
619
|
+
* 包括所有需要增强的数组方法。
|
|
620
|
+
* 注意:在代码库中我们强制使用 es2016,但用户代码可能在更高版本的环境中运行。
|
|
621
|
+
*/
|
|
622
|
+
type ArrayMethods = keyof Array<any> | 'findLast' | 'findLastIndex';
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* 应用数组方法。
|
|
626
|
+
*
|
|
627
|
+
* 实现了以下功能:
|
|
628
|
+
* 1. 调用数组方法
|
|
629
|
+
* 2. 自动追踪数组的访问
|
|
630
|
+
* 3. 处理回调函数的执行
|
|
631
|
+
* 4. 处理返回值的转换
|
|
632
|
+
*
|
|
633
|
+
* 注意:如果调用的方法来自用户扩展的 Array,参数将是未知的
|
|
634
|
+
* (未知顺序和未知参数类型)。在这种情况下,我们跳过 shallowReadArray
|
|
635
|
+
* 处理,直接使用 self 调用 apply。
|
|
636
|
+
*
|
|
637
|
+
* @param self 目标数组
|
|
638
|
+
* @param method 方法名
|
|
639
|
+
* @param fn 回调函数
|
|
640
|
+
* @param thisArg 回调函数的 this 值
|
|
641
|
+
* @param wrappedRetFn 返回值包装函数,用于将返回值转换为响应式
|
|
642
|
+
* @param args 方法参数
|
|
643
|
+
* @returns 方法的执行结果
|
|
644
|
+
*/
|
|
645
|
+
function apply(
|
|
646
|
+
self: unknown[],
|
|
647
|
+
method: ArrayMethods,
|
|
648
|
+
fn: (item: unknown, index: number, array: unknown[]) => unknown,
|
|
649
|
+
thisArg?: unknown,
|
|
650
|
+
wrappedRetFn?: (result: any) => unknown,
|
|
651
|
+
args?: IArguments,
|
|
652
|
+
)
|
|
653
|
+
{
|
|
654
|
+
const arr = shallowReadArray(self);
|
|
655
|
+
const needsWrap = arr !== self;
|
|
656
|
+
const methodFn = arr[method];
|
|
657
|
+
|
|
658
|
+
// #11759
|
|
659
|
+
// If the method being called is from a user-extended Array, the arguments will be unknown
|
|
660
|
+
// (unknown order and unknown parameter types). In this case, we skip the shallowReadArray
|
|
661
|
+
// handling and directly call apply with self.
|
|
662
|
+
if (methodFn !== Array.prototype[method as any])
|
|
663
|
+
{
|
|
664
|
+
const result = methodFn.apply(self, args);
|
|
665
|
+
|
|
666
|
+
return needsWrap ? toReactive(result) : result;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
let wrappedFn = fn;
|
|
670
|
+
|
|
671
|
+
if (arr !== self)
|
|
672
|
+
{
|
|
673
|
+
if (needsWrap)
|
|
674
|
+
{
|
|
675
|
+
wrappedFn = function (this: unknown, item, index)
|
|
676
|
+
{
|
|
677
|
+
return fn.call(this, toReactive(item), index, self);
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
else if (fn.length > 2)
|
|
681
|
+
{
|
|
682
|
+
wrappedFn = function (this: unknown, item, index)
|
|
683
|
+
{
|
|
684
|
+
return fn.call(this, item, index, self);
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
const result = methodFn.call(arr, wrappedFn, thisArg);
|
|
689
|
+
|
|
690
|
+
return needsWrap && wrappedRetFn ? wrappedRetFn(result) : result;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* 应用数组的归约方法。
|
|
695
|
+
*
|
|
696
|
+
* 实现了以下功能:
|
|
697
|
+
* 1. 调用数组的归约方法
|
|
698
|
+
* 2. 自动追踪数组的访问
|
|
699
|
+
* 3. 处理回调函数的执行
|
|
700
|
+
* 4. 处理响应式值的归约
|
|
701
|
+
*
|
|
702
|
+
* 注意:此函数用于处理 reduce 和 reduceRight 方法,
|
|
703
|
+
* 确保在归约过程中正确处理响应式值。
|
|
704
|
+
*
|
|
705
|
+
* @param self 目标数组
|
|
706
|
+
* @param method 方法名('reduce' 或 'reduceRight')
|
|
707
|
+
* @param fn 归约函数
|
|
708
|
+
* @param args 方法参数,包括初始值(可选)
|
|
709
|
+
* @returns 归约的结果
|
|
710
|
+
*/
|
|
711
|
+
function reduce(
|
|
712
|
+
self: unknown[],
|
|
713
|
+
method: keyof Array<any>,
|
|
714
|
+
fn: (acc: unknown, item: unknown, index: number, array: unknown[]) => unknown,
|
|
715
|
+
args: unknown[],
|
|
716
|
+
)
|
|
717
|
+
{
|
|
718
|
+
const arr = shallowReadArray(self);
|
|
719
|
+
let wrappedFn = fn;
|
|
720
|
+
|
|
721
|
+
if (arr !== self)
|
|
722
|
+
{
|
|
723
|
+
wrappedFn = function (this: unknown, acc, item, index)
|
|
724
|
+
{
|
|
725
|
+
return fn.call(this, acc, toReactive(item), index, self);
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
return (arr[method] as any)(wrappedFn, ...args);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* 在数组中搜索元素。
|
|
734
|
+
*
|
|
735
|
+
* 实现了以下功能:
|
|
736
|
+
* 1. 处理响应式值的搜索
|
|
737
|
+
* 2. 自动追踪数组的访问
|
|
738
|
+
* 3. 处理代理对象的搜索
|
|
739
|
+
*
|
|
740
|
+
* 注意:我们首先使用原始参数(可能是响应式的)运行方法。
|
|
741
|
+
* 如果那不起作用,我们再次使用原始值运行。
|
|
742
|
+
* 这确保了在搜索响应式值时能够正确处理。
|
|
743
|
+
*
|
|
744
|
+
* @param self 目标数组
|
|
745
|
+
* @param method 方法名('includes'、'indexOf' 或 'lastIndexOf')
|
|
746
|
+
* @param args 搜索参数
|
|
747
|
+
* @returns 搜索的结果(布尔值或索引)
|
|
748
|
+
*/
|
|
749
|
+
function searchProxy(
|
|
750
|
+
self: unknown[],
|
|
751
|
+
method: keyof Array<any>,
|
|
752
|
+
args: unknown[],
|
|
753
|
+
)
|
|
754
|
+
{
|
|
755
|
+
const arr = toRaw(self) as any;
|
|
756
|
+
|
|
757
|
+
PropertyReactivity.track(arr, TrackOpTypes.ITERATE, ARRAY_ITERATE_KEY);
|
|
758
|
+
// we run the method using the original args first (which may be reactive)
|
|
759
|
+
const res = arr[method](...args);
|
|
760
|
+
|
|
761
|
+
// if that didn't work, run it again using raw values.
|
|
762
|
+
if ((res === -1 || res === false) && isProxy(args[0]))
|
|
763
|
+
{
|
|
764
|
+
args[0] = toRaw(args[0]);
|
|
765
|
+
|
|
766
|
+
return arr[method](...args);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
return res;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* 执行不跟踪的数组操作。
|
|
774
|
+
*
|
|
775
|
+
* 实现了以下功能:
|
|
776
|
+
* 1. 执行数组操作
|
|
777
|
+
* 2. 避免跟踪长度变化
|
|
778
|
+
* 3. 在批处理中执行操作
|
|
779
|
+
*
|
|
780
|
+
* 注意:这用于避免在某些情况下(#2137)由于跟踪长度变化而导致的无限循环。
|
|
781
|
+
* 通过使用批处理和禁用跟踪,我们可以安全地执行这些操作。
|
|
782
|
+
*
|
|
783
|
+
* @param self 目标数组
|
|
784
|
+
* @param method 方法名('push'、'pop'、'shift'、'unshift' 或 'splice')
|
|
785
|
+
* @param args 方法参数
|
|
786
|
+
* @returns 操作的执行结果
|
|
787
|
+
*/
|
|
788
|
+
function noTracking(
|
|
789
|
+
self: unknown[],
|
|
790
|
+
method: keyof Array<any>,
|
|
791
|
+
args: unknown[] = [],
|
|
792
|
+
)
|
|
793
|
+
{
|
|
794
|
+
const res = batchRun(() =>
|
|
795
|
+
noTrack(() =>
|
|
796
|
+
(toRaw(self) as any)[method].apply(self, args),
|
|
797
|
+
),
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
return res;
|
|
801
|
+
}
|