响应式原理
# 响应式原理
# vue2.x的响应式
实现原理:
对象类型:通过
Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)。数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
Object.defineProperty(data, 'count', { get () {}, set () {} })
1
2
3
4
存在问题:
新增属性、删除属性, 界面不会更新。
直接通过下标修改数组, 界面不会自动更新。
// 新增 methods:{ addSex(){ this.$set(this.person,'sex','女') // 或者 引入 import Vue from 'vue' // Vue.set(this.person,'sex','女') } } // 删除 deleteName(){ this.$delete(this.person,'name') } // 修改数组 updateHobby(){ this.$set(this.person.hobby,0,'逛街') // 或者 this.person.hobby.splice(0,1,'逛街') }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Vue3.0的响应式
在目标对象架设一层“拦截”,当外界对该对象进行访问时,需要经过这层拦截,而Proxy充当这种机制,类似于“代理”的意思,可以在外界访问该对象前进行过滤和修改
实现原理:
通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
通过Reflect(反射): 对源对象的属性进行操作。
MDN文档中描述的Proxy与Reflect:
Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
new Proxy(data, { // 拦截读取属性值 get (target, prop) { return Reflect.get(target, prop) }, // 拦截设置属性值或添加新属性 set (target, prop, value) { return Reflect.set(target, prop, value) }, // 拦截删除属性 deleteProperty (target, prop) { return Reflect.deleteProperty(target, prop) } }) proxy.name = 'tom'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 举例
// 源数据
let person = {
name: '张三',
age: 18
}
// 模拟Vue2中实现响应式
let p = {}
Object.defineProperty(p, 'name', {
configurable:true,
// 有人读取name调用
get() {
return person.name
},
//
set(value) {
person.name = value
}
})
// 模拟Vue3中实现响应式
const p = new Proxy(person, {
// 有人读取p的某个属性时调用
get(target, propName) {
console.log(`有人读取了p身上的${propName}某个属性`)
return Reflect.get(target, propName)
},
// 有人修改p某个属性或者追加某个属性时调用
set(target, propName, value) {
console.log(`有人修改了p身上的${propName}某个属性`)
return Reflect.set(target, propName, value)
},
// 有人删除p的某个属性时调用
defineProperty(target, propName) {
console.log(`有人删除了p身上的${propName}某个属性`)
return Reflect.deleteProperty(target, propName)
}
})
let obj = {a: 1, b: 2}
// 通过Object.defineProperty去操作
try {
Object.defineProperty(obj, 'c', {
get() {
return 3
}
})
Object.defineProperty(obj, c, {
get() {
return 4
}
})
} catch (err) {
console.log(err)
}
// 通过Reflect.defineProperty去操作
const x1 = Reflect.defineProperty(obj, 'c', {
get() {
return 3
}
})
const x2 = Reflect.defineProperty(obj, 'c', {
get() {
return 4
}
})
console.log(x2)
if (x2) {
console.log('成功')
} else {
console.log('失败')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
上次更新: 2024/08/14, 04:14:33