文章目录
前言
“鲁棒性”(Robustness) 是一个软件工程术语,意思是:
程序在面对异常情况、边界条件或不完美输入时,仍能稳定、正确运行的能力。
✅ 举例说明
情况 | 鲁棒性体现 |
---|---|
传入已经是代理的对象 | 不重复代理,直接返回 |
出现循环引用 | 不死递归,正确引用自己 |
用户传入 null/undefined/非对象 | 不报错,直接返回原值或做容错处理 |
属性不存在 | 返回 undefined 而不是抛异常 |
✅ 在 Vue 响应式系统中的鲁棒性
你的 reactive()
方法如果没有处理好这些情况:
- 传入已经代理过的对象又再次代理,会导致多层代理或性能浪费;
- 遇到循环引用没做缓存,会死栈;
get
或set
时没做 null 检查,会报错。
这些都说明鲁棒性不够。
✅ 总结一句话:
鲁棒性 = 出错时不崩溃,边缘条件下仍合理运行。
一个高质量的框架/库,必须具备良好的鲁棒性。
下面在现有 reactive()
实现上,增加 4 项关键的鲁棒性增强,确保 mini-vue 面对各种异常/边界情况都能稳定运行。
✅ 1. 忽略非对象类型(null、number、boolean 等)
if (!isObject(target)) {
return target
}
原因:
非对象是不能被 Proxy
代理的,否则直接报错。
✅ 2. 避免重复代理(支持 isReactive() 和 WeakMap 缓存双保险)
if ((target as any)[ReactiveFlags.IS_REACTIVE]) {
return target // 已是响应式,直接返回
}
if (reactiveMap.has(target)) {
return reactiveMap.get(target)
}
原因:
即使外部不小心再次调用 reactive()
,也应返回已生成的代理对象。
✅ 3. 防止循环引用死递归:递归时也判断是否已经代理
if (isObject(result)) {
return reactive(result)
}
需要进一步增强为:
if (isObject(result)) {
// 优先使用 WeakMap 缓存中的代理
const existingProxy = reactiveMap.get(result)
return existingProxy ? existingProxy : reactive(result)
}
✅ 4. 兼容 toRaw()
还原原始对象
你已有:
if (key === ReactiveFlags.RAW) {
return target
}
再配合:
export function toRaw(value: any): any {
return value && (value as any)[ReactiveFlags.RAW] || value
}
这样你可以任意判断、恢复响应式对象。
🧩 最终鲁棒版 reactive.ts
核心结构如下:
export function reactive<T extends object>(target: T): T {
if (!isObject(target)) {
return target
}
if ((target as any)[ReactiveFlags.IS_REACTIVE]) {
return target
}
if (reactiveMap.has(target)) {
return reactiveMap.get(target)
}
const proxy = new Proxy(target, {
get(target, key, receiver) {
if (key === ReactiveFlags.IS_REACTIVE) return true
if (key === ReactiveFlags.RAW) return target
const result = Reflect.get(target, key, receiver)
track(target, key)
if (isObject(result)) {
const existingProxy = reactiveMap.get(result)
return existingProxy ? existingProxy : reactive(result)
}
return result
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver)
trigger(target, key)
return result
}
})
reactiveMap.set(target, proxy)
return proxy
}
✅ 附加:isObject
工具函数
function isObject(val: any): val is object {
return val !== null && typeof val === 'object'
}
✅ 小结
防御策略 | 解决的问题 |
---|---|
非对象返回原值 | 防止 Proxy 报错 |
重复代理检测 | 避免多层代理 / 死递归 |
IS_REACTIVE 检查 | 允许 isReactive() 判定状态 |
RAW 支持 | toRaw() 安全还原原始对象 |
WeakMap 缓存 | 优化性能 + 支持循环引用 |