Frontend Development 10 min read

Performance Comparison of Vue3 Proxy vs Object.defineProperty for Reactive Systems

This article benchmarks Vue3's Proxy-based reactivity against the traditional Object.defineProperty approach across initialization, read, write, multiple object creation, and nested‑object scenarios, revealing where each technique excels and why Vue3 ultimately prefers Proxy despite nuanced performance trade‑offs.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Performance Comparison of Vue3 Proxy vs Object.defineProperty for Reactive Systems

When browsing articles about Vue's reactivity, many note that Vue3 abandons Object.defineProperty in favor of Proxy because the latter is claimed to have better performance; the author therefore built a small demo to compare the two mechanisms in various scenarios.

The following tests were run only in Google Chrome; results may differ in other browsers. An online link is provided for testing in other environments.

The article does not re‑explain the implementation details of Object.defineProperty and Proxy wrappers, as they are widely covered elsewhere. It notes that Vue3 optimizes nested object reactivity with a lazy‑addition strategy, whereas Vue2 recursively makes the whole object reactive at once. To keep the comparison fair, the demo also applies lazy addition to the Object.defineProperty version.

Object.defineProperty

/** Object.defineProperty 深度监听 */
export function deepDefObserve(obj, week) {
  const keys = Object.keys(obj)
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    let value = obj[key]

    Object.defineProperty(obj, key, {
      configurable: true,
      enumerable: true,
      get() {
        if (
          typeof value === "object" &&
          value !== null &&
          week &&
          !week.has(value)
        ) {
          week.set(value, true)
          deepDefObserve(value)
        }
        return value
      },
      set(newValue) {
        value = newValue
      },
    })
  }
  return obj
}

Proxy

/** Proxy 深度监听 */
export function deepProxy(obj, proxyWeek) {
  const myProxy = new Proxy(obj, {
    get(target, property) {
      let res = Reflect.get(target, property)
      if (
        typeof res === "object" &&
        res !== null &&
        proxyWeek &&
        !proxyWeek.has(res)
      ) {
        proxyWeek.set(res, true)
        return deepProxy(res)
      }
      return res
    },
    set(target, property, value) {
      return Reflect.set(target, property, value)
    },
  })
  return myProxy
}

The performance tests cover five scenarios:

Creating a reactive object with two API calls (e.g., const obj = reactive({}) ).

Reading a property of an already‑created reactive object (e.g., obj.a ).

Writing a property value (e.g., obj.a = 1 ).

Creating many reactive objects and repeatedly accessing/modifying their properties.

Testing reactivity on nested objects to evaluate deep‑structure performance.

Initialization Performance

const _0_calling = {
  useObjectDefineProperty() {
    const data = {a:1,b:1,c:1,d:1,e:1}
    const keys = Object.keys(data)
    for (let i = 0; i < keys.length; i++) {
      Object.defineProperty(data, keys[i], { get(){}, set(){} })
    }
  },
  useProxy() {
    const data = {a:1,b:1,c:1,d:1,e:1}
    const proxy = new Proxy(data, { get(){}, set(){} })
  },
}

Results show that Proxy creates reactive objects noticeably faster than Object.defineProperty .

Read Performance

const readDefData = deepDefObserve({a:1,b:1,c:1,d:1,e:1})
const readProxyData = deepProxy({a:1,b:1,c:1,d:1,e:1})
export const _1_read = {
  useObjectDefineProperty() {
    readDefData.a
    readDefData.b
    readDefData.e
  },
  useProxy() {
    readProxyData.a
    readProxyData.b
    readProxyData.e
  },
}

In this scenario, Object.defineProperty reads are clearly faster than Proxy reads.

Write Performance

const writeDefData = deepDefObserve({a:1,b:1,c:1,d:1,e:1})
const writeProxyData = deepProxy({a:1,b:1,c:1,d:1,e:1})
export const _2_write = {
  count: 2,
  useObjectDefineProperty() {
    writeDefData.a = _2_write.count++
    writeDefData.b = _2_write.count++
  },
  useProxy() {
    writeProxyData.a = _2_write.count++
    writeProxyData.b = _2_write.count++
  },
}

Here Object.defineProperty still outperforms Proxy , though the gap is small.

Multiple Creation and Read/Write

export const _4_create_read_write = {
  count: 2,
  useObjectDefineProperty() {
    const data = {a:1,b:1,c:1,d:1,e:1}
    deepDefObserve(data)
    data.a = _4_create_read_write.count++
    data.b = _4_create_read_write.count++
    data.a
    data.c
  },
  proxyWeek: new WeakMap(),
  useProxy() {
    const data = {a:1,b:1,c:1,d:1,e:1}
    const proxy = deepProxy(data, _4_create_read_write.proxyWeek)
    proxy.a = _4_create_read_write.count++
    proxy.b = _4_create_read_write.count++
    proxy.a
    proxy.c
  },
}

Proxy shows a larger advantage in this batch‑creation scenario, but such cases are uncommon in typical development.

Nested Object Performance

Two sub‑scenarios were measured:

All properties read/written

/* code omitted for brevity – similar structure using deepDefObserve and deepProxy on a nested response object */

Object.defineProperty is slightly better, but the difference is minimal.

Only top‑level nested properties read/written

/* code omitted for brevity – similar structure focusing on shallow updates of a nested response */

In this case Proxy has a modest edge.

Conclusion

Proxy clearly outperforms Object.defineProperty when creating reactive objects, while Object.defineProperty reads and writes are faster for shallow objects. As nesting depth grows, the advantage of Object.defineProperty diminishes. Vue3 chose Proxy not solely for raw speed but because it offers a more modern, flexible API that simplifies reactive programming.

frontendperformanceJavaScriptProxyVueObject.defineProperty
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.