1. Principles of Vue2.0 and Vue3.0

The principle of Vue2.0 implementation of MVVM(two-way data binding) is to hijack the setter and getter of each attribute through object.defineproperty, publish the message to the subscriber when the data changes, and trigger the corresponding listening callback. Vue 3.0 implements a responsive ES6-based Proxy. The differences between the two are as follows:

  • Vue2.0
  1. Based on Object.defineProperty, there is no ability to listen on the array, so you need to redefine the array prototype to achieve responsiveness.
  2. Object.defineproperty cannot detect the addition and deletion of Object attributes.
  3. Since Vue performs getter/setter conversions on properties when initializing instances, all properties must exist on the data object for Vue to convert it to responsive.
  4. Deep monitoring requires one-time recursion, which has a large impact on performance.
  • Vue3.0
  1. With Proxy and Reflect, you can listen natively on arrays, listening for object attributes to be added and removed.
  2. You can significantly improve performance by not having to iterate through data’s properties at once.
  3. Because Proxy is a new attribute in ES6, some browsers do not support it and can only be compatible with IE11.

2. Responsive implementation of Vue2.0

  1. Because Object.defineProperty cannot listen on an array, the array type implements responsiveness and needs to be handled. If it is an array type, override the array’s prototype methods (‘push’,’pop’,’shift’, etc.)
 DefineProperty does not have methods to listen on arrays
 const oldArrayProperty = Array.prototype;
     const arrProto = Object.create(oldArrayProperty);
     ["push"."pop"."shift"."unshift"."splice"].forEach(
         methodName= > 
         (arrProto[methodName] = function() {
             updateView();
             oldArrayProperty[methodName].call(this. arguments); }))Copy the code
  1. The passed data property is deeply listened to determine whether it is an object or an array.
 function observer(target){
     if(typeoftarget ! = ='object' || target === null) {return target
     }
 
     / / if it is an array type, rewrite array prototype method (" push ", "pop", "shift", "unshift", "splice")
     if(Array.isArray(target)){
         target.__proto__ == arrProto;
     }
 
     // If it is an Object, iterate over all the properties of the Object and convert them to getters/setters using Object.defineProperty
     for(let key in target){
         defineReactive(target,key,target[key])
     }
 }
Copy the code
  1. The core API Object.defineProperty converts an incoming property into a getter/setter
function defineReactive(target, key, value){
    // If the object has more layers, call the Observer listener method again for deeper listening.
    observer(value);

    Object.defineProperty(target, key, {
        get(){
            return value;
        },
        set(newValue){
            // Deep listen is also required when setting values
            observer(value);

            if(newValue ! == value){ value = newValue;// Data drives the view. If the data changes, the view update method is called. The corresponding to Vue is to execute VDOMupdateView(); }}})}Copy the code
  1. The data update will trigger the view update, which is the binding principle of MVVM, which will involve the Vue template compilation into the render function, in the implementation of the Virtual Dom, Diff algorithm and other content.
 function updateView(){
     console.log('View Update')}Copy the code
  1. Using the instance
const data = {
  name: "zhangsan".age: 20.info: {
    address: "Beijing" // Deep listening is required
  },
  nums: [10.20.30]}; observer(data);Copy the code

3. Responsive implementation of Vue3.0

Vue3.0 is based on Proxy to do data hijacking Proxy. It can support the response of array natively, without rewriting the prototype of array, and can directly support the addition and deletion of attributes, which is clearer than Object. DefineProperty of vue2.x.

 const proxyData = new Proxy(data, {
   get(target,key,receive){ 
     // Only handle attributes that are themselves (non-archetypes)
     const ownKeys = Reflect.ownKeys(target)
     if(ownKeys.includes(key)){
       console.log('get',key) / / to monitor
     }
     const result = Reflect.get(target,key,receive)
     return result
   },
   set(target, key, val, reveive){
     // Duplicate data is not processed
     const oldVal = target[key]
     if(val == oldVal){
       return true
     }
     const result = Reflect.set(target, key, val,reveive)
     return result
   },
   // Delete attributes
   deleteProperty(target, key){
     const result = Reflect.deleteProperty(target,key)
     return result
   }
 })
Copy the code

Example:

 const data = {
   name: "zhangsan".age: 20.info: {
     address: "Beijing" // Deep listening is required
   },
   nums: [10.20.30]};Copy the code

4. Core source code

  1. Vue2.0 core source code
function defineReactive(target, key, value) {
   // Deep monitor
   observer(value);
 
   Object.defineProperty(target, key, {
     get() {
       return value;
     },
     set(newValue) {
       // Deep monitor
       observer(value);
       if(newValue ! == value) { value = newValue; updateView(); }}}); }function observer(target) {
   if (typeoftarget ! = ="object" || target === null) {
     return target;
   }
 
   if (Array.isArray(target)) {
     target.__proto__ = arrProto;
   }
 
   for (let key intarget) { defineReactive(target, key, target[key]); }}// Redefine the array prototype
 const oldAddrayProperty = Array.prototype;
 const arrProto = Object.create(oldAddrayProperty);
 ["push"."pop"."shift"."unshift"."spluce"].forEach(
   methodName= >
     (arrProto[methodName] = function() {
       updateView();
       oldAddrayProperty[methodName].call(this. arguments); }));// View update
  function updateView() {
   console.log("View Update");
 }
 
 // Declare the object to be reactive
 const data = {
   name: "zhangsan".age: 20.info: {
     address: "Beijing" // Deep listening is required
   },
   nums: [10.20.30]};// execute reactive
 observer(data);
Copy the code
  1. Vue3.0 core source code
  // Declare a responsive object, and Proxy automatically proxies it
 const data = {
   name: "zhangsan".age: 20.info: {
     address: "Beijing" // Deep listening is required
   },
   nums: [10.20.30]};const proxyData = new Proxy(data, {
   get(target,key,receive){ 
     // Only handle attributes that are themselves (non-archetypes)
     const ownKeys = Reflect.ownKeys(target)
     if(ownKeys.includes(key)){
       console.log('get',key) / / to monitor
     }
     const result = Reflect.get(target,key,receive)
     return result
   },
   set(target, key, val, reveive){
     // Duplicate data is not processed
     const oldVal = target[key]
     if(val == oldVal){
       return true
     }
     const result = Reflect.set(target, key, val,reveive)
     console.log('set', key, val)
     return result
   },
   deleteProperty(target, key){
     const result = Reflect.deleteProperty(target,key)
     console.log('delete property', key)
     console.log('result',result)
     return result
   }
 })
 
console.log(proxyData.age);    / / 20
console.log(proxyData.info);   // {address: 'Beijing'}
Copy the code