VueJS: Implementing Proxy behaviour of Data object

The official Vue guide for the Vue instance tells that the instance object proxies all properties found in the instance’s data object.

var data = { a: 1 }

var vm = new Vue({ data })

vm.a === data.a // -> true
// setting the property also affects original data
vm.a = 2
data.a // -> 2

// ... and vice-versa
data.a = 3
vm.a // -> 3

We’ll replicate this behaviour in a vanilla JS function. You don’t have to know about VueJS to follow the rest of the post. It’s just about javascript.

function myVue(opts){
  this._data = opts.data;
  Object
    .keys(opts.data)
    .forEach(key => {
      props = {
        configurable: true,
        enumerable: true,
        get() { return this._data[key]; },
        set(val) { this._data[key] = val; }
      }
      Object.defineProperty(this, key, props);
    });
}

Let’s try this "myVue" function with the same example as from the official guide.

let data = { a: 1 };

let vm = new myVue({ data });

console.log(vm.a === data.a);

// setting the property also affects original data
vm.a = 2;
data.a // -> 2

// ... and vice-versa
data.a = 3;
vm.a // -> 3

It works!

But how?

The key JS feature that enables this behaviour is Getters and Setters of the javascript object.

It lets you define properties which are not hard-coded, instead are represented by functions that dynamically return values.

Conclusion

I came to know about this technique after finding it in the VueJS source code. The magic happens in the src/core/instance/state.js file.

The initData function does the work. It loops over data’s keys and asks the proxy function to define the proxied properties on the Vue instance itself.

Thoughts on the post are welcome! Mail me at prasanna@npras.in or .