Vue 2.0 implements data hijacking via Object.defineProperty, while Vue 3.0 replaces it with a proxy that listens to data. DefineProperty and Object.defineProperty. Proxy has certain advantages over Object.defineProperty, otherwise you wouldn’t bother to rewrite it, so today we’ll talk about Object.defineProperty and proxy.

Object. DefineProperty disadvantage

  • Unable to implement listening on arrays.

But as anyone who has used VUe2.0 knows, when an array changes, the view changes too. How does that work? Here’s what it’s all about. The main reason is that Vue2.0 overrides the array. prototype method, which changes its prototype when listening to data of an Array type.

Function updateView() {console.log(" View is about to be updated "); } // Array prototype const oldPrototype = array.prototype; Const newPrototype = object.create (array.prototype); // Create an empty Object that points to array.prototype. Const arrayMethod = ["push", "pop", "shift", "unshift"]; arrayMethod.forEach((methodName) => { newPrototype[methodName] = function () { oldPrototype[methodName].call(this, ... arguments); updateView(); }; });Copy the code

In the previous article, data hijacking still has some defects, there is no array listening, now that we know the principle, next, look at the specific code implementation:

function observer(data) { if (isBaseType(data)) return data; If (isArray(data)) data.__proto__ = newPrototype object.keys (data).foreach ((key) => {defineReactive(data, key, data[key]); }); }Copy the code

Although this can achieve array listening, but compared with proxy, or more trouble.

  • To achieve the object of deep listening, need to recurse to the end. For the data with deep hierarchy, the computation is large.

Specific how to implement object deep listening, you can refer to my last article.

  • Unable to listen for new/delete attributes (but vue2.0 provides additional apis, vue.set and vue.delete respectively)

For these and other reasons, Ueda decided to change the way it listened to its data.

Proxy

Proxy is a new API in ES6. Proxy builds a layer of interception on the outer layer of the target object. Some operations on the target object must pass this layer of interception, so we can accomplish what we want to accomplish in this layer of interception.

Let’s look at the specific use of proxy. First, we need to generate a proxy instance as follows:

const proxy = new Proxy(target, handler);
Copy the code

The target parameter represents the target object to intercept, and the handler parameter is also an object used to customize the interception behavior. Continue with the following code:

Const target = {name: 'poetries',}; const handler = { get: function(target, key, receive) { const result = Reflect.get(target, key,receive); Console. log(' ${key} was read ',result); return result; }, set: function(target, key, value, receive) { const result = Reflect.set(target, key, value, receive); Console. log(' ${key} is set to ${value} '); return result; }, deleteProperty: function(target, key){ const result = Reflect.deleteProperty(target, key); Console. log(' ${key} 'deleted); return result; }}Copy the code

As we can see from the above code, we can execute our business logic arbitrarily until the operation completes some property of the object. The next step is to use proxies instead of Object.defineProperty to implement data hijacking.

function observer(data) { if (isBaseType(data)) return data; Const handler = {get: function(target, key, receive) {const ownKeys = reflect.ownKeys (target); If (ownkeys.includes (key)){console.log(' ${key}, you have been listening '); } const result = Reflect.get(target, key,receive); Console. log(' ${key} was read ',result); return observer(result); }, set: function(target, key, value, receive) {if(target[key] === value){return true; } const result = Reflect.set(target, key, value, receive); Console. log(' ${key} is set to ${value} '); // Deep listener, unlike Object.defineProperty, only listens for attributes in the Object if the Object is used. return result; }, deleteProperty: function(target, key){ const result = Reflect.deleteProperty(target, key); Console. log(' ${key} 'deleted); return result; } } const observedData = new Proxy(data,handler); return observedData; }Copy the code

Therefore, proxy is a good way to avoid the object.defineProperty problem.