Preface
Hello everyone, I’m Lin Sanxin, and everyone knows that this rookie usually writes a lot of basic articles, and I always believe in two sentences.
- Use the most easy-to-understand words to talk about the most difficult knowledge points
- foundation is the premise of advanced
In fact, Vue3 has been out for a long time, and it may be used by most companies. However, how is Vue3 better than Vue2? In fact, many people don't know. Today I will firstyou about the responsive principle of
Vue3. By the way, how is the responsiveness of 161d64d2af2075 Vue3 better than that of Vue2.
What's the good thing?
Okay, let's first talk about why Vue3 is better than that of Vue2. Maybe I usually ask you: do you know how Vue's responsiveness is implemented? Everyone can roughly answer
- The responsive style of
Object.defineProperty
- The responsive style of
Proxy
is implemented based on ES6's 061d64d2af2131
Yes, although the answer above is a bit abstract, it does answer the core principles of the responsiveness of the two versions of Vue, and the responsiveness of the two versions of Vue is indeed reflected in Object.defineProperty
and Proxy
The difference.
Vue2
Everyone knows that the response of Object.defineProperty
is based on 061d64d2af21c1, then I will take Object.defineProperty
as an example
// 响应式函数
function reactive(obj, key, value) {
Object.defineProperty(data, key, {
get() {
console.log(`访问了${key}属性`)
return value
},
set(val) {
console.log(`将${key}由->${value}->设置成->${val}`)
if (value !== val) {
value = val
}
}
})
}
const data = {
name: '林三心',
age: 22
}
Object.keys(data).forEach(key => reactive(data, key, data[key]))
console.log(data.name)
// 访问了name属性
// 林三心
data.name = 'sunshine_lin' // 将name由->林三心->设置成->sunshine_lin
console.log(data.name)
// 访问了name属性
// sunshine_lin
Through the above example, I think everyone has Object.defineProperty
, then the problem is coming? What are the disadvantages of it? This makes it especially abandoned in Vue3, let's continue to look at:
// 接着上面代码
data.hobby = '打篮球'
console.log(data.hobby) // 打篮球
data.hobby = '打游戏'
console.log(data.hobby) // 打游戏
Now everyone can see what is wrong with Object.defineProperty
As we can see, data has added the hobby
attribute for access and setting, but it will not trigger get and set, so the drawback is:
Object.defineProperty
only monitors the attributes in the initial object, but for the new attributes invalid. This is why the modification of the new properties of the object in Vue2 needs to use Vue.$set
to set the value.
Vue3
From the above, we know the Object.defineProperty
Proxy
is the core of the responsive principle in Vue3, compensates for this defect. As usual, let’s take an example (first roughly, the specific parameters will be discussed in detail below):
const data = {
name: '林三心',
age: 22
}
function reactive(target) {
const handler = {
get(target, key, receiver) {
console.log(`访问了${key}属性`)
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
console.log(`将${key}由->${target[key]}->设置成->${value}`)
Reflect.set(target, key, value, receiver)
}
}
return new Proxy(target, handler)
}
const proxyData = reactive(data)
console.log(proxyData.name)
// 访问了name属性
// 林三心
proxyData.name = 'sunshine_lin'
// 将name由->林三心->设置成->sunshine_lin
console.log(proxyData.name)
// 访问了name属性
// sunshine_lin
As you can see, the effect is actually the same as the above Object.defineProperty
, so why do you want to abandon it and choose Proxy
? Attention, the most important thing is to add new properties to the object, let's see the effect:
proxyData.hobby = '打篮球'
console.log(proxyData.hobby)
// 访问了hobby属性
// 打篮球
proxyData.hobby = '打游戏'
// 将hobby由->打篮球->设置成->打游戏
console.log(proxyData.hobby)
// 访问了hobby属性
// 打游戏
So now everyone knows how responsive Vue3 is better than Vue2, right?
Vue3 responsive principle
After talking Proxy
the benefits of 061d64d2af239e, let's formally talk about the core part of Vue3's responsive principle.
Preface
First look at the following code
let name = '林三心', age = 22, money = 20
let myself = `${name}今年${age}岁,存款${money}元`
console.log(myself) // 林三心今年22岁,存款20元
money = 300
// 预期:林三心今年22岁,存款300元
console.log(myself) // 实际:林三心今年22岁,存款20元
Think about it, everyone. I want myself
follow money
. What should I do? Hey, in fact, as long as myself ='${name} is ${age} years old this year, deposit ${money}元', just execute it again, as follows
let name = '林三心', age = 22, money = 20
let myself = `${name}今年${age}岁,存款${money}元`
console.log(myself) // 林三心今年22岁,存款20元
money = 300
myself = `${name}今年${age}岁,存款${money}元` // 再执行一次
// 预期:林三心今年22岁,存款300元
console.log(myself) // 实际:林三心今年22岁,存款300元
effect
As mentioned above, every time money
changed, 161d64d2af2506 has to be executed again. myself ='${name} is ${age} years old this year, deposit ${money} yuan', in order to
myself
, in fact, this is not elegant, we can encapsulate A effect function
let name = '林三心', age = 22, money = 20
let myself = ''
const effect = () => myself = `${name}今年${age}岁,存款${money}元`
effect() // 先执行一次
console.log(myself) // 林三心今年22岁,存款20元
money = 300
effect() // 再执行一次
console.log(myself) // 林三心今年22岁,存款300元
In fact, this is also harmful. If you don’t believe me, you can take a look at the following situation
let name = '林三心', age = 22, money = 20
let myself = '', ohtherMyself = ''
const effect1 = () => myself = `${name}今年${age}岁,存款${money}元`
const effect2 = () => ohtherMyself = `${age}岁的${name}居然有${money}元`
effect1() // 先执行一次
effect2() // 先执行一次
console.log(myself) // 林三心今年22岁,存款20元
console.log(ohtherMyself) // 22岁的林三心居然有20元
money = 300
effect1() // 再执行一次
effect2() // 再执行一次
console.log(myself) // 林三心今年22岁,存款300元
console.log(ohtherMyself) // 22岁的林三心居然有300元
If you add a ohtherMyself
, you have to write another effect
, and then execute it every time you update. If the number of additions increases, wouldn't it be necessary to write a lot of effect function execution code every time?
track and trigger
In view of the above problem, we can solve it like this: use the track function to collect all the
effect functions that depend on the
money variable
dep
in dep
Why does Set
use 061d64d2af25f4? Because Set
can automatically remove duplicates. After the collection, whenever the money variable changes in the
trigger function to notify all the
effect functions in
dep
that depend on the money variable to execute to implement the update of the dependent variable. Let's take a look at the code first, and then I will show you through a picture, I am afraid that everyone is dizzy haha.
let name = '林三心', age = 22, money = 20
let myself = '', ohtherMyself = ''
const effect1 = () => myself = `${name}今年${age}岁,存款${money}元`
const effect2 = () => ohtherMyself = `${age}岁的${name}居然有${money}元`
const dep = new Set()
function track () {
dep.add(effect1)
dep.add(effect2)
}
function trigger() {
dep.forEach(effect => effect())
}
track() //收集依赖
effect1() // 先执行一次
effect2() // 先执行一次
console.log(myself) // 林三心今年22岁,存款20元
console.log(ohtherMyself) // 22岁的林三心居然有20元
money = 300
trigger() // 通知变量myself和otherMyself进行更新
console.log(myself) // 林三心今年22岁,存款300元
console.log(ohtherMyself) // 22岁的林三心居然有300元
What about the object?
The above are all about basic data types. Let’s talk about the object. Let me give an example first, and use the most primitive way to achieve his response.
const person = { name: '林三心', age: 22 }
let nameStr1 = ''
let nameStr2 = ''
let ageStr1 = ''
let ageStr2 = ''
const effectNameStr1 = () => { nameStr1 = `${person.name}是个大菜鸟` }
const effectNameStr2 = () => { nameStr2 = `${person.name}是个小天才` }
const effectAgeStr1 = () => { ageStr1 = `${person.age}岁已经算很老了` }
const effectAgeStr2 = () => { ageStr2 = `${person.age}岁还算很年轻啊` }
effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// 林三心是个大菜鸟 林三心是个小天才 22岁已经算很老了 22岁还算很年轻啊
person.name = 'sunshine_lin'
person.age = 18
effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// sunshine_lin是个大菜鸟 sunshine_lin是个小天才 18岁已经算很老了 18岁还算很年轻啊
We have also seen the above code, and feel that it is very brainless. . Remember the dep
collection effect
? Let's take the name and age in the person object as two variables for the time being, they all have their own dependent variables
- name: nameStr1 and nameStr2
- age: ageStr1 and ageStr2
Soname and age should have their own
dep
effect
corresponding to each dependent variable
dep
earlier, 061d64d2af2827 uses Set
. Since the person has two attributes of age and name, it has two deps
. So what should be used to store these two deps? We can use another ES6 data structure
Map
to store
const person = { name: '林三心', age: 22 }
let nameStr1 = ''
let nameStr2 = ''
let ageStr1 = ''
let ageStr2 = ''
const effectNameStr1 = () => { nameStr1 = `${person.name}是个大菜鸟` }
const effectNameStr2 = () => { nameStr2 = `${person.name}是个小天才` }
const effectAgeStr1 = () => { ageStr1 = `${person.age}岁已经算很老了` }
const effectAgeStr2 = () => { ageStr2 = `${person.age}岁还算很年轻啊` }
const depsMap = new Map()
function track(key) {
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, dep = new Set())
}
// 这里先暂且写死
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') // 收集person.name的依赖
track('age') // 收集person.age的依赖
effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// 林三心是个大菜鸟 林三心是个小天才 22岁已经算很老了 22岁还算很年轻啊
person.name = 'sunshine_lin'
person.age = 18
trigger('name') // 通知person.name的依赖变量更新
trigger('age') // 通知person.age的依赖变量更新
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// sunshine_lin是个大菜鸟 sunshine_lin是个小天才 18岁已经算很老了 18岁还算很年轻啊
Above we have only one person object, what if there are multiple objects? what to do? We all know that each object will create a Map
dep of the attributes in the object (using Set to store). If there are multiple objects, what should be used to store the
Map
corresponding to each object? Please see the picture below
In fact, ES6 also has a new data structure called WeakMap
. Let's use it to store the Map
these objects. So we have to modify the track function and the
trigger function, let’s see what they look like before.
const depsMap = new Map()
function track(key) {
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, dep = new Set())
}
// 这里先暂且写死
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())
}
}
The previous code only did a single object processing solution, but now if you want multiple objects, you have to use WeakMap
for transformation (the code may be a bit verbose, but it will all take care of students with weak foundations)
const person = { name: '林三心', age: 22 }
const animal = { type: 'dog', height: 50 }
const targetMap = new WeakMap()
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())
}
// 这里先暂且写死
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())
}
}
}
After the above transformation, we finally realized the multi-object dependency collection, let's give it a try
const person = { name: '林三心', 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}是个大菜鸟` }
const effectNameStr2 = () => { nameStr2 = `${person.name}是个小天才` }
const effectAgeStr1 = () => { ageStr1 = `${person.age}岁已经算很老了` }
const effectAgeStr2 = () => { ageStr2 = `${person.age}岁还算很年轻啊` }
const effectTypeStr1 = () => { typeStr1 = `${animal.type}是个大菜鸟` }
const effectTypeStr2 = () => { typeStr2 = `${animal.type}是个小天才` }
const effectHeightStr1 = () => { heightStr1 = `${animal.height}已经算很高了` }
const effectHeightStr2 = () => { heightStr2 = `${animal.height}还算很矮啊` }
track(person, 'name') // 收集person.name的依赖
track(person, 'age') // 收集person.age的依赖
track(animal, 'type') // animal.type的依赖
track(animal, 'height') // 收集animal.height的依赖
effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()
effectTypeStr1()
effectTypeStr2()
effectHeightStr1()
effectHeightStr2()
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// 林三心是个大菜鸟 林三心是个小天才 22岁已经算很老了 22岁还算很年轻啊
console.log(typeStr1, typeStr2, heightStr1, heightStr2)
// dog是个大菜鸟 dog是个小天才 50已经算很高了 50还算很矮啊
person.name = 'sunshine_lin'
person.age = 18
animal.type = '猫'
animal.height = 20
trigger(person, 'name')
trigger(person, 'age')
trigger(animal, 'type')
trigger(animal, 'height')
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// sunshine_lin是个大菜鸟 sunshine_lin是个小天才 18岁已经算很老了 18岁还算很年轻啊
console.log(typeStr1, typeStr2, heightStr1, heightStr2)
// 猫是个大菜鸟 猫是个小天才 20已经算很高了 20还算很矮啊
Proxy
Through the above learning, we can realize that when the data is updated, his dependent variables are also changed, but there are still shortcomings. You can find that each time we always have to manually execute the track function to perform dependent collection, and When the data changes, we have to manually execute the
trigger function to update the notification
So, is there a way to achieve automatic collection of dependencies and automatic notification of updates? The answer is yes, Proxy
can solve this problem for us. Let’s first write a reactive function. Let’s take a look and understand
Proxy-track-trigger
. Later I will talk about why Proxy
needs to be matched with Reflect
function reactive(target) {
const handler = {
get(target, key, receiver) {
track(receiver, key) // 访问时收集依赖
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver)
trigger(receiver, key) // 设值时自动通知更新
}
}
return new Proxy(target, handler)
}
Then change the previous code, remove manual track and
manual trigger, and found that the previous effect can also be achieved
const person = reactive({ name: '林三心', age: 22 }) // 传入reactive
const animal = reactive({ type: 'dog', height: 50 }) // 传入reactive
effectNameStr1()
effectNameStr2()
effectAgeStr1()
effectAgeStr2()
effectTypeStr1()
effectTypeStr2()
effectHeightStr1()
effectHeightStr2()
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// 林三心是个大菜鸟 林三心是个小天才 22岁已经算很老了 22岁还算很年轻啊
console.log(typeStr1, typeStr2, heightStr1, heightStr2)
// dog是个大菜鸟 dog是个小天才 50已经算很高了 50还算很矮啊
person.name = 'sunshine_lin'
person.age = 18
animal.type = '猫'
animal.height = 20
console.log(nameStr1, nameStr2, ageStr1, ageStr2)
// sunshine_lin是个大菜鸟 sunshine_lin是个小天才 18岁已经算很老了 18岁还算很年轻啊
console.log(typeStr1, typeStr2, heightStr1, heightStr2)
// 猫是个大菜鸟 猫是个小天才 20已经算很高了 20还算很矮啊
Some students may be a little bit confused, a little confused about the above code, or a little bit circumstantial, I thought that through a picture to explain the process to everyone, the picture may be compressed, it is recommended to open it and have a look
Solve the hard-coded problem
, do you still remember, it is in the track function 161d64d2af2a7a
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())
}
// 这里先暂且写死
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)
}
}
}
In actual development, there must be more than two objects. If you add an additional object, you must add another else if
judgment, which is absolutely impossible. So how do we solve this problem? In fact, it is not difficult to say. The authors of Vue3 came up with a very clever way, using a global variable activeEffect
to cleverly solve this problem. How to solve it? In fact, it is very simple, that is, as as each 161d64d2af2ada effect function is executed, it puts itself in the corresponding 061d64d2af2ad6, which eliminates the need
dep
How can we achieve this function? We need to modify the effect function, and modify the
track function
let activeEffect = null
function effect(fn) {
activeEffect = fn
activeEffect()
activeEffect = null // 执行后立马变成null
}
function track(target, key) {
// 如果此时activeEffect为null则不执行下面
// 这里判断是为了避免例如console.log(person.name)而触发track
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) // 把此时的activeEffect添加进去
}
// 每个effect函数改成这么执行
effect(effectNameStr1)
effect(effectNameStr2)
effect(effectAgeStr1)
effect(effectAgeStr2)
effect(effectTypeStr1)
effect(effectTypeStr2)
effect(effectHeightStr1)
effect(effectHeightStr2)
Implement ref
This is how we use ref
let num = ref(5)
console.log(num.value) // 5
Then num
will become a responsive data, and num
, you need to write num.value
to use it.
Realizing ref is actually very simple. We have already implemented reactive
above, and we only need to do this to achieve ref
function ref (initValue) {
return reactive({
value: initValue
})
}
Let's try it out
let num = ref(5)
effect(() => sum = num.value * 100)
console.log(sum) // 500
num.value = 10
console.log(sum) // 1000
Achieve computed
Let's simply implement computed
way, it's actually very simple
function computed(fn) {
const result = ref()
effect(() => result.value = fn()) // 执行computed传入函数
return result
}
Let's see the result
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
Since then we have implemented all the functions of this article
Final code
const targetMap = new WeakMap()
function track(target, key) {
// 如果此时activeEffect为null则不执行下面
// 这里判断是为了避免例如console.log(person.name)而触发track
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) // 把此时的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) // 访问时收集依赖
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver)
trigger(receiver, key) // 设值时自动通知更新
}
}
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
}
Proxy and Reflect
Proxy
const person = { name: '林三心', age: 22 }
const proxyPerson = new Proxy(person, {
get(target, key, receiver) {
console.log(target) // 原来的person
console.log(key) // 属性名
console.log(receiver) // 代理后的proxyPerson
},
set(target, key, value, receiver) {
console.log(target) // 原来的person
console.log(key) // 属性名
console.log(value) // 设置的值
console.log(receiver) // 代理后的proxyPerson
}
})
proxyPerson.name // 访问属性触发get方法
proxyPerson.name = 'sunshine_lin' // 设置属性值触发set方法
Reflect
Here are two methods of Reflect
get(target, key, receiver)
: Personal understanding is that accesstarget
ofkey
property, butthis
pointingreceiver
, so the actual value is accessed isvalue of the receiver of the key, but this is not directly accessible
receiver[key]
property, you have to distinguish betweenset(target, key, value, receiver)
: Personal understanding is settarget
ofkey
propertyvalue
, butthis
pointingreceiver
, it actually is to setReceiver of the key value
value
, but it is not directlyreceiver[key] = value
, we have to distinguish between
We emphasized above that you cannot directly receiver[key]
or receiver[key] = value
, but use and Reflect.set to access or set properties around a corner. Why is this? Let's take a counter example below
const person = { name: '林三心', age: 22 }
const proxyPerson = new Proxy(person, {
get(target, key, receiver) {
return Reflect.get(receiver, key) // 相当于 receiver[key]
},
set(target, key, value, receiver) {
Reflect.set(receiver, key, value) // 相当于 receiver[key] = value
}
})
console.log(proxyPerson.name)
proxyPerson.name = 'sunshine_lin'
// 会直接报错,栈内存溢出 Maximum call stack size exceeded
Why is this so? Look at the solution below
Now you know why you can't directly receiver[key]
or receiver[key] = value
, because doing this directly will cause an infinite loop, and eventually an error will be reported. So the correct way is
const person = { name: '林三心', 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) // 林三心
proxyPerson.name = 'sunshine_lin'
console.log(proxyPerson.name) // sunshine_lin
Some students are sure to ask, the following is fine, why not suggest it? I put it down and say it together
const proxyPerson = new Proxy(person, {
get(target, key, receiver) {
return Reflect.get(target, key)
},
set(target, key, value, receiver) {
Reflect.get(target, key, value)
}
})
Why use it together
In fact, it is possible to use Proxy without Reflect. We can write like this and still achieve the desired effect
const person = { name: '林三心', 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) // 林三心
proxyPerson.name = 'sunshine_lin'
console.log(proxyPerson.name) // sunshine_lin
So why is it recommended to use Proxy and Reflect together? Because
Proxy and methods Reflect is one to one, in
Proxy
use in Reflect
will improve semantic
- The get of
Proxy corresponds to
Reflect.get
Proxy set corresponds to
Reflect.set
- There are many other methods I won’t list them one by one, they all correspond one by one
Another reason is, try to put this on receiver
instead of target
Why put this on the proxy object receiver
as much as possible, instead of putting it on the original object target
? Because the original object target
may have been a proxy object of another proxy, if this is kept on target
, the probability of bugs will be greatly increased. So why is the previous code not recommended? You should know?
const proxyPerson = new Proxy(person, {
get(target, key, receiver) {
return Reflect.get(target, key)
},
set(target, key, value, receiver) {
Reflect.set(target, key, value)
}
})
Concluding remarks
I am Lin Sanxin, an enthusiastic front-end rookie programmer. If you are motivated, like the front-end, and want to learn the front-end, then we can make friends, fish together haha, fish school, add me, please note [think]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。