Write in front: On The morning of November 16, Vue3 previewed some new features of Vuue. Js 3.0 during his keynote in Vue Toronto. One of the important changes is that Vue3 will use ES6 Proxy as its observer mechanism. Replace the object.defineProperty used earlier. I believe many students have the experience that object.defineProperty is a popular research point of vue framework in many interviews. At the beginning, people were a little unfamiliar with this attribute, but gradually with more and more people using Vue, this attribute was often used for research. After everyone became familiar with this property, the authors of VUE decided to replace it with Proxy in the next vue release. Vue3 won’t be released until the second half of next year, but let’s explore the proxy-based observer mechanism and anticipate the Proxy part of vue3’s code (although it doesn’t seem to be useful).

DefineProperty should be replaced by Object.defineProperty. DefineProperty should be replaced by object.defineProperty.

  1. In Vue, Object.defineProperty cannot monitor array subscript changes, so the array is set directly by array subscript and cannot respond in real time. To solve this problem, you can use the following methods to listen for arrays after being handled internally by Vue (as mentioned in the comments section, Object.defineProperty itself can detect array subscript changes.
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
Copy the code

Because only the above eight methods for hack processing, so other array attributes can not be detected, or has certain limitations.

  1. Object.defineproperty can only hijack attributes of objects, so we need to traverse each attribute of each Object. In Vue, the monitoring of data is achieved through recursion and traversal of data objects. If the attribute value is also an object, it needs deep traversal. Obviously, if you can hijack a complete object, there will be a great improvement in both operability and performance.

The Proxy to replace it has the following two advantages;

  • You can hijack an entire object and return a new one
  • There are 13 hijacking operations

Since Proxy can solve the above two problems, and the attribute of Proxy existed before vue2. X, why not use Proxy for vue2. A very important reason is that:

  • Proxy is a new feature provided by ES6 with poor compatibility. The most important thing is that this attribute cannot be compatible with Polyfill

After comments, there is no effective compatibility scheme for Proxy at present. In the future, it will probably be 3.0 and 2.0 parallel, and the choice 2.0 of IE needs to be supported

For object.defineProperty to implement the observer mechanism, please refer to the article analyzing Vue principle & Implementing bidirectional binding MVVM. The following content mainly introduces how to implement Vue observer mechanism based on Proxy.

What is Proxy

1. :

  • Proxy is a new feature in ES6, which translates as “Proxy” and is used to indicate that it “proxies” certain operations. Proxy allows us to control external access to objects in a concise and easy-to-understand way. Its function is very similar to that of the proxy pattern in design mode.
  • Proxy can be understood as a layer of “interception” before the target object. All external access to the object must pass this layer of interception. Therefore, Proxy provides a mechanism for filtering and rewriting external access.
  • The core advantage of using a Proxy is that it can be left to handle some non-core logic (logging before reading or setting certain attributes of an object; Validation is required before setting some property values of an object. Access control for certain attributes, etc.). In this way, the object can only focus on the core logic, to achieve the separation of concerns, reduce the object complexity and other purposes.

2. Basic Usage:

let p = new Proxy(target, handler);
Copy the code

Parameters:

A target is a proxy-wrapped object (which can be any type of object, including a native array, a function, or even another Proxy).

Handler is an object that declares operations on the agent target, and its properties are functions that define the agent’s behavior when an operation is performed.

P is the object after the proxy. Every time the outside world does something to p, it executes some method on the handler object. There are 13 types of Proxy hijacking operations. Some common methods of the handler agent are as follows:

Read the get:setConstruct: determines whether the object has the propertyCopy the code

3. Example: Use Proxy to define the get and set of an object as a basic demo

 let obj = {};
 let handler = {
   get(target, property) {
    console.log(`${property}Be read `);return property in target ? target[property] : 3;
   },
   set(target, property, value) {
    console.log(`${property}Is set to${value}`); target[property] = value; }}let p = new Proxy(obj, handler);
 p.name = 'tom'//name is set to Tom p.age; //age is read by 3Copy the code

When p reads the value of the property, it actually does handler.get() : prints the information on the console and reads the properties of the proxied object obj.

When p sets the property value, it actually does handler.set() : prints the information on the console and sets the property value of the proxied object obj.

This describes the basic use of Proxy, but there is actually a lot more to this attribute, and you can refer to the Proxy documentation for details

3. Implement bidirectional binding based on Proxy

Without further discussion, let’s use Proxy to implement a classic two-way binding todolist, first write a simple HTML structure:

 <div id="app">
      <input type="text" id="input"/> <div> You enter: <span id="title"></span></div>
      <button type="button" name="button" id="btn"> add to todolist</button> <ul id="list"></ul>
 </div>
Copy the code

Let’s start with a Proxy to achieve bidirectional binding display of the input box:

    const obj = {};
    const input = document.getElementById("input");
    const title = document.getElementById("title");
    
    const newObj = new Proxy(obj, {
      get: function(target, key, receiver) {
        console.log(`getting ${key}! `);return Reflect.get(target, key, receiver);
      },
      set: function(target, key, value, receiver) {
        console.log(target, key, value, receiver);
        if (key === "text") {
          input.value = value;
          title.innerHTML = value;
        }
        returnReflect.set(target, key, value, receiver); }}); input.addEventListener("keyup".function(e) {
      newObj.text = e.target.value;
    });
Copy the code

The code here refers to the Reflect property, which is also a new es6 feature and should be referenced in the Reflect documentation if you are not familiar with it. Next we add the Todolist list by rendering the array to the page:

// todolist list const Render = {// init:function(arr) {
        const fragment = document.createDocumentFragment();
        for (let i = 0; i < arr.length; i++) {
          const li = document.createElement("li");
          li.textContent = arr[i];
          fragment.appendChild(li);
        }
        list.appendChild(fragment);
      },
      addList: function(val) {
        const li = document.createElement("li"); li.textContent = val; list.appendChild(li); }};Copy the code

Add Todolist as a Proxy:

const arr = []; Const newArr = new Proxy(arr, {get:function(target, key, receiver) {
        return Reflect.get(target, key, receiver);
      },
      set: function(target, key, value, receiver) {
        console.log(target, key, value, receiver);
        if(key ! = ="length") {
          Render.addList(value);
        }
        returnReflect.set(target, key, value, receiver); }}); // Initialize window.onload =function() {
      Render.init(arr);
    };

    btn.addEventListener("click".function() {
      newArr.push(parseInt(newObj.text));
    });

Copy the code

This implements a simple bidirectional binding Todolist using Proxy, as shown in proxy.html

Implement vUE observer mechanism based on Proxy 1

    observe(data) {
        const that = this;
        let handler = {
         get(target, property) {
            return target[property];
          },
          set(target, key, value) {
            let res = Reflect.set(target, key, value);
            that.subscribe[key].map(item => {
              item.update();
            });
            return res;
          }
        }
        this.$data = new Proxy(data, handler);
      }

Copy the code

$data = this.$data = this.$data = this.$data = this.

2. com from running and watcher

For those familiar with vue, vue2. X comes after new vue (). Vue initializes by calling the _init function, which initializes the lifecycle, events, props, methods, data, computed, watch, and so on. The most important of these is setting setters and getters via Object.defineProperty for “reactive” and “dependent collection”. Something like this internal flow chart:

In addition to observe, a series of mechanisms such as compile and watche are required to implement the basic MVVM bidirectional binding process. We will not expand the description of template compilation here. In order to add Totolist to proxy-based VUE, only compile and Watcher are written here to support the work of Observe. Please refer to proxyVue for the specific code. This code is equivalent to a simplified version of proxy-based VUE, mainly to achieve the function of bidirectional-binding. In order to facilitate here put JS into the HTML page, you can find after local running, now the effect and the effect of the third chapter to achieve the same, wait until next year vue3 release, its source code based on Proxy implementation of the observer mechanism may be a lot of different from the implementation here, This article mainly introduces the feature of Proxy and its applications, and the author himself has learned a lot by exploring the observer mechanism of Proxy. Therefore, the author integrates resources and summarizes this article, hoping to share with you. Above, we will see you next time.