Two way binding with Proxy

We need to use Proxy to implement two-way binding in vue3.0, so let's try to implement it first.

1 implementation of object.defineproperty
The original implementation of vue2 uses Object.defineProperty to listen to set, but it can't listen to the set value of array directly subscript.

function observe(data) {
  if (!data || typeof data !== 'object') {
      return;
  }
  // Take out all attribute traversal
  Object.keys(data).forEach(function(key) {
      defineReactive(data, key, data[key]);
  });
};

function defineReactive(data, key, val) {
  observe(val); // Listen to child properties
  Object.defineProperty(data, key, {
      enumerable: true, // enumerable
      configurable: false, // defineProperty can no longer be overridden
      get: function() {
          return val;
      },
      set: function(newVal) {
          console.log('-------Notify subscribers--------')
          val = newVal;
      }
  });
}

2 implement with Proxy

The main principle of using Proxy is to use a new Proxy object to Proxy your data value. It should be noted that for array method operations, there will be two assignment operations, one is to add a value, the other is to change its length value. For array subscripts that cannot be monitored by Object.defineProperty, the Proxy can monitor.

function observe(data) {
    if (!data || typeof data !== 'object') {
        return;
    }
    // Take out all attribute traversal
    Object.keys(data).forEach(function(_k) {
        // Proxy does not allow binding on non object
        if (data[_k] && typeof data[_k] === 'object') {
            data[_k] = defineReactive(data[_k]);
        }
    });
}

function defineReactive(data) {
  return new Proxy(data, {
    set(target, key, value, proxy) {
        // During array operation, the data will be set twice, the data will be changed once, the length will be changed once, and the data value will be changed twice, so the message should not be distributed once more
      if (
        Object.prototype.toString.call(data) === "[object Array]" &&
        key === "length"
      ) {
        Reflect.set(target, key, value, proxy);
        return true;
      }
      observe(data);
      Reflect.set(target, key, value, proxy);
      console.log('-------Notify subscribers--------')
      return true;
    }
  });

Tags: Javascript Attribute

Posted on Mon, 02 Dec 2019 14:54:48 -0500 by jammesz