Data Reactivity Mechanisms: Vue 2 vs Vue 3

Data Proxy and Data Hijacking

Understanding Vue's reactivity system requires examining two key concepts: data proxy and data hijacking.

Data proxy involves creating processed copies of properties defined in the data option. When accessing vm._data, you interact with getter and setter methods for each property. When a property changes, the setter triggers template re-parsing, generating a new virtual DOM that gets compared witth the previous version before updating the view.

Data hijacking attaches getters and setters directly to data properties to enable reactive monitoring. The getter activates when a property is read, while the setter fires when data is modified.

In Vue 2, arrays defined in data without explicit keys lack proper hijacking—meaning no getters or setters exist. Modifying such arrays through index assignment won't trigger updates. Newly added properties after initialization also lack reactivity unless addressed through Vue.set. Vue 2 intercepts array mutation methods like push, pop, and splice to ensure template re-parsing occurs.

Vue 2 Reactivity Implementation

Vue 2 leverages Object.defineProperty to implement reactivity within the data function:

const person = {};
Object.defineProperty(person, 'name', {
    get() {
        console.log('Property read detected');
        return person.name;
    },
    set(newValue) {
        console.log('Property modification detected');
        person.name = newValue;
    }
});

The getter retrieves data while triggering dependency tracking, and the setter updates the underlying value before initiating template re-rendering.

Vue 3 Reactivity Implementation

Vue 3 employs Proxy for reactivity. With the composition API's <script setup> syntax, variables can be declared directly. When using the setup function, variables must be returned to expose them:

const userData = {
    name: 'Zhang San',
    gender: 'Male'
};

const proxyUser = new Proxy(userData, {
    get(target, propKey) {
        console.log('Reading:', target, propKey);
        return target[propKey];
    },
    set(target, propKey, newVal) {
        console.log('Updating:', newVal);
        target[propKey] = newVal;
        return true;
    },
    deleteProperty(target, propKey) {
        return delete target[propKey];
    }
});

Reactive Primitives in Vue 3

The ref function handles reactivity for primitive values in Vue 3. Internally, it relies on Object.defineProperty for basic types. For objects and arrays, ref delegates to Proxy:

import { ref, reactive } from 'vue';

// Basic type - uses Object.defineProperty internally
const count = ref(0);

// Object type - uses Proxy internally
const state = reactive({
    items: [],
    config: { theme: 'dark' }
});

The reactive function in Vue 3 functions similarly to Object.defineProperty, but getters and setters receive the entire data object rather than individual properties. The set handler in Proxy also accepts an additional parameter compared to Vue 2, and Proxy provides a built-in deleteProperty handler.

Key Differences

Vue 2's reactivity foundation rests on ES5's Object.defineProperty, which presents several limitations:

  1. Deep observation requires recursive traversal, presenting performance concerns
  2. Cannot detect property addition or removal without Vue-specific utilities
  3. Requires array method interception at the prototype level

Vue 3 adopts ES6's Proxy to address these constraints. Proxy enables:

  • Monitoring entire objects rather than individual properties
  • Direct observation of array mutations
  • Operations on a new proxy object without object iteration
  • Browser vendor performance optimizations as a modern standard

The Proxy API natively handles property additions, deletions, index-based array modifications, length changes, and supports collections like Map, Set, WeakMap, and WeakSet without additional configuration.

Tags: Vue.js javascript Reactivity Proxy Object.defineProperty

Posted on Fri, 15 May 2026 01:53:19 +0000 by OhLordy