Proxy 实践
遍历 Proxy 实例上的属性/属性值的方法
const origin = {
a: 1,
b: 2
};
const proxy = new Proxy(origin, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
console.log('get', key, result);
return result;
},
set(target, key, value, receiver) {
console.log('set', key, value);
return Reflect.set(target, key, value, receiver);
},
ownKeys(target) {
const result = Reflect.ownKeys(target);
console.log('ownKeys', result);
return result;
}
});
Object.keys(proxy);
// ownKeys [ 'a', 'b' ]
Object.values(proxy);
// ownKeys [ 'a', 'b' ]
// get a 1
// get b 2
Object.entries(proxy);
// ownKeys [ 'a', 'b' ]
// get a 1
// get b 2
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
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
Proxy 实例上的数组方法
当为数组创建代理时,调用代理上的数组方法时,可能会触发数组下标、length
等属性的set
和get
。
(TODO: 这里会触发的原因应该是 C++ 源码里在实现这些方法时会访问/设置这些属性)
const origin = ['a', 'b'];
const proxy = new Proxy(origin, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
console.log('get', key, result);
return result;
},
set(target, key, value, receiver) {
console.log('set', key, value);
return Reflect.set(target, key, value, receiver);
},
deleteProperty(target, key) {
console.log('delete', key);
return Reflect.deleteProperty(target, key);
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
push
proxy.push('c');
// 结果
// get push function push() { [native code] }
// get length 2
// set 2 c
// set length 3
1
2
3
4
5
6
7
2
3
4
5
6
7
pop
proxy.pop();
// 结果
// get pop function pop() { [native code] }
// get length 2
// get 1 b
// delete 1
// set length 1
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
shift
proxy.shift();
// 结果
// get shift function shift() { [native code] }
// get length 2
// get 0 a
// get 1 b
// set 0 b
// delete 1
// set length 1
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
unshift
proxy.unshift('c');
// 结果
// get unshift function unshift() { [native code] }
// get length 2
// get 1 b
// set 2 b
// get 0 a
// set 1 a
// set 0 c
// set length 3
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
splice
proxy.splice(0, 1);
// 结果
// get splice function splice() { [native code] }
// get length 2
// get constructor function Array() { [native code] }
// get 0 a
// get 1 b
// set 0 b
// delete 1
// set length 1
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
proxy.splice(0, 1, 'c', 'd');
// 结果
// get splice function splice() { [native code] }
// get length 2
// get constructor function Array() { [native code] }
// get 0 a
// get 1 b
// set 2 b
// set 0 c
// set 1 d
// set length 3
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
includes/indexOf/lastIndexOf
const origin = ['a', 'b'];
const proxy = new Proxy(origin, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
console.log('get', key, result);
return result;
},
});
proxy.includes('a')
// 结果
// get includes function includes() { [native code] }
// get length 2
// get 0 a
proxy.includes('c')
// 结果
// get includes function includes() { [native code] }
// get length 2
// get 0 a
// get 1 b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
indexOf
和lastIndexOf
同理,不再赘述。
需要注意的是,调用数组的这三个方法,并不能保证会get
数组的每一项,若在某一项匹配到,则后续项将不会再get
。
map
forEach
for of
Proxy 的 ownKeys() 方法
Proxy 的ownKeys()
可以拦截:
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
for...in
循环
但是这些被拦截的不同的遍历方式在handler.ownKeys
里统一使用Reflect.ownKeys()
获取的值还是对应遍历方法原本的结果,这一点比较神奇。
const origin = {
[Symbol('')]: '',
a: 'a'
}
Object.defineProperty(origin, 'b', {
value: 'b',
enumerable: false
})
const handler = {
ownKeys(target) {
return Reflect.ownKeys(target);
}
}
const proxy = new Proxy(origin, handler)
Reflect.ownKeys(proxy) // [ 'a', 'b', Symbol() ]
Object.getOwnPropertyNames(proxy) // [ 'a', 'b' ]
Object.getOwnPropertySymbols(proxy) // [ Symbol() ]
Object.keys(proxy) // [ 'a' ]
for(let i in proxy) {
console.log(i) // a
}
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
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