Object.defineProperty bypasses reactive array reactivity
🔩 p2-edge-case
## Description
`Object.defineProperty` and `Reflect.defineProperty` on a reactive array set values without notifying observers. The `defineProperty` Proxy trap exists but does not call `trigger()` for array indices.
## Reproduction
```js
import { reactive, effect } from "@vue/reactivity"
const arr = reactive([1, 2, 3])
let v
effect(() => { v = arr[0] })
console.log(v) // 1
arr[0] = 10 // ✅ v === 10 (notified)
Object.defineProperty(arr, "0", { value: 999 })
console.log(v) // ❌ 10 (stale! arr[0] is actually 999)
```
Affects: existing index values, new index creation at `arr[arr.length]`, and `arr.length` modification via `defineProperty`.
## Impact
Any code that uses `Object.defineProperty` on a reactive array — including test frameworks (Jest mockImplementation, Sinon stubs), serialization libraries, and polyfills — silently produces stale downstream computations.
## Analysis
Vue 3s reactive Proxy does have a `defineProperty` trap (it handles `__v_skip` and `__v_raw` flags), but it does not call `trigger()` for numeric string keys that correspond to array indices. The `set` trap correctly triggers, but `defineProperty` provides a parallel mutation path.
Found by the reactive array conformance suite (8 mutation traces across 4 reactive implementations).
2 条评论