const p = new Proxy(target, {
get: function (target, property, receiver) {},
});
获取一个数组上的不存在项时,会返回undefined,可以利用代理,使得访问不存在的项返回0
let arr = [1, 2, 3];
arr = new Proxy(arr, {
get(target, p) {
if (p in target) {
return target[p];
}
return 0;
},
});
console.log(arr[1]);
console.log(arr[10]);
总结:借助get钩子可以在读取一个对象上不存在的属性时,得到一个默认值
set 钩子
const p = new Proxy(target, {
set: function (target, property, value, receiver) {},
});
注意:如果写入成功则返回true,否则返回false(触发TypeError)
创建一个只能写入数字的数组
let arr = [];
arr = new Proxy(arr, {
set(target, p, value) {
// 拦截写入操作
if (typeof value == 'number') {
target[p] = value;
return true;
}
return false;
},
});
arr.push(1);
arr.push('2');
总结:借助set钩子可以对一个对象的属性和值进行验证
has 钩子
const p = new Proxy(target, {
has: function (target, prop) {},
});
检查数字是否在range范围内
let range = [1, 10];
range = new Proxy(range, {
has(target, p) {
return p >= target[0] && p <= target[1];
},
});
console.log(5 in range);
console.log(100 in range);
ownKeys 钩子
const p = new Proxy(target, {
ownKeys: function (target) {},
});
使用for...in或Object.keys()遍历对象,并过滤_开头的属性
let obj = {
name: 'jianwu',
age: 24,
_password: '123456',
};
obj = new Proxy(obj, {
ownKeys(target) {
return Object.keys(target).filter((key) => !key.startsWith('_'));
},
});
for (let key in obj) console.log(key);
console.log(Object.keys(obj));
console.log(Object.values(obj));
Proxy
Proxy
对象是用于包装另一个对象,并拦截其读/写等操作语法
target
: 要包装的目标对象(任何类型的对象,包括函数)handler
: 带有钩子函数的对象,用于处理代理对象的各种拦截操作,下面列出一些常用的操作方法:get
[[Get]]
set
[[Set]]
has
[[HasProperty]]
in
操作符deleteProperty
[[Delete]]
delete
操作符apply
[[Call]]
ownKeys
[[OwnPropertyKeys]]
Object.getOwnPropertyNames
Object.getOwnPropertySymbols
getOwnPropertyDescriptor
[[GetOwnProperty]]
Object.getOwnPropertyDescriptor
get 钩子
undefined
,可以利用代理,使得访问不存在的项返回0
总结:借助
get
钩子可以在读取一个对象上不存在的属性时,得到一个默认值set 钩子
注意:如果写入成功则返回
true
,否则返回false
(触发TypeError
)总结:借助
set
钩子可以对一个对象的属性和值进行验证has 钩子
range
范围内ownKeys 钩子
for...in
或Object.keys()
遍历对象,并过滤_
开头的属性注意:如果
ownKeys
钩子返回对象上不存在的属性,Object.getOwnPropertyNames
方法可以列出不存在的键;但Object.keys
不可以,因为Object.keys
方法只返回带有enumerable
标记的非Symbol
键,可以使用getOwnPropertyDescriptor
钩子将enumerable
标记改为true
,就可列出了。deleteProperty 钩子
_
开头的属性apply 钩子
delay(fn, ms)
方法,在ms
后执行fn
函数下面使用
Proxy
来包装上面的函数:总结:普通的包装函数不会转发读写等操作,所以无法访问到原始函数的属性,如
length
,name
等;而Proxy
则可以在代理对象上的所有操作转发到原始函数,从而实现一个更完整的包装器Reflect
Reflect
对象提供拦截JS
操作的方法,与Proxy handler
的方法相同,可以简化创建Proxy
内部方法仅在规范中使用,不能直接调用,
Reflect
的方法对内部方法进行包装,使得调用成为可能Reflect.get(target, propertyKey, receiver)
target[name]
[[Get]]
Reflect.set(target, propertyKey, value, receiver)
target[name] = value
[[Set]]
Reflect.has(target, propertyKey)
name in target
[[HasProperty]]
Reflect.deleteProperty(target, propertyKey)
delete target[name]
[[Delete]]
getter 代理
Proxy
的get
钩子返回代理对象原属性上面的栗子中,触发
get
钩子会从原对象返回target[p]
,此处属性是一个getter
访问器,this
指向原对象,所以返回user.name
。对于普通函数,可以使用
call/apply
来绑定正确的this
,但是getter
怎么绑定呢?Reflect.get
案例
负数索引访问数组
给定一个数组:
arr = [1, 2, 3]
,实现:arr[-1] = 3
,arr[-2] = 2
,arr[-3] = 1
实现简单的 Observable
创建一个
makeObservable(target)
函数,使得对象可观察