This is the 27th day of my participation in Gwen Challenge

preface

Vue3 has been released for a long time and we know that the biggest change to vue3 in this version is the change in the implementation of two-way binding, changing defineProperty to proxy. So why did Vue make this change? What are the advantages of proxy? Let’s talk about it today.

defineProperty

Es5 added defineProperty, which allows you to add or modify an attribute to an object and then return the object.

grammar

Object.defineProperty(obj, prop, descriptor)

obj

The target object

prop

Attribute name, usually a string, or symbol

descriptor

Attribute description of attribute name, object format

  • Value: Indicates the value of the attribute

  • Writable: Whether a property can be assigned. Default is false

  • Enumerable: Whether a property can be enumerable. The default is false

  • The default is false, and the default is different

  • The set setter function, called when a property is modified, cannot be used in conjunction with writable.

  • The get getter function is called when a property is accessed. It cannot be used together with value.

example

// Do getter/setter for name
let obj = Object.defineProperty({}, 'name', {
  get () {
    return 'the answer cp3'
  },
  set () {
    console.log('Setter function called! ')}})console.log(obj.name) / / the answer cp3
obj.name = 'test' // The setter function is called!
Copy the code

As you can see, we’ve defined set and get to call GET when we get a property, and set when we set a property.

proxy

Es6 adds proxy to implement object proxy and intercept basic operations (add, delete, modify, and search).

grammar

new Proxy(target, handler)

target

The target object for which the proxy is needed

handler

Various operations on proxy objects, object forms, and keys are functions.

The following methods are supported:

  • getGetter function This function is called when a property is accessed
  • setSetter functions call this function when a property is modified
  • hasThis function is called when the in operator is used
  • getPrototypeOfGet the prototype chain, interceptObject.getPrototypeOf
  • setPrototypeOfSet up prototype chain, interceptObject.setPrototypeOf
  • isExtensibleDetermine whether an object can be extended and interceptedObject.isExtensible
  • preventExtensionsSet object unextensible, interceptObject.preventExtensions
  • getOwnPropertyDescriptorReturns the property description of the property, interceptionObject.getOwnPropertyDescriptor
  • definePropertyDefine attributes, interceptObject.defineProperty
  • deletePropertyDelete attributes, interceptdeleteThe operator
  • ownKeysReturns an array of enumerable elements, interceptsObject.getOwnPropertyNamesandObject.getOwnPropertySymbols
  • applyintercepttargetIt’s a function call
  • constructinterceptnewOperator, which requirestargetIt has to be a function.

These method names are the same as the method names of the Reflect object, and we can call Reflect directly from within.

example

// Basic usage
let obj = new Proxy({}, {
  get () {
    return 'the answer cp3'
  },
  set () {
    console.log('Setter function called! ')}})// proxy {}
console.log(obj.name) / / the answer cp3
obj.name = 'test' // The setter function is called!
Copy the code
// Simulate private attributes
Use the has method to hide certain attributes from the IN operator
var handler = {
  get (target, key) {
    if (key.startsWith('_')) {
      console.error('Access to private attributes is not supported! ')
      return false
    }
    return Reflect.get(target, key)
  },
  set (target, key, val) {
    if (key.startsWith('_')) {
      console.error('Setting private properties is not supported! ')
      return false
    }
    return Reflect.set(target, key, val)
  },
  has (target, key) {
    if (key.startsWith('_')) {
      console.error('Detecting private attributes is not supported! ')
      return false
    }
    return Reflect.has(target, key)
  }
};
var target = { _name: 'I'm a private property'.name: 'the answer cp3'};
var proxy = new Proxy(target, handler);
console.log('_name' in proxy); // false
proxy._name = 123; // false
console.log(proxy._name);  // false


console.log('name' in proxy); // true
proxy.name = 123;    // true
console.log(proxy.name);  / / 123
Copy the code

The difference between

Here is the difference between the two in VUE:

  1. DefineProperty can only listen for defined attributes, but cannot listen for new attributes or deleted attributes. Proxy listens for the whole object, and responds to new attributes or deleted attributes.

    Here’s a simple code:

    let name = 'the answer cp3'
    let obj = { name }
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        Object.defineProperty(obj, key, {
          get () {
            console.log('Get function called')
            return name
          },
          set (val) {
            console.log('Set function called')
            name = val
          }
        })
      }
    }
    obj.name = 'cp3' // The set function is called
    obj.age = 18 // No print set is called
    console.log(obj.name) // The get function is called
    console.log(obj.age) // No print
    Copy the code

    As you can see, the new age attribute is not as successful as defineProperty, so vue can only provide a $set method to handle it.

    For proxies, this problem is not present. Let’s see by example

    let name = 'the answer cp3'
    let obj = new Proxy({ name }, {
      get (target, key) {
        console.log('Get function called')
        return target[key]
      },
      set (target, key, val) {
        console.log('Set function called')
        target[key] = val
      }
    })
    obj.name = 'cp3' // The set function is called
    obj.age = 18 // The set function is called
    console.log(obj.name) // The get function is called
    console.log(obj.age) // The get function is called
    Copy the code
  2. Vue defineProperty does not implement array listening. It only provides push, POP, sort, reserve, splice, unshift, shift and other methods to trigger array listening. The proxy listens for the entire object and responds to new or deleted elements.

    let arr = new Proxy([1.2.3], {
      get (target, key) {
        console.log('Get function called')
        return Reflect.get(target, key)
      },
      set (target, key, val) {
        console.log('Set function called')
        return Reflect.set(target, key, val)
      }
    })
    console.log(arr[0]) // The get function is called
    arr[3] = 4  // The set function is called
    arr.push(5)// The set function is called
    Copy the code
  3. In addition, for defineProperty, there are only 2 GET and SET methods, while there are as many as 13 methods on proxy, which can basically meet various needs.

  4. The problem with Proxy is that it is not compatible because it is a new API for ES6.

The last

Today, I will briefly talk about the comparison between VUe3 proxy and VUe2 defineProperty. Proxy can realize many more functions than defineProperty. I hope what I said today is helpful to you