vue3-proxy
宁静致远 7/18/2020 vue3
Object.defineProperty的缺点
- 深度监听需要一次性递归
- 无法监听新增属性/删除属性(Vue.set Vue.delete)
- 无法原生监听数组,需要特殊处理
# Proxy实现响应式
- 深度监听、性能更好
- 可监听新增/删除属性
- 可监听数组变化
- Proxy 能规避Object.defineProperty的问题
- Proxy 无法兼容所有浏览器,无法监听 Polyfill
# Proxy 实现
/**
* 参数1 target: Proxy包装的目标对象 任何类型的对象
* 参数2 handler 各属性定义的函数执行操作
*
*/
// let data = {
// a: 1,
// b: 2,
// }
let data = [1,2,3,4]
const ProxyData = new Proxy(data, {
// 获取
/**
*
* @param {*} target 目标对象
* @param {*} property 被获取的属性名 理解为key
* @param {*} receiver Proxy 或者继承 Proxy 的对象
* return 可以返回任何值
*/
get(target, property, receiver) {
/**
* target 需要取值的目标对象
* property 需要获取的值的键值
* receiver 如果target对象中指定了getter,receiver则为getter调用时的this值。
* return 属性的值
*/
const result = Reflect.get(target, property, receiver)
console.log('get', result);
return result
},
// 设置
/**
*
* @param {*} target 目标对象
* @param {*} property 将被设置的属性名 理解为key
* @param {*} value 新属性值
* @param {*} receiver 被调用的对象
* return 会返回一个布尔值
*/
set(target, property, value, receiver) {
/**
* target 设置属性的目标对象
* property 设置的属性的名称
* value 设置的值
* receiver 如果遇到 setter,receiver则为setter调用时的this值。
* return 返回一个 Boolean 值表明是否成功设置属性。
*/
const result = Reflect.set(target, property, value, receiver)
console.log('set', property, value);
return result
},
// 删除
/**
*
* @param {*} target 目标对象
* @param {*} property 待删除的属性名
* return 必须返回一个布尔值,表示该属性是否被成功删除
*/
deleteProperty(target, property) {
/**
* target 删除属性的目标对象
* property 需要删除的属性的名称
* return Boolean 值表明该属性是否被成功删除。
*/
const result = Reflect.deleteProperty(target, property)
console.log('delete', property);
return result
}
})
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
# Proxy响应式实现
// 创建响应式
function reactive(target = {}) {
// 对象或数组, 不是对象或数组,返回
if (typeof target !== 'object' || target == null) {
return target
}
// 代理proxy配置
const proxyConfig = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
console.log('get', result);
// 深度监听,获取到的时候才执行,
// object.defienProperty 一次性执行
return reactive(result)
},
set(target, key, value, receiver) {
// 重复设置数据,不处理
if(value === target[key]){
return true // 默认设置成功
}
const ownkey = Reflect.ownKeys(target)
if(ownkey.includes(key)){
console.log('已存在', key);
}else{
console.log('新增', key);
}
const result = Reflect.set(target, key, value, receiver)
console.log('set', key, value);
return result // 是否设置成功
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('deleteProperty', key);
return result // 是否删除成功
}
}
// 返回代理对象
const observer = new Proxy(target, proxyConfig)
return observer
}
// 数据
// const data = {
// a: 1,
// b: 2,
// c: {
// d:{
// e:{
// f:{
// g:3
// }
// }
// }
// }
// }
let data = [1,2,3,4,5]
const proxyData = reactive(data)
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
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