preface

Hello, everyone, I am Lin Sanxin, we also know that the rookie usually write basic articles more, I always believe in two words

  • Explain the most difficult points in the most plain language
  • Foundation is a prerequisite for advancement

Vue3 has been around for a long time, and most companies are probably using it, but how is it better than Vue2? A lot of people don’t know. Today I will first tell you about Vue3’s response principle, by the way, Vue3’s response is better than Vue2’s response.

What’s good about it?

Ok, so let’s talk about why Vue3 is better than Vue2. May usually ask you: do you know how the Vue response is achieved? You can give a rough answer

  • The response formula of Vue2 is based onObject.definePropertyImplementation of the
  • Vue3’s responsiveness is based on ES6ProxyTo implement the

Yes, although the above answer is a little abstract, it does answer the core principle of the two versions of Vue responsiveness, and the good and bad of the two versions of Vue responsiveness is indeed reflected in the difference between Object.defineProperty and Proxy.

Vue2

We all know that Vue2’s response is based on Object.defineProperty, so I’ll take Object.defineProperty as an example

// response function
function reactive(obj, key, value) {
  Object.defineProperty(data, key, {
    get() {
      console.log(Visited `${key}Attribute `)
      return value
    },
    set(val) {
      console.log(` will${key}By the - >${value}-> Set to ->${val}`)
      if(value ! == val) { value = val } } }) }const data = {
  name: 'Lin Three Hearts'.age: 22
}
Object.keys(data).forEach(key= > reactive(data, key, data[key]))
console.log(data.name)
// Access the name attribute
/ / Lin three hearts
data.name = 'sunshine_lin' // Change name from -> Lin -> to ->sunshine_lin
console.log(data.name)
// Access the name attribute
// sunshine_lin
Copy the code

From the above example, I think we all have an idea about Object.defineProperty. What’s the problem? What are the disadvantages of it? Caused yudha to abandon it in Vue3. Let’s see:

// Continue with the above code

data.hobby = 'Play basketball'
console.log(data.hobby) / / to play basketball
data.hobby = 'Play games'
console.log(data.hobby) / / playing video games
Copy the code

DefineProperty Object defineProperty Object defineProperty Data has a new hobby property, which can be accessed and set, but neither get nor set is triggered. Therefore, object.defineProperty only listens for attributes in the original Object, but does not listen for new attributes. This is why Vue2 uses vue. $set to modify new attributes of objects.

Vue3

Object.defineproperty () : Object defineProperty () : Object defineProperty () : Object defineProperty () : Object defineProperty

const data = {
  name: 'Lin Three Hearts'.age: 22
}

function reactive(target) {
  const handler = {
    get(target, key, receiver) {
      console.log(Visited `${key}Attribute `)
      return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      console.log(` will${key}By the - >${target[key]}-> Set to ->${value}`)
      Reflect.set(target, key, value, receiver)
    }
  }

  return new Proxy(target, handler)
}

const proxyData = reactive(data)

console.log(proxyData.name)
// Access the name attribute
/ / Lin three hearts
proxyData.name = 'sunshine_lin'
// Change name from -> Lin -> to ->sunshine_lin
console.log(proxyData.name)
// Access the name attribute
// sunshine_lin
Copy the code

DefineProperty is the same as object.defineProperty, so why do you choose Proxy instead of object.defineProperty? Note, the most critical to come, that is the object new attribute, let’s see the effect:

proxyData.hobby = 'Play basketball'
console.log(proxyData.hobby)
// The Hobby property is accessed
/ / to play basketball
proxyData.hobby = 'Play games'
// Change hobby from -> playing basketball -> to -> playing games
console.log(proxyData.hobby)
// The Hobby property is accessed
/ / playing video games
Copy the code

So now you see how Vue3’s response is better than Vue2’s?

Vue3 response principle

With the benefits of Proxy out of the way, let’s talk formally about the core of Vue3’s responsive principle.

preface

Take a look at the following code

let name = 'Lin Three Hearts', age = 22, money = 20
let myself = `${name}This year,${age}Age, deposit${money}Yuan `

console.log(myself) // Lin Sanxin is 22 years old and has 20 yuan in her savings

money = 300

// Expectation: Lin Sanxin is 22 years old and has 300 yuan in savings
console.log(myself) // Reality: Lin Sanxin is 22 years old and has 20 yuan in savings
Copy the code

Think about it. I want myself to change with money. What should I do? ${money} ${money} ${name} ${age} ${name} ${age

let name = 'Lin Three Hearts', age = 22, money = 20
let myself = `${name}This year,${age}Age, deposit${money}Yuan `

console.log(myself) // Lin Sanxin is 22 years old and has 20 yuan in her savings

money = 300

myself = `${name}This year,${age}Age, deposit${money}Yuan ` // Execute again

// Expectation: Lin Sanxin is 22 years old and has 300 yuan in savings
console.log(myself) // Reality: Lin Sanxin is 22 years old and has 300 yuan in savings
Copy the code

effect

Each time money changes, I have to implement myself = ‘${name} this year ${age}, deposit ${money} ‘again to update myself

let name = 'Lin Three Hearts', age = 22, money = 20
let myself = ' '
const effect = () = > myself = `${name}This year,${age}Age, deposit${money}Yuan `

effect() // Execute once
console.log(myself) // Lin Sanxin is 22 years old and has 20 yuan in her savings
money = 300

effect() // Execute again

console.log(myself) // Lin Sanxin is 22 years old and has 300 yuan in her savings
Copy the code

In fact, this is also bad, do not believe you can look at the following situation

let name = 'Lin Three Hearts', age = 22, money = 20
let myself = ' ', ohtherMyself = ' '
const effect1 = () = > myself = `${name}This year,${age}Age, deposit${money}Yuan `
const effect2 = () = > ohtherMyself = `${age}At the age of${name}Had the${money}Yuan `

effect1() // Execute once
effect2() // Execute once
console.log(myself) // Lin Sanxin is 22 years old and has 20 yuan in her savings
console.log(ohtherMyself) // Lin Sanxin, 22, had 20 yuan
money = 300

effect1() // Execute again
effect2() // Execute again

console.log(myself) // Lin Sanxin is 22 years old and has 300 yuan in her savings
console.log(ohtherMyself) // Lin Sanxin, 22, had 300 yuan
Copy the code

To add ohtherMyself, you have to write another effect and execute it every time you update it. If you add a lot of ohtherMyself, you have to write a lot of effect function execution code every time.

Track and the trigger

The track function collects all the effect functions that depend on the money variable and places them in the DEP. Because Set can automatically de-weight. Once collected, the trigger function will be executed to notify all effect functions in DEP that depend on the money variable to execute whenever the money variable changes in the future, so as to realize the update of the dependent variable. So let’s take a look at the code, and then I’m going to show you a picture just in case you get dizzy.

let name = 'Lin Three Hearts', age = 22, money = 20
let myself = ' ', ohtherMyself = ' '
const effect1 = () = > myself = `${name}This year,${age}Age, deposit${money}Yuan `
const effect2 = () = > ohtherMyself = `${age}At the age of${name}Had the${money}Yuan `

const dep = new Set(a)function track () {
    dep.add(effect1)
    dep.add(effect2)
}
function trigger() {
    dep.forEach(effect= > effect())
}
track() // Collect dependencies
effect1() // Execute once
effect2() // Execute once
console.log(myself) // Lin Sanxin is 22 years old and has 20 yuan in her savings
console.log(ohtherMyself) // Lin Sanxin, 22, had 20 yuan
money = 300

trigger() // Notify the variables myself and otherMyself to be updated

console.log(myself) // Lin Sanxin is 22 years old and has 300 yuan in her savings
console.log(ohtherMyself) // Lin Sanxin, 22, had 300 yuan
Copy the code

Objects?

So let’s talk about objects, and I’ll give you an example of how to implement their responses in a primitive way

const person = { name: 'Lin Three Hearts'.age: 22 }
let nameStr1 = ' '
let nameStr2 = ' '
let ageStr1 = ' '
let ageStr2 = ' '

const effectNameStr1 = () = > { nameStr1 = `${person.name}He's a rookie }
const effectNameStr2 = () = > { nameStr2 = `${person.name}A little genius }
const effectAgeStr1 = () = > { ageStr1 = `${person.age}Age is very old }
const effectAgeStr2 = () = > { ageStr2 = `${person.age}Age is still very young ah }

effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// Lin Sanxin is a rookie. Lin Sanxin is a genius. Twenty-two is very old

person.name = 'sunshine_lin'
person.age = 18

effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()

console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// Sunshine_lin is a rookie sunshine_lin is a genius 18 is old 18 is still young
Copy the code

The above code, we also see, feel write very brainless. Remember the DEP collection effect? Let’s think of the name and age in the Person object as two variables, each with its own dependent variable

  • Name: nameStr1 and nameStr2
  • Age: ageStr1 and ageStr2

Therefore, name and age should have their own DEPs and collect the corresponding effects of their dependent variables

A deP is a Set. A person has an age and a name, so it has two DEPs. We can use another ES6 data structure, Map, to store it

const person = { name: 'Lin Three Hearts'.age: 22 }
let nameStr1 = ' '
let nameStr2 = ' '
let ageStr1 = ' '
let ageStr2 = ' '

const effectNameStr1 = () = > { nameStr1 = `${person.name}He's a rookie }
const effectNameStr2 = () = > { nameStr2 = `${person.name}A little genius }
const effectAgeStr1 = () = > { ageStr1 = `${person.age}Age is very old }
const effectAgeStr2 = () = > { ageStr2 = `${person.age}Age is still very young ah }

const depsMap = new Map(a)function track(key) {
    let dep = depsMap.get(key)
    if(! dep) { depsMap.set(key, dep =new Set()}// For now, I'm going to write it dead
    if (key === 'name') {
        dep.add(effectNameStr1)
        dep.add(effectNameStr2)
    } else {
        dep.add(effectAgeStr1)
        dep.add(effectAgeStr2)
    }
}
function trigger (key) {
    const dep = depsMap.get(key)
    if (dep) {
        dep.forEach(effect= > effect())
    }
}

track('name') // Collect the person.name dependency
track('age') // Collect person.age dependencies



effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// Lin Sanxin is a rookie. Lin Sanxin is a genius. Twenty-two is very old

person.name = 'sunshine_lin'
person.age = 18

trigger('name') // Notify the dependent variable of Person.name to be updated
trigger('age') // Notify the dependent variable of Person.age to be updated

console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// Sunshine_lin is a rookie sunshine_lin is a genius 18 is old 18 is still young
Copy the code

We only have one Person object. What if we have multiple objects? How to do? We all know that each object creates a Map to store the DEP of the attributes in the object (using a Set). If there are multiple objects, how do we store the Map of each object? Please see below

In fact, ES6 also has a new data structure called WeakMap, let’s use it to store the Map of these objects. So we need to modify the track and trigger functions to see what they look like before

const depsMap = new Map(a)function track(key) {
    let dep = depsMap.get(key)
    if(! dep) { depsMap.set(key, dep =new Set()}// For now, I'm going to write it dead
    if (key === 'name') {
        dep.add(effectNameStr1)
        dep.add(effectNameStr2)
    } else {
        dep.add(effectAgeStr1)
        dep.add(effectAgeStr2)
    }
}
function trigger (key) {
    const dep = depsMap.get(key)
    if (dep) {
        dep.forEach(effect= > effect())
    }
}
Copy the code

The previous code only did the processing scheme of a single object, but now if you want multiple objects, you have to use WeakMap for transformation (the following code may be a little wordy, but it will take care of students with weak foundation)

const person = { name: 'Lin Three Hearts'.age: 22 }
const animal = { type: 'dog'.height: 50 }

const targetMap = new WeakMap(a)function track(target, key) {
    let depsMap = targetMap.get(target)
    if(! depsMap) { targetMap.set(target, depsMap =new Map()}let dep = depsMap.get(key)
    if(! dep) { depsMap.set(key, dep =new Set()}// For now, I'm going to write it dead
    if (target === person) {
        if (key === 'name') {
            dep.add(effectNameStr1)
            dep.add(effectNameStr2)
        } else {
            dep.add(effectAgeStr1)
            dep.add(effectAgeStr2)
        }
    } else if (target === animal) {
        if (key === 'type') {
            dep.add(effectTypeStr1)
            dep.add(effectTypeStr2)
        } else {
            dep.add(effectHeightStr1)
            dep.add(effectHeightStr2)
        }
    }
}

function trigger(target, key) {
    let depsMap = targetMap.get(target)
    if (depsMap) {
        const dep = depsMap.get(key)
        if (dep) {
            dep.forEach(effect= > effect())
        }
    }
}
Copy the code

After the above transformation, we finally realize the dependency collection of multiple objects, let’s give it a try

const person = { name: 'Lin Three Hearts'.age: 22 }
const animal = { type: 'dog'.height: 50 }
let nameStr1 = ' '
let nameStr2 = ' '
let ageStr1 = ' '
let ageStr2 = ' '
let typeStr1 = ' '
let typeStr2 = ' '
let heightStr1 = ' '
let heightStr2 = ' '

const effectNameStr1 = () = > { nameStr1 = `${person.name}He's a rookie }
const effectNameStr2 = () = > { nameStr2 = `${person.name}A little genius }
const effectAgeStr1 = () = > { ageStr1 = `${person.age}Age is very old }
const effectAgeStr2 = () = > { ageStr2 = `${person.age}Age is still very young ah }
const effectTypeStr1 = () = > { typeStr1 = `${animal.type}He's a rookie }
const effectTypeStr2 = () = > { typeStr2 = `${animal.type}A little genius }
const effectHeightStr1 = () = > { heightStr1 = `${animal.height}That's pretty high }
const effectHeightStr2 = () = > { heightStr2 = `${animal.height}Still calculate very short ah }

track(person, 'name') // Collect the person.name dependency
track(person, 'age') // Collect person.age dependencies
track(animal, 'type') // animal.type dependency
track(animal, 'height') // Collect animal.height dependency



effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()
effectTypeStr1()
effectTypeStr2()
effectHeightStr1()
effectHeightStr2()

console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// Lin Sanxin is a rookie. Lin Sanxin is a genius. Twenty-two is very old

console.log(typeStr1, typeStr2, heightStr1, heightStr2)
Dog is a genius. 50 is tall. 50 is short

person.name = 'sunshine_lin'
person.age = 18
animal.type = 'the cat'
animal.height = 20

trigger(person, 'name')
trigger(person, 'age')
trigger(animal, 'type')
trigger(animal, 'height')

console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// Sunshine_lin is a rookie sunshine_lin is a genius 18 is old 18 is still young

console.log(typeStr1, typeStr2, heightStr1, heightStr2)
// The cat is a rookie. The cat is a genius. 20 is tall
Copy the code

Proxy

Through the above study, we have been able to achieve when data update, the dependent variable of followed him change, but there are still shortcomings, we can find that every time we always have to manually perform track function depend on the collection, and when the data changes, we have to manually perform the trigger function to update notification

So, is there a way to automatically collect dependencies and automatically notify updates? The answer is yes, Proxy can solve this problem for us. Reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive reactive

function reactive(target) {
    const handler = {
        get(target, key, receiver) {
            track(receiver, key) // Collect dependencies while accessing
            return Reflect.get(target, key, receiver)
        },
        set(target, key, value, receiver) {
            Reflect.set(target, key, value, receiver)
            trigger(receiver, key) // Automatically notifies updates when setting the value}}return new Proxy(target, handler)
}
Copy the code

Then change the previous code, remove the manual track and manual trigger, and find that the previous effect can also be achieved

const person = reactive({ name: 'Lin Three Hearts'.age: 22 }) / / to reactive
const animal = reactive({ type: 'dog'.height: 50 }) / / to reactive

effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()
effectTypeStr1()
effectTypeStr2()
effectHeightStr1()
effectHeightStr2()

console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// Lin Sanxin is a rookie. Lin Sanxin is a genius. Twenty-two is very old

console.log(typeStr1, typeStr2, heightStr1, heightStr2)
Dog is a genius. 50 is tall. 50 is short

person.name = 'sunshine_lin'
person.age = 18
animal.type = 'the cat'
animal.height = 20

console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// Sunshine_lin is a rookie sunshine_lin is a genius 18 is old 18 is still young

console.log(typeStr1, typeStr2, heightStr1, heightStr2)
// The cat is a rookie. The cat is a genius. 20 is tall
Copy the code

Maybe some students will be a little confused, a little confused about the above code, and maybe a little round, I thought I would explain the process to you through a diagram, the diagram may be compressed, I suggest to open a look

Solve write dead problem

There’s one place up there where we’re dead, if you remember, in the track function

function track(target, key) {
    let depsMap = targetMap.get(target)
    if(! depsMap) { targetMap.set(target, depsMap =new Map()}let dep = depsMap.get(key)
    if(! dep) { depsMap.set(key, dep =new Set()}// For now, I'm going to write it dead
    if (target === person) {
        if (key === 'name') {
            dep.add(effectNameStr1)
            dep.add(effectNameStr2)
        } else {
            dep.add(effectAgeStr1)
            dep.add(effectAgeStr2)
        }
    } else if (target === animal) {
        if (key === 'type') {
            dep.add(effectTypeStr1)
            dep.add(effectTypeStr2)
        } else {
            dep.add(effectHeightStr1)
            dep.add(effectHeightStr2)
        }
    }
}
Copy the code

In the real world, there will be more than two objects, and if you add an else if for every additional object, you can’t do that. So how do we solve this problem? The authors of Vue3 have come up with a clever way to solve this problem, using a global variable activeEffect. In fact, it is very simple, each effect function executes, put itself into the corresponding DEP, this can not need to write dead.

How can we implement this feature? We need to modify the effect function and the track function

let activeEffect = null
function effect(fn) {
    activeEffect = fn
    activeEffect()
    activeEffect = null // Change to null immediately after execution
}
function track(target, key) {
    // If activeEffect is null, the following is not executed
    // This is to avoid track being triggered by things like console.log(person.name)
    if(! activeEffect)return
    let depsMap = targetMap.get(target)
    if(! depsMap) { targetMap.set(target, depsMap =new Map()}let dep = depsMap.get(key)
    if(! dep) { depsMap.set(key, dep =new Set())
    }
    dep.add(activeEffect) // Add the activeEffect
}

// Each effect function is executed this way
effect(effectNameStr1)
effect(effectNameStr2)
effect(effectAgeStr1)
effect(effectAgeStr2)
effect(effectTypeStr1)
effect(effectTypeStr2)
effect(effectHeightStr1)
effect(effectHeightStr2)
Copy the code

Realize the ref

This is how we use ref in Vue3

let num = ref(5)

console.log(num.value) / / 5
Copy the code

Num then becomes a reactive data, and num. Value is written this way to use num

It’s very easy to implement a REF, because we’ve already implemented Reactive, so you just need to do this

function ref (initValue) {
    return reactive({
        value: initValue
    })
}
Copy the code

Let’s try it out. How does it look

let num = ref(5)

effect(() = > sum = num.value * 100)

console.log(sum) / / 500

num.value = 10

console.log(sum) / / 1000
Copy the code

To realize the computed

So let’s do computed, which is really easy, by the way

function computed(fn) {
    const result = ref()
    effect(() = > result.value = fn()) // Executes a computed passed function
    return result
}
Copy the code

Let’s look at the results

let num1 = ref(5)
let num2 = ref(8)
let sum1 = computed(() = > num1.value * num2.value)
let sum2 = computed(() = > sum1.value * 10)

console.log(sum1.value) / / 40
console.log(sum2.value) / / 400

num1.value = 10

console.log(sum1.value) / / 80
console.log(sum2.value) / / 800

num2.value = 16

console.log(sum1.value) / / 160
console.log(sum2.value) / / 1600
Copy the code

Since then we have implemented all the functions of this article

The final code

const targetMap = new WeakMap(a)function track(target, key) {
    // If activeEffect is null, the following is not executed
    // This is to avoid track being triggered by things like console.log(person.name)
    if(! activeEffect)return
    let depsMap = targetMap.get(target)
    if(! depsMap) { targetMap.set(target, depsMap =new Map()}let dep = depsMap.get(key)
    if(! dep) { depsMap.set(key, dep =new Set())
    }
    dep.add(activeEffect) // Add the activeEffect
}
function trigger(target, key) {
    let depsMap = targetMap.get(target)
    if (depsMap) {
        const dep = depsMap.get(key)
        if (dep) {
            dep.forEach(effect= > effect())
        }
    }
}
function reactive(target) {
    const handler = {
        get(target, key, receiver) {
            track(receiver, key) // Collect dependencies while accessing
            return Reflect.get(target, key, receiver)
        },
        set(target, key, value, receiver) {
            Reflect.set(target, key, value, receiver)
            trigger(receiver, key) // Automatically notifies updates when setting the value}}return new Proxy(target, handler)
}
let activeEffect = null
function effect(fn) {
    activeEffect = fn
    activeEffect()
    activeEffect = null
}
function ref(initValue) {
    return reactive({
        value: initValue
    })
}
function computed(fn) {
    const result = ref()
    effect(() = > result.value = fn())
    return result
}
Copy the code

The Proxy and Reflect

Proxy

const person = { name: 'Lin Three Hearts'.age: 22 }

const proxyPerson = new Proxy(person, {
    get(target, key, receiver) {
        console.log(target) // The original person
        console.log(key) / / the property name
        console.log(receiver) // proxyPerson after proxy
    },
    set(target, key, value, receiver) {
        console.log(target) // The original person
        console.log(key) / / the property name
        console.log(value) // Set the value
        console.log(receiver) // proxyPerson after proxy
    }
})

proxyPerson.name // Access attributes trigger get methods

proxyPerson.name = 'sunshine_lin' // Set the property value to trigger the set method
Copy the code

Reflect

Here are two methods for Reflecting

  • get(target, key, receiver): Personal understanding is, visittargetthekeyProperty, butthisIs pointing toreceiver, so the value actually accessed isThe receiver of the keyBut this is not direct accessreceiver[key]Properties, you have to distinguish between them
  • set(target, key, value, receiver): Personal understanding is, settingtargetthekeyProperties forvalue, butthisIs pointing toreceiver“, so it’s actually settingThe receiver of the keyThe value ofvalueBut this is not directreceiver[key] = valueYou have to differentiate

Receiver [key] = value; receiver[key] = value; reflect. get; reflect. set Let’s take a counter example

const person = { name: 'Lin Three Hearts'.age: 22 }

const proxyPerson = new Proxy(person, {
    get(target, key, receiver) {
        return Reflect.get(receiver, key) // Equivalent to receiver[key]
    },
    set(target, key, value, receiver) {
        Reflect.set(receiver, key, value) // Equivalent to receiver[key] = value}})console.log(proxyPerson.name)

proxyPerson.name = 'sunshine_lin' 
// The stack memory exceeds the Maximum call stack size exceeded
Copy the code

Why is that? Take a look at the solution below

Now you can see why you cannot directly receiver[key] or receiver[key] = value, because doing so will cause an infinite loop and eventually an error. So the right thing to do is

const person = { name: 'Lin Three Hearts'.age: 22 }

const proxyPerson = new Proxy(person, {
    get(target, key, receiver) {
        return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
        Reflect.set(target, key, value, receiver)
    }
})

console.log(proxyPerson.name) / / Lin three hearts

proxyPerson.name = 'sunshine_lin'

console.log(proxyPerson.name) // sunshine_lin
Copy the code

I’m sure some of you are going to ask, you can write it this way, why not? Let me put it down here

const proxyPerson = new Proxy(person, {
    get(target, key, receiver) {
        return Reflect.get(target, key)
    },
    set(target, key, value, receiver) {
        Reflect.get(target, key, value)
    }
})
Copy the code

Why do we use them together

It’s also possible to Reflect without Proxy. We could write it this way, and still get what we want

const person = { name: 'Lin Three Hearts'.age: 22 }

const proxyPerson = new Proxy(person, {
    get(target, key, receiver) {
        return target[key]
    },
    set(target, key, value, receiver) {
        target[key] = value
    }
})

console.log(proxyPerson.name) / / Lin three hearts

proxyPerson.name = 'sunshine_lin'

console.log(proxyPerson.name) // sunshine_lin
Copy the code

So why is Proxy and Reflect recommended? Because the Proxy and Reflect methods are one-to-one, using Reflect in a Proxy improves semantics

  • The Proxy of the getThe correspondingReflect.get
  • The Proxy of the setThe correspondingReflect.set
  • There are a lot of other ways that I’m not going to list, but they’re all one to one

Another reason is to try to put this on the receiver rather than the target

Why try to put this on the proxy object receiver instead of the original object Target? The target object may also be a proxy object of another proxy, so if this is always placed on target, the probability of a bug will be greatly increased.

const proxyPerson = new Proxy(person, {
    get(target, key, receiver) {
        return Reflect.get(target, key)
    },
    set(target, key, value, receiver) {
        Reflect.get(target, key, value)
    }
})
Copy the code

conclusion

If you think this article is a little bit helpful to you, click a like and encourage Lin Sanxin haha.

To enter the learning group, touch fish, please click here to touch fish