@feng3d/reactivity 1.0.6 → 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 -3
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +91 -5
- 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 +5 -4
- package/lib/index.d.ts.map +1 -1
- package/package.json +69 -72
- 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-9zMEdmDL.js +0 -2540
- package/dist/assets/src//345/244/215/346/235/202/346/203/205/345/206/265/345/217/226/345/200/274/index.html-a69uOZEV.js +0 -59
- package/dist/assets/src//346/225/260/347/273/204/index.html-CaZ_5kCZ.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/ComputedReactivity.html +0 -72
- package/dist/docs/classes/EffectReactivity.html +0 -62
- package/dist/docs/classes/EffectScope.html +0 -40
- package/dist/docs/classes/Reactivity.html +0 -35
- package/dist/docs/classes/RefReactivity.html +0 -57
- 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,486 +1,486 @@
|
|
|
1
|
-
import { toReactive } from './reactive';
|
|
2
|
-
import { ITERATE_KEY, MAP_KEY_ITERATE_KEY, ReactiveFlags, TrackOpTypes, TriggerOpTypes } from './shared/constants';
|
|
3
|
-
import { hasChanged, hasOwn, isMap, Target, toRaw, toRawType, warn } from './shared/general';
|
|
4
|
-
import { PropertyReactivity } from './property';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 可变集合响应式处理器。
|
|
8
|
-
*
|
|
9
|
-
* 用于处理集合类型(Map、Set、WeakMap、WeakSet)的响应式代理。
|
|
10
|
-
* 通过拦截集合的操作方法,实现响应式功能。
|
|
11
|
-
*/
|
|
12
|
-
export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = {
|
|
13
|
-
get: createInstrumentationGetter(),
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* 创建集合方法的拦截器。
|
|
18
|
-
*
|
|
19
|
-
* 返回一个 get 拦截器函数,用于:
|
|
20
|
-
* 1. 处理响应式标识和原始对象获取
|
|
21
|
-
* 2. 拦截集合的操作方法
|
|
22
|
-
* 3. 转发其他属性访问
|
|
23
|
-
*
|
|
24
|
-
* @returns 集合方法的拦截器函数
|
|
25
|
-
*/
|
|
26
|
-
function createInstrumentationGetter()
|
|
27
|
-
{
|
|
28
|
-
const instrumentations = createInstrumentations();
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
target: CollectionTypes,
|
|
32
|
-
key: string | symbol,
|
|
33
|
-
receiver: CollectionTypes,
|
|
34
|
-
) =>
|
|
35
|
-
{
|
|
36
|
-
// 处理响应式标识
|
|
37
|
-
if (key === ReactiveFlags.IS_REACTIVE)
|
|
38
|
-
{
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
// 获取原始对象
|
|
42
|
-
else if (key === ReactiveFlags.RAW)
|
|
43
|
-
{
|
|
44
|
-
return target;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 如果方法在增强对象中存在,则使用增强版本
|
|
48
|
-
return Reflect.get(
|
|
49
|
-
hasOwn(instrumentations, key) && key in target
|
|
50
|
-
? instrumentations
|
|
51
|
-
: target,
|
|
52
|
-
key,
|
|
53
|
-
receiver,
|
|
54
|
-
);
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* 集合方法增强类型。
|
|
60
|
-
*
|
|
61
|
-
* 定义了所有需要增强的集合方法的类型。
|
|
62
|
-
*/
|
|
63
|
-
type Instrumentations = Record<string | symbol, Function | number>;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 创建集合方法的增强实现。
|
|
67
|
-
*
|
|
68
|
-
* 为集合类型(Map、Set、WeakMap、WeakSet)创建响应式增强方法:
|
|
69
|
-
* 1. 基本操作:get、set、has、delete、clear
|
|
70
|
-
* 2. 遍历操作:forEach、keys、values、entries
|
|
71
|
-
* 3. 大小获取:size
|
|
72
|
-
*
|
|
73
|
-
* @returns 增强后的集合方法对象
|
|
74
|
-
*/
|
|
75
|
-
function createInstrumentations(): Instrumentations
|
|
76
|
-
{
|
|
77
|
-
const instrumentations: Instrumentations = {
|
|
78
|
-
/**
|
|
79
|
-
* 获取 Map 中的值。
|
|
80
|
-
*
|
|
81
|
-
* 实现了以下功能:
|
|
82
|
-
* 1. 支持原始键和响应式键的查找
|
|
83
|
-
* 2. 自动追踪键的访问
|
|
84
|
-
* 3. 自动将返回值转换为响应式
|
|
85
|
-
*
|
|
86
|
-
* @param key 要查找的键
|
|
87
|
-
* @returns 找到的值,如果不存在则返回 undefined
|
|
88
|
-
*/
|
|
89
|
-
get(this: MapTypes, key: unknown)
|
|
90
|
-
{
|
|
91
|
-
// #1772: readonly(reactive(Map)) 应该返回只读的响应式值
|
|
92
|
-
const target = this[ReactiveFlags.RAW];
|
|
93
|
-
const rawTarget = toRaw(target);
|
|
94
|
-
const rawKey = toRaw(key);
|
|
95
|
-
|
|
96
|
-
// 追踪键的访问
|
|
97
|
-
if (hasChanged(key, rawKey))
|
|
98
|
-
{
|
|
99
|
-
PropertyReactivity.track(rawTarget, TrackOpTypes.GET, key);
|
|
100
|
-
}
|
|
101
|
-
PropertyReactivity.track(rawTarget, TrackOpTypes.GET, rawKey);
|
|
102
|
-
|
|
103
|
-
const { has } = getProto(rawTarget);
|
|
104
|
-
const wrap = toReactive;
|
|
105
|
-
|
|
106
|
-
if (has.call(rawTarget, key))
|
|
107
|
-
{
|
|
108
|
-
return wrap(target.get(key));
|
|
109
|
-
}
|
|
110
|
-
else if (has.call(rawTarget, rawKey))
|
|
111
|
-
{
|
|
112
|
-
return wrap(target.get(rawKey));
|
|
113
|
-
}
|
|
114
|
-
else if (target !== rawTarget)
|
|
115
|
-
{
|
|
116
|
-
// #3602 readonly(reactive(Map))
|
|
117
|
-
// 确保嵌套的响应式 Map 可以追踪自身
|
|
118
|
-
target.get(key);
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* 获取集合的大小。
|
|
124
|
-
*
|
|
125
|
-
* 实现了以下功能:
|
|
126
|
-
* 1. 追踪集合大小的访问
|
|
127
|
-
* 2. 返回集合的实际大小
|
|
128
|
-
*/
|
|
129
|
-
get size()
|
|
130
|
-
{
|
|
131
|
-
const target = (this as unknown as IterableCollections)[ReactiveFlags.RAW];
|
|
132
|
-
|
|
133
|
-
PropertyReactivity.track(toRaw(target), TrackOpTypes.ITERATE, ITERATE_KEY);
|
|
134
|
-
|
|
135
|
-
return Reflect.get(target, 'size', target);
|
|
136
|
-
},
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* 检查集合是否包含某个值。
|
|
140
|
-
*
|
|
141
|
-
* 实现了以下功能:
|
|
142
|
-
* 1. 支持原始键和响应式键的检查
|
|
143
|
-
* 2. 自动追踪键的检查
|
|
144
|
-
*
|
|
145
|
-
* @param key 要检查的键
|
|
146
|
-
* @returns 如果集合包含该键则返回 true,否则返回 false
|
|
147
|
-
*/
|
|
148
|
-
has(this: CollectionTypes, key: unknown): boolean
|
|
149
|
-
{
|
|
150
|
-
const target = this[ReactiveFlags.RAW];
|
|
151
|
-
const rawTarget = toRaw(target);
|
|
152
|
-
const rawKey = toRaw(key);
|
|
153
|
-
|
|
154
|
-
// 追踪键的检查
|
|
155
|
-
if (hasChanged(key, rawKey))
|
|
156
|
-
{
|
|
157
|
-
PropertyReactivity.track(rawTarget, TrackOpTypes.HAS, key);
|
|
158
|
-
}
|
|
159
|
-
PropertyReactivity.track(rawTarget, TrackOpTypes.HAS, rawKey);
|
|
160
|
-
|
|
161
|
-
return key === rawKey
|
|
162
|
-
? target.has(key)
|
|
163
|
-
: target.has(key) || target.has(rawKey);
|
|
164
|
-
},
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* 遍历集合中的所有元素。
|
|
168
|
-
*
|
|
169
|
-
* 实现了以下功能:
|
|
170
|
-
* 1. 追踪集合的遍历操作
|
|
171
|
-
* 2. 自动将遍历的值转换为响应式
|
|
172
|
-
* 3. 保持回调函数的 this 上下文
|
|
173
|
-
*
|
|
174
|
-
* @param callback 遍历回调函数
|
|
175
|
-
* @param thisArg 回调函数的 this 值
|
|
176
|
-
*/
|
|
177
|
-
forEach(this: IterableCollections, callback: Function, thisArg?: unknown)
|
|
178
|
-
{
|
|
179
|
-
const observed = this;
|
|
180
|
-
const target = observed[ReactiveFlags.RAW];
|
|
181
|
-
const rawTarget = toRaw(target);
|
|
182
|
-
const wrap = toReactive;
|
|
183
|
-
|
|
184
|
-
PropertyReactivity.track(rawTarget, TrackOpTypes.ITERATE, ITERATE_KEY);
|
|
185
|
-
|
|
186
|
-
return target.forEach((value: unknown, key: unknown) =>
|
|
187
|
-
// 重要:确保回调函数
|
|
188
|
-
// 1. 使用响应式 map 作为 this 和第三个参数
|
|
189
|
-
// 2. 接收到的值应该是相应的响应式/只读版本
|
|
190
|
-
callback.call(thisArg, wrap(value), wrap(key), observed),
|
|
191
|
-
);
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* 向 Set 中添加值。
|
|
196
|
-
*
|
|
197
|
-
* 实现了以下功能:
|
|
198
|
-
* 1. 自动将值转换为原始值
|
|
199
|
-
* 2. 避免重复添加
|
|
200
|
-
* 3. 触发添加操作的通知
|
|
201
|
-
*
|
|
202
|
-
* @param value 要添加的值
|
|
203
|
-
* @returns 集合本身,支持链式调用
|
|
204
|
-
*/
|
|
205
|
-
add(this: SetTypes, value: unknown)
|
|
206
|
-
{
|
|
207
|
-
value = toRaw(value);
|
|
208
|
-
const target = toRaw(this);
|
|
209
|
-
const proto = getProto(target);
|
|
210
|
-
const hadKey = proto.has.call(target, value);
|
|
211
|
-
|
|
212
|
-
if (!hadKey)
|
|
213
|
-
{
|
|
214
|
-
target.add(value);
|
|
215
|
-
PropertyReactivity.trigger(target, TriggerOpTypes.ADD, value, value);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return this;
|
|
219
|
-
},
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* 设置 Map 中的值。
|
|
223
|
-
*
|
|
224
|
-
* 实现了以下功能:
|
|
225
|
-
* 1. 自动将值转换为原始值
|
|
226
|
-
* 2. 支持原始键和响应式键的设置
|
|
227
|
-
* 3. 触发添加或修改操作的通知
|
|
228
|
-
*
|
|
229
|
-
* @param key 要设置的键
|
|
230
|
-
* @param value 要设置的值
|
|
231
|
-
* @returns 集合本身,支持链式调用
|
|
232
|
-
*/
|
|
233
|
-
set(this: MapTypes, key: unknown, value: unknown)
|
|
234
|
-
{
|
|
235
|
-
value = toRaw(value);
|
|
236
|
-
const target = toRaw(this);
|
|
237
|
-
const { has, get } = getProto(target);
|
|
238
|
-
|
|
239
|
-
let hadKey = has.call(target, key);
|
|
240
|
-
|
|
241
|
-
if (!hadKey)
|
|
242
|
-
{
|
|
243
|
-
key = toRaw(key);
|
|
244
|
-
hadKey = has.call(target, key);
|
|
245
|
-
}
|
|
246
|
-
else if (__DEV__)
|
|
247
|
-
{
|
|
248
|
-
checkIdentityKeys(target, has, key);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const oldValue = get.call(target, key);
|
|
252
|
-
|
|
253
|
-
target.set(key, value);
|
|
254
|
-
if (!hadKey)
|
|
255
|
-
{
|
|
256
|
-
PropertyReactivity.trigger(target, TriggerOpTypes.ADD, key, value);
|
|
257
|
-
}
|
|
258
|
-
else if (hasChanged(value, oldValue))
|
|
259
|
-
{
|
|
260
|
-
PropertyReactivity.trigger(target, TriggerOpTypes.SET, key, value, oldValue);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return this;
|
|
264
|
-
},
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* 从集合中删除值。
|
|
268
|
-
*
|
|
269
|
-
* 实现了以下功能:
|
|
270
|
-
* 1. 支持原始键和响应式键的删除
|
|
271
|
-
* 2. 触发删除操作的通知
|
|
272
|
-
*
|
|
273
|
-
* @param key 要删除的键
|
|
274
|
-
* @returns 如果删除成功则返回 true,否则返回 false
|
|
275
|
-
*/
|
|
276
|
-
delete(this: CollectionTypes, key: unknown)
|
|
277
|
-
{
|
|
278
|
-
const target = toRaw(this);
|
|
279
|
-
const { has, get } = getProto(target);
|
|
280
|
-
let hadKey = has.call(target, key);
|
|
281
|
-
|
|
282
|
-
if (!hadKey)
|
|
283
|
-
{
|
|
284
|
-
key = toRaw(key);
|
|
285
|
-
hadKey = has.call(target, key);
|
|
286
|
-
}
|
|
287
|
-
else if (__DEV__)
|
|
288
|
-
{
|
|
289
|
-
checkIdentityKeys(target, has, key);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const oldValue = get ? get.call(target, key) : undefined;
|
|
293
|
-
// 在触发反应之前执行操作
|
|
294
|
-
const result = target.delete(key);
|
|
295
|
-
|
|
296
|
-
if (hadKey)
|
|
297
|
-
{
|
|
298
|
-
PropertyReactivity.trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
return result;
|
|
302
|
-
},
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* 清空集合。
|
|
306
|
-
*
|
|
307
|
-
* 实现了以下功能:
|
|
308
|
-
* 1. 清空集合中的所有元素
|
|
309
|
-
* 2. 触发清空操作的通知
|
|
310
|
-
* 3. 在开发模式下保存旧值用于调试
|
|
311
|
-
*
|
|
312
|
-
* @returns 如果清空成功则返回 true,否则返回 false
|
|
313
|
-
*/
|
|
314
|
-
clear(this: IterableCollections)
|
|
315
|
-
{
|
|
316
|
-
const target = toRaw(this);
|
|
317
|
-
const hadItems = target.size !== 0;
|
|
318
|
-
const oldTarget = __DEV__
|
|
319
|
-
? isMap(target)
|
|
320
|
-
? new Map(target)
|
|
321
|
-
: new Set(target)
|
|
322
|
-
: undefined;
|
|
323
|
-
// 在触发反应之前执行操作
|
|
324
|
-
const result = target.clear();
|
|
325
|
-
|
|
326
|
-
if (hadItems)
|
|
327
|
-
{
|
|
328
|
-
PropertyReactivity.trigger(
|
|
329
|
-
target,
|
|
330
|
-
TriggerOpTypes.CLEAR,
|
|
331
|
-
undefined,
|
|
332
|
-
undefined,
|
|
333
|
-
oldTarget,
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return result;
|
|
338
|
-
},
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
// 添加迭代器方法
|
|
342
|
-
const iteratorMethods = [
|
|
343
|
-
'keys',
|
|
344
|
-
'values',
|
|
345
|
-
'entries',
|
|
346
|
-
Symbol.iterator,
|
|
347
|
-
] as const;
|
|
348
|
-
|
|
349
|
-
iteratorMethods.forEach((method) =>
|
|
350
|
-
{
|
|
351
|
-
instrumentations[method] = createIterableMethod(method);
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
return instrumentations;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* 创建迭代器方法。
|
|
359
|
-
*
|
|
360
|
-
* 为集合创建响应式的迭代器方法,包括:
|
|
361
|
-
* 1. keys() - 返回键的迭代器
|
|
362
|
-
* 2. values() - 返回值的迭代器
|
|
363
|
-
* 3. entries() - 返回键值对的迭代器
|
|
364
|
-
* 4. [Symbol.iterator] - 返回默认迭代器
|
|
365
|
-
*
|
|
366
|
-
* @param method 迭代器方法名
|
|
367
|
-
* @returns 增强后的迭代器方法
|
|
368
|
-
*/
|
|
369
|
-
function createIterableMethod(method: string | symbol)
|
|
370
|
-
{
|
|
371
|
-
return function (
|
|
372
|
-
this: IterableCollections,
|
|
373
|
-
...args: unknown[]
|
|
374
|
-
): Iterable<unknown> & Iterator<unknown>
|
|
375
|
-
{
|
|
376
|
-
const target = this[ReactiveFlags.RAW];
|
|
377
|
-
const rawTarget = toRaw(target);
|
|
378
|
-
const targetIsMap = isMap(rawTarget);
|
|
379
|
-
const isPair
|
|
380
|
-
= method === 'entries' || (method === Symbol.iterator && targetIsMap);
|
|
381
|
-
const isKeyOnly = method === 'keys' && targetIsMap;
|
|
382
|
-
const innerIterator = target[method](...args);
|
|
383
|
-
const wrap = toReactive;
|
|
384
|
-
|
|
385
|
-
// 追踪迭代操作
|
|
386
|
-
PropertyReactivity.track(
|
|
387
|
-
rawTarget,
|
|
388
|
-
TrackOpTypes.ITERATE,
|
|
389
|
-
isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY,
|
|
390
|
-
);
|
|
391
|
-
|
|
392
|
-
// 返回一个包装的迭代器,它会返回响应式版本的值
|
|
393
|
-
return {
|
|
394
|
-
// 迭代器协议
|
|
395
|
-
next()
|
|
396
|
-
{
|
|
397
|
-
const { value, done } = innerIterator.next();
|
|
398
|
-
|
|
399
|
-
return done
|
|
400
|
-
? { value, done }
|
|
401
|
-
: {
|
|
402
|
-
value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),
|
|
403
|
-
done,
|
|
404
|
-
};
|
|
405
|
-
},
|
|
406
|
-
// 可迭代协议
|
|
407
|
-
[Symbol.iterator]()
|
|
408
|
-
{
|
|
409
|
-
return this;
|
|
410
|
-
},
|
|
411
|
-
};
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* 检查键的身份。
|
|
417
|
-
*
|
|
418
|
-
* 在开发模式下检查键的身份,确保不会出现重复的键。
|
|
419
|
-
*
|
|
420
|
-
* @param target 目标集合
|
|
421
|
-
* @param has 检查方法
|
|
422
|
-
* @param key 要检查的键
|
|
423
|
-
*/
|
|
424
|
-
function checkIdentityKeys(
|
|
425
|
-
target: CollectionTypes,
|
|
426
|
-
has: (key: unknown) => boolean,
|
|
427
|
-
key: unknown,
|
|
428
|
-
)
|
|
429
|
-
{
|
|
430
|
-
const rawKey = toRaw(key);
|
|
431
|
-
|
|
432
|
-
if (rawKey !== key && has.call(target, rawKey))
|
|
433
|
-
{
|
|
434
|
-
const type = toRawType(target);
|
|
435
|
-
|
|
436
|
-
warn(
|
|
437
|
-
`Reactive ${type} contains both the raw and reactive ` +
|
|
438
|
-
`versions of the same object${type === `Map` ? ` as keys` : ``}, ` +
|
|
439
|
-
`which can lead to inconsistencies. ` +
|
|
440
|
-
`It is recommended to use only the reactive version.`,
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
/**
|
|
446
|
-
* 获取对象的原型。
|
|
447
|
-
*
|
|
448
|
-
* @param v 目标对象
|
|
449
|
-
* @returns 对象的原型
|
|
450
|
-
*/
|
|
451
|
-
const getProto = <T extends CollectionTypes>(v: T): any => Reflect.getPrototypeOf(v);
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* 集合类型。
|
|
455
|
-
*
|
|
456
|
-
* 包括可迭代集合和弱引用集合。
|
|
457
|
-
*/
|
|
458
|
-
type CollectionTypes = IterableCollections | WeakCollections;
|
|
459
|
-
|
|
460
|
-
/**
|
|
461
|
-
* 可迭代集合类型。
|
|
462
|
-
*
|
|
463
|
-
* 包括 Map 和 Set。
|
|
464
|
-
*/
|
|
465
|
-
type IterableCollections = (Map<any, any> | Set<any>) & Target;
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* 弱引用集合类型。
|
|
469
|
-
*
|
|
470
|
-
* 包括 WeakMap 和 WeakSet。
|
|
471
|
-
*/
|
|
472
|
-
type WeakCollections = (WeakMap<any, any> | WeakSet<any>) & Target;
|
|
473
|
-
|
|
474
|
-
/**
|
|
475
|
-
* Map 类型。
|
|
476
|
-
*
|
|
477
|
-
* 包括 Map 和 WeakMap。
|
|
478
|
-
*/
|
|
479
|
-
type MapTypes = (Map<any, any> | WeakMap<any, any>) & Target;
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Set 类型。
|
|
483
|
-
*
|
|
484
|
-
* 包括 Set 和 WeakSet。
|
|
485
|
-
*/
|
|
486
|
-
type SetTypes = (Set<any> | WeakSet<any>) & Target;
|
|
1
|
+
import { toReactive } from './reactive';
|
|
2
|
+
import { ITERATE_KEY, MAP_KEY_ITERATE_KEY, ReactiveFlags, TrackOpTypes, TriggerOpTypes } from './shared/constants';
|
|
3
|
+
import { hasChanged, hasOwn, isMap, Target, toRaw, toRawType, warn } from './shared/general';
|
|
4
|
+
import { PropertyReactivity } from './property';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 可变集合响应式处理器。
|
|
8
|
+
*
|
|
9
|
+
* 用于处理集合类型(Map、Set、WeakMap、WeakSet)的响应式代理。
|
|
10
|
+
* 通过拦截集合的操作方法,实现响应式功能。
|
|
11
|
+
*/
|
|
12
|
+
export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = {
|
|
13
|
+
get: createInstrumentationGetter(),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 创建集合方法的拦截器。
|
|
18
|
+
*
|
|
19
|
+
* 返回一个 get 拦截器函数,用于:
|
|
20
|
+
* 1. 处理响应式标识和原始对象获取
|
|
21
|
+
* 2. 拦截集合的操作方法
|
|
22
|
+
* 3. 转发其他属性访问
|
|
23
|
+
*
|
|
24
|
+
* @returns 集合方法的拦截器函数
|
|
25
|
+
*/
|
|
26
|
+
function createInstrumentationGetter()
|
|
27
|
+
{
|
|
28
|
+
const instrumentations = createInstrumentations();
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
target: CollectionTypes,
|
|
32
|
+
key: string | symbol,
|
|
33
|
+
receiver: CollectionTypes,
|
|
34
|
+
) =>
|
|
35
|
+
{
|
|
36
|
+
// 处理响应式标识
|
|
37
|
+
if (key === ReactiveFlags.IS_REACTIVE)
|
|
38
|
+
{
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
// 获取原始对象
|
|
42
|
+
else if (key === ReactiveFlags.RAW)
|
|
43
|
+
{
|
|
44
|
+
return target;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 如果方法在增强对象中存在,则使用增强版本
|
|
48
|
+
return Reflect.get(
|
|
49
|
+
hasOwn(instrumentations, key) && key in target
|
|
50
|
+
? instrumentations
|
|
51
|
+
: target,
|
|
52
|
+
key,
|
|
53
|
+
receiver,
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 集合方法增强类型。
|
|
60
|
+
*
|
|
61
|
+
* 定义了所有需要增强的集合方法的类型。
|
|
62
|
+
*/
|
|
63
|
+
type Instrumentations = Record<string | symbol, Function | number>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 创建集合方法的增强实现。
|
|
67
|
+
*
|
|
68
|
+
* 为集合类型(Map、Set、WeakMap、WeakSet)创建响应式增强方法:
|
|
69
|
+
* 1. 基本操作:get、set、has、delete、clear
|
|
70
|
+
* 2. 遍历操作:forEach、keys、values、entries
|
|
71
|
+
* 3. 大小获取:size
|
|
72
|
+
*
|
|
73
|
+
* @returns 增强后的集合方法对象
|
|
74
|
+
*/
|
|
75
|
+
function createInstrumentations(): Instrumentations
|
|
76
|
+
{
|
|
77
|
+
const instrumentations: Instrumentations = {
|
|
78
|
+
/**
|
|
79
|
+
* 获取 Map 中的值。
|
|
80
|
+
*
|
|
81
|
+
* 实现了以下功能:
|
|
82
|
+
* 1. 支持原始键和响应式键的查找
|
|
83
|
+
* 2. 自动追踪键的访问
|
|
84
|
+
* 3. 自动将返回值转换为响应式
|
|
85
|
+
*
|
|
86
|
+
* @param key 要查找的键
|
|
87
|
+
* @returns 找到的值,如果不存在则返回 undefined
|
|
88
|
+
*/
|
|
89
|
+
get(this: MapTypes, key: unknown)
|
|
90
|
+
{
|
|
91
|
+
// #1772: readonly(reactive(Map)) 应该返回只读的响应式值
|
|
92
|
+
const target = this[ReactiveFlags.RAW];
|
|
93
|
+
const rawTarget = toRaw(target);
|
|
94
|
+
const rawKey = toRaw(key);
|
|
95
|
+
|
|
96
|
+
// 追踪键的访问
|
|
97
|
+
if (hasChanged(key, rawKey))
|
|
98
|
+
{
|
|
99
|
+
PropertyReactivity.track(rawTarget, TrackOpTypes.GET, key);
|
|
100
|
+
}
|
|
101
|
+
PropertyReactivity.track(rawTarget, TrackOpTypes.GET, rawKey);
|
|
102
|
+
|
|
103
|
+
const { has } = getProto(rawTarget);
|
|
104
|
+
const wrap = toReactive;
|
|
105
|
+
|
|
106
|
+
if (has.call(rawTarget, key))
|
|
107
|
+
{
|
|
108
|
+
return wrap(target.get(key));
|
|
109
|
+
}
|
|
110
|
+
else if (has.call(rawTarget, rawKey))
|
|
111
|
+
{
|
|
112
|
+
return wrap(target.get(rawKey));
|
|
113
|
+
}
|
|
114
|
+
else if (target !== rawTarget)
|
|
115
|
+
{
|
|
116
|
+
// #3602 readonly(reactive(Map))
|
|
117
|
+
// 确保嵌套的响应式 Map 可以追踪自身
|
|
118
|
+
target.get(key);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 获取集合的大小。
|
|
124
|
+
*
|
|
125
|
+
* 实现了以下功能:
|
|
126
|
+
* 1. 追踪集合大小的访问
|
|
127
|
+
* 2. 返回集合的实际大小
|
|
128
|
+
*/
|
|
129
|
+
get size()
|
|
130
|
+
{
|
|
131
|
+
const target = (this as unknown as IterableCollections)[ReactiveFlags.RAW];
|
|
132
|
+
|
|
133
|
+
PropertyReactivity.track(toRaw(target), TrackOpTypes.ITERATE, ITERATE_KEY);
|
|
134
|
+
|
|
135
|
+
return Reflect.get(target, 'size', target);
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 检查集合是否包含某个值。
|
|
140
|
+
*
|
|
141
|
+
* 实现了以下功能:
|
|
142
|
+
* 1. 支持原始键和响应式键的检查
|
|
143
|
+
* 2. 自动追踪键的检查
|
|
144
|
+
*
|
|
145
|
+
* @param key 要检查的键
|
|
146
|
+
* @returns 如果集合包含该键则返回 true,否则返回 false
|
|
147
|
+
*/
|
|
148
|
+
has(this: CollectionTypes, key: unknown): boolean
|
|
149
|
+
{
|
|
150
|
+
const target = this[ReactiveFlags.RAW];
|
|
151
|
+
const rawTarget = toRaw(target);
|
|
152
|
+
const rawKey = toRaw(key);
|
|
153
|
+
|
|
154
|
+
// 追踪键的检查
|
|
155
|
+
if (hasChanged(key, rawKey))
|
|
156
|
+
{
|
|
157
|
+
PropertyReactivity.track(rawTarget, TrackOpTypes.HAS, key);
|
|
158
|
+
}
|
|
159
|
+
PropertyReactivity.track(rawTarget, TrackOpTypes.HAS, rawKey);
|
|
160
|
+
|
|
161
|
+
return key === rawKey
|
|
162
|
+
? target.has(key)
|
|
163
|
+
: target.has(key) || target.has(rawKey);
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 遍历集合中的所有元素。
|
|
168
|
+
*
|
|
169
|
+
* 实现了以下功能:
|
|
170
|
+
* 1. 追踪集合的遍历操作
|
|
171
|
+
* 2. 自动将遍历的值转换为响应式
|
|
172
|
+
* 3. 保持回调函数的 this 上下文
|
|
173
|
+
*
|
|
174
|
+
* @param callback 遍历回调函数
|
|
175
|
+
* @param thisArg 回调函数的 this 值
|
|
176
|
+
*/
|
|
177
|
+
forEach(this: IterableCollections, callback: Function, thisArg?: unknown)
|
|
178
|
+
{
|
|
179
|
+
const observed = this;
|
|
180
|
+
const target = observed[ReactiveFlags.RAW];
|
|
181
|
+
const rawTarget = toRaw(target);
|
|
182
|
+
const wrap = toReactive;
|
|
183
|
+
|
|
184
|
+
PropertyReactivity.track(rawTarget, TrackOpTypes.ITERATE, ITERATE_KEY);
|
|
185
|
+
|
|
186
|
+
return target.forEach((value: unknown, key: unknown) =>
|
|
187
|
+
// 重要:确保回调函数
|
|
188
|
+
// 1. 使用响应式 map 作为 this 和第三个参数
|
|
189
|
+
// 2. 接收到的值应该是相应的响应式/只读版本
|
|
190
|
+
callback.call(thisArg, wrap(value), wrap(key), observed),
|
|
191
|
+
);
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 向 Set 中添加值。
|
|
196
|
+
*
|
|
197
|
+
* 实现了以下功能:
|
|
198
|
+
* 1. 自动将值转换为原始值
|
|
199
|
+
* 2. 避免重复添加
|
|
200
|
+
* 3. 触发添加操作的通知
|
|
201
|
+
*
|
|
202
|
+
* @param value 要添加的值
|
|
203
|
+
* @returns 集合本身,支持链式调用
|
|
204
|
+
*/
|
|
205
|
+
add(this: SetTypes, value: unknown)
|
|
206
|
+
{
|
|
207
|
+
value = toRaw(value);
|
|
208
|
+
const target = toRaw(this);
|
|
209
|
+
const proto = getProto(target);
|
|
210
|
+
const hadKey = proto.has.call(target, value);
|
|
211
|
+
|
|
212
|
+
if (!hadKey)
|
|
213
|
+
{
|
|
214
|
+
target.add(value);
|
|
215
|
+
PropertyReactivity.trigger(target, TriggerOpTypes.ADD, value, value);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return this;
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 设置 Map 中的值。
|
|
223
|
+
*
|
|
224
|
+
* 实现了以下功能:
|
|
225
|
+
* 1. 自动将值转换为原始值
|
|
226
|
+
* 2. 支持原始键和响应式键的设置
|
|
227
|
+
* 3. 触发添加或修改操作的通知
|
|
228
|
+
*
|
|
229
|
+
* @param key 要设置的键
|
|
230
|
+
* @param value 要设置的值
|
|
231
|
+
* @returns 集合本身,支持链式调用
|
|
232
|
+
*/
|
|
233
|
+
set(this: MapTypes, key: unknown, value: unknown)
|
|
234
|
+
{
|
|
235
|
+
value = toRaw(value);
|
|
236
|
+
const target = toRaw(this);
|
|
237
|
+
const { has, get } = getProto(target);
|
|
238
|
+
|
|
239
|
+
let hadKey = has.call(target, key);
|
|
240
|
+
|
|
241
|
+
if (!hadKey)
|
|
242
|
+
{
|
|
243
|
+
key = toRaw(key);
|
|
244
|
+
hadKey = has.call(target, key);
|
|
245
|
+
}
|
|
246
|
+
else if (__DEV__)
|
|
247
|
+
{
|
|
248
|
+
checkIdentityKeys(target, has, key);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const oldValue = get.call(target, key);
|
|
252
|
+
|
|
253
|
+
target.set(key, value);
|
|
254
|
+
if (!hadKey)
|
|
255
|
+
{
|
|
256
|
+
PropertyReactivity.trigger(target, TriggerOpTypes.ADD, key, value);
|
|
257
|
+
}
|
|
258
|
+
else if (hasChanged(value, oldValue))
|
|
259
|
+
{
|
|
260
|
+
PropertyReactivity.trigger(target, TriggerOpTypes.SET, key, value, oldValue);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return this;
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* 从集合中删除值。
|
|
268
|
+
*
|
|
269
|
+
* 实现了以下功能:
|
|
270
|
+
* 1. 支持原始键和响应式键的删除
|
|
271
|
+
* 2. 触发删除操作的通知
|
|
272
|
+
*
|
|
273
|
+
* @param key 要删除的键
|
|
274
|
+
* @returns 如果删除成功则返回 true,否则返回 false
|
|
275
|
+
*/
|
|
276
|
+
delete(this: CollectionTypes, key: unknown)
|
|
277
|
+
{
|
|
278
|
+
const target = toRaw(this);
|
|
279
|
+
const { has, get } = getProto(target);
|
|
280
|
+
let hadKey = has.call(target, key);
|
|
281
|
+
|
|
282
|
+
if (!hadKey)
|
|
283
|
+
{
|
|
284
|
+
key = toRaw(key);
|
|
285
|
+
hadKey = has.call(target, key);
|
|
286
|
+
}
|
|
287
|
+
else if (__DEV__)
|
|
288
|
+
{
|
|
289
|
+
checkIdentityKeys(target, has, key);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const oldValue = get ? get.call(target, key) : undefined;
|
|
293
|
+
// 在触发反应之前执行操作
|
|
294
|
+
const result = target.delete(key);
|
|
295
|
+
|
|
296
|
+
if (hadKey)
|
|
297
|
+
{
|
|
298
|
+
PropertyReactivity.trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return result;
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* 清空集合。
|
|
306
|
+
*
|
|
307
|
+
* 实现了以下功能:
|
|
308
|
+
* 1. 清空集合中的所有元素
|
|
309
|
+
* 2. 触发清空操作的通知
|
|
310
|
+
* 3. 在开发模式下保存旧值用于调试
|
|
311
|
+
*
|
|
312
|
+
* @returns 如果清空成功则返回 true,否则返回 false
|
|
313
|
+
*/
|
|
314
|
+
clear(this: IterableCollections)
|
|
315
|
+
{
|
|
316
|
+
const target = toRaw(this);
|
|
317
|
+
const hadItems = target.size !== 0;
|
|
318
|
+
const oldTarget = __DEV__
|
|
319
|
+
? isMap(target)
|
|
320
|
+
? new Map(target)
|
|
321
|
+
: new Set(target)
|
|
322
|
+
: undefined;
|
|
323
|
+
// 在触发反应之前执行操作
|
|
324
|
+
const result = target.clear();
|
|
325
|
+
|
|
326
|
+
if (hadItems)
|
|
327
|
+
{
|
|
328
|
+
PropertyReactivity.trigger(
|
|
329
|
+
target,
|
|
330
|
+
TriggerOpTypes.CLEAR,
|
|
331
|
+
undefined,
|
|
332
|
+
undefined,
|
|
333
|
+
oldTarget,
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return result;
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
// 添加迭代器方法
|
|
342
|
+
const iteratorMethods = [
|
|
343
|
+
'keys',
|
|
344
|
+
'values',
|
|
345
|
+
'entries',
|
|
346
|
+
Symbol.iterator,
|
|
347
|
+
] as const;
|
|
348
|
+
|
|
349
|
+
iteratorMethods.forEach((method) =>
|
|
350
|
+
{
|
|
351
|
+
instrumentations[method] = createIterableMethod(method);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
return instrumentations;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* 创建迭代器方法。
|
|
359
|
+
*
|
|
360
|
+
* 为集合创建响应式的迭代器方法,包括:
|
|
361
|
+
* 1. keys() - 返回键的迭代器
|
|
362
|
+
* 2. values() - 返回值的迭代器
|
|
363
|
+
* 3. entries() - 返回键值对的迭代器
|
|
364
|
+
* 4. [Symbol.iterator] - 返回默认迭代器
|
|
365
|
+
*
|
|
366
|
+
* @param method 迭代器方法名
|
|
367
|
+
* @returns 增强后的迭代器方法
|
|
368
|
+
*/
|
|
369
|
+
function createIterableMethod(method: string | symbol)
|
|
370
|
+
{
|
|
371
|
+
return function (
|
|
372
|
+
this: IterableCollections,
|
|
373
|
+
...args: unknown[]
|
|
374
|
+
): Iterable<unknown> & Iterator<unknown>
|
|
375
|
+
{
|
|
376
|
+
const target = this[ReactiveFlags.RAW];
|
|
377
|
+
const rawTarget = toRaw(target);
|
|
378
|
+
const targetIsMap = isMap(rawTarget);
|
|
379
|
+
const isPair
|
|
380
|
+
= method === 'entries' || (method === Symbol.iterator && targetIsMap);
|
|
381
|
+
const isKeyOnly = method === 'keys' && targetIsMap;
|
|
382
|
+
const innerIterator = target[method](...args);
|
|
383
|
+
const wrap = toReactive;
|
|
384
|
+
|
|
385
|
+
// 追踪迭代操作
|
|
386
|
+
PropertyReactivity.track(
|
|
387
|
+
rawTarget,
|
|
388
|
+
TrackOpTypes.ITERATE,
|
|
389
|
+
isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY,
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
// 返回一个包装的迭代器,它会返回响应式版本的值
|
|
393
|
+
return {
|
|
394
|
+
// 迭代器协议
|
|
395
|
+
next()
|
|
396
|
+
{
|
|
397
|
+
const { value, done } = innerIterator.next();
|
|
398
|
+
|
|
399
|
+
return done
|
|
400
|
+
? { value, done }
|
|
401
|
+
: {
|
|
402
|
+
value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),
|
|
403
|
+
done,
|
|
404
|
+
};
|
|
405
|
+
},
|
|
406
|
+
// 可迭代协议
|
|
407
|
+
[Symbol.iterator]()
|
|
408
|
+
{
|
|
409
|
+
return this;
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* 检查键的身份。
|
|
417
|
+
*
|
|
418
|
+
* 在开发模式下检查键的身份,确保不会出现重复的键。
|
|
419
|
+
*
|
|
420
|
+
* @param target 目标集合
|
|
421
|
+
* @param has 检查方法
|
|
422
|
+
* @param key 要检查的键
|
|
423
|
+
*/
|
|
424
|
+
function checkIdentityKeys(
|
|
425
|
+
target: CollectionTypes,
|
|
426
|
+
has: (key: unknown) => boolean,
|
|
427
|
+
key: unknown,
|
|
428
|
+
)
|
|
429
|
+
{
|
|
430
|
+
const rawKey = toRaw(key);
|
|
431
|
+
|
|
432
|
+
if (rawKey !== key && has.call(target, rawKey))
|
|
433
|
+
{
|
|
434
|
+
const type = toRawType(target);
|
|
435
|
+
|
|
436
|
+
warn(
|
|
437
|
+
`Reactive ${type} contains both the raw and reactive ` +
|
|
438
|
+
`versions of the same object${type === `Map` ? ` as keys` : ``}, ` +
|
|
439
|
+
`which can lead to inconsistencies. ` +
|
|
440
|
+
`It is recommended to use only the reactive version.`,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* 获取对象的原型。
|
|
447
|
+
*
|
|
448
|
+
* @param v 目标对象
|
|
449
|
+
* @returns 对象的原型
|
|
450
|
+
*/
|
|
451
|
+
const getProto = <T extends CollectionTypes>(v: T): any => Reflect.getPrototypeOf(v);
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* 集合类型。
|
|
455
|
+
*
|
|
456
|
+
* 包括可迭代集合和弱引用集合。
|
|
457
|
+
*/
|
|
458
|
+
type CollectionTypes = IterableCollections | WeakCollections;
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* 可迭代集合类型。
|
|
462
|
+
*
|
|
463
|
+
* 包括 Map 和 Set。
|
|
464
|
+
*/
|
|
465
|
+
type IterableCollections = (Map<any, any> | Set<any>) & Target;
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* 弱引用集合类型。
|
|
469
|
+
*
|
|
470
|
+
* 包括 WeakMap 和 WeakSet。
|
|
471
|
+
*/
|
|
472
|
+
type WeakCollections = (WeakMap<any, any> | WeakSet<any>) & Target;
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Map 类型。
|
|
476
|
+
*
|
|
477
|
+
* 包括 Map 和 WeakMap。
|
|
478
|
+
*/
|
|
479
|
+
type MapTypes = (Map<any, any> | WeakMap<any, any>) & Target;
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Set 类型。
|
|
483
|
+
*
|
|
484
|
+
* 包括 Set 和 WeakSet。
|
|
485
|
+
*/
|
|
486
|
+
type SetTypes = (Set<any> | WeakSet<any>) & Target;
|