People who drive cars often do not understand the mechanics of the car, but an in-depth understanding of the mechanics of the car can have a powerful effect

1. Introduction

As vue3.x gets more and more popular, so does the discussion of proxy. How does proxy differ from Object.defineProperty, what advantages it has, and where it can be used? This article is a brief introduction

2.Object.defineProperty

Before we talk about proxy, let’s review Object.defineProperty. As you know, vue2. X and previous versions use Object.defineProperty to implement bidirectional binding of data. How? So let’s do a simple implementation

function observer(obj) {
    if (typeof obj ==='object') {
        for (let key in obj) {
            if(obj.hasOwnProperty(key)){
                defineReactive(obj, key, obj[key])
            }
        }
    }
}

function defineReactive(obj, key, value) {
    // Check recursively if value is an object
    observer(value)
    // The key of the object being hijacked
    Object.defineProperty(obj, key, {
        get() {
            console.log('Get:'+key)
            return value
        },
        set(val) {
            // Val is the object for which it is set
            observer(val)
            console.log(key+"- The data has changed.")
            value = val
        }
    })
}

let obj={
    name:'wait'.flag: {book: {name:'js'.page:325
        },
        interest: ['hot pot'.'travel'],
    }
}

observer(obj)
Copy the code

Run it in the browser’s console and it seems to work

But in reality, object.defineProperty has the following problems

Fault 1. Deleting or adding object attributes cannot be monitored

For example, add a gender attribute, which cannot be listened on because it is not available when the observer(obj) is implemented. Deleted properties are also not listened in

To add attributes, vue needs to operate with $set, and also with Object.defineProperty inside $set

Problem 2. Array changes cannot be heard

As you can see from the figure above, although the array property is actually modified successfully, it cannot be listened on

Problem 3. Because the Object is traversed recursively, the attribute of the Object is hijacked by object.defineProperty. If the traversed Object has a deep hierarchy, it takes a long time and even has performance problems

3.proxy

For proxy, the description on MDN is: custom behavior of objects used to define basic operations (such as property lookup, assignment, enumeration, function call, etc.)

Simply put, you can place a layer of interception on the target object. So whatever you do to the target object, you go through this layer of interception, right

It might sound like a proxy is better and much simpler than Object.defineProperty, but it is. Let’s use proxy to rewrite the above code

function observerProxy(obj){
    let handler = {
      get (target, key, receiver) {
        console.log('Get:'+key)
        // If it is an object, add proxy interception recursively
        if (typeof target[key] === 'object'&& target[key] ! = =null) {
          return new Proxy(target[key], handler)
        }
        return Reflect.get(target, key, receiver)
      },
      set (target, key, value, receiver) {
        console.log(key+"- The data has changed.")
        return Reflect.set(target, key, value, receiver)
      }
    }
    return new Proxy(obj, handler)
}


let obj={
    name:'wait'.flag: {book: {name:'js'.page:325
        },
        interest: ['hot pot'.'travel'].}}let objTest=observerProxy(obj)
Copy the code

Same effect

Also, it can do things that Object.defineProperty can’t, such as adding an attribute gender to listen in

Operate on arrays, can also listen

Finally, tap on the board to summarize the differences

1. Object.defineproperty intercepts attributes of an Object and changes the original Object. Proxy intercepts the entire object and generates a new object through new without changing the original object.

2. There are 11 proxy interception modes in addition to get and set. DefineProperty can also listen for operations that Object. DefineProperty can’t listen for, such as listening for arrays, adding and deleting attributes of objects, etc.

4. Proxy application scenario

As for the usage scenarios of proxy, due to the limited space, here are a few, and more can be referred to MDN.

See here, the difference between the two, and the advantages of proxy already know a general. However, in development, what scenarios can proxy be used? Here are some possible situations

4-1. Negative-indexed arrays

With apis like Splice (-1) and Slice (-1), negative numbers are positioned at the end of the array when entered, but they cannot be used on normal arrays. [-1] This code does not print 3. To make the above code print 3, you can also use a proxy implementation.

let ecArrayProxy = {
  get (target, key, receiver) {
    let _index=key<0? target.length+Number(key):key
    return Reflect.get(target, _index, receiver)
  }
}
let arr=new Proxy([1.2.3],ecArrayProxy)
Copy the code

4-2. Form verification

When a change is made to a form value, it can be intercepted in a set to determine whether the value is valid

let ecValidate = {
  set (target, key, value, receiver) {
    if (key === 'age') {
      // If the value is less than 0 or not a positive integer
      if (value<0| |!Number.isInteger(value)) {
        throw new TypeError('Please enter the correct age'); }}return Reflect.set(target, key, value, receiver)
  }
}

let obj=new Proxy({age:18},ecValidate)
obj.age=16
obj.age='young'
Copy the code

4-3. Add additional attributes

For example, there is a requirement to ensure that the user enters the correct ID number and then adds the date of birth, place of birth, and gender to the user’s information

As we all know, the first and second id numbers represent the province (autonomous region, municipality directly under the Central Government, special administrative region), and the third and fourth numbers represent the city (prefecture-level city, autonomous prefecture, league and national municipality directly under the municipal district and county summary code). The seventh to fourteenth are birth years, months and days. The lower 17 represent the genders, men in singles and women in doubles.

const PROVINCE_NUMBER={
    44:'Guangdong'.46:'Hainan'
}
const CITY_NUMBER={
    4401:'Guangzhou'.4601:'Haikou'
}

let ecCardNumber = {
  set (target, key, value, receiver) {
    if(key === 'cardNumber') {Reflect.set(target, 'hometown', PROVINCE_NUMBER[value.substr(0.2)]+CITY_NUMBER[value.substr(0.4)], receiver)
        Reflect.set(target, 'date', value.substr(6.8), receiver)
        Reflect.set(target, 'gender', value.substr(2 -.1) %2= = =1?'male':'woman', receiver)
    }
    return Reflect.set(target, key, value, receiver)
  }
}
let obj=new Proxy({cardNumber:' '},ecCardNumber)
Copy the code

4-4. Data formatting

For example, there is a requirement to pass a timestamp to the back end, but the front end gets a time string, this can also be intercepted by proxy, when the time string, can automatically add the timestamp.

let ecDate = {
  set (target, key, value, receiver) {
    if(key === 'date') {Reflect.set(target, 'timeStamp', +new Date(value), receiver)
    }
    return Reflect.set(target, key, value, receiver)
  }
}
let obj=new Proxy({date:' '},ecDate)
Copy the code

Refer to the link

Proxy

Interviewer: How better is implementing a two-way binding Proxy than defineProperty?

Understand Proxy in Vue3.0

summary

Some differences between proxy and Object.defineProperty, as well as advantages of proxy and usage scenarios, are briefly introduced here. The introduction of this article is not in-depth, it is not difficult to understand. As for proxy, the author also plans to further study it. If I gain something in the future, I will share it as soon as possible. If there are any mistakes or suggestions, please leave them in the comments section.

— — — — — — — — — — — — — — — — — — — — — — — — — gorgeous line — — — — — — — — — — — — — — — — — — — —

To learn more and communicate with me, please add me on wechat. Or follow my wechat public number: Waiting book Pavilion