一、Proxy
- 概述 Proxy取其英文意思即“代理”。
所谓代理,是你要取得某样东西或对其进行某些操作的中间媒介,而不是直接作用在这个对象上。
Proxy 对象就是这样的媒介,要操作这个对象的话,需要经过这个媒介的同意。
使用方式: let p = new Proxy(target,habdler); target:用 Proxy 包装的目标对象(可以是数组对象,函数,或者另一个代理);
handler:一个对象,拦截过滤代理操作的函数。
let xiaohong = {
name: "小红",
age: 15,
};
xiaohong = new Proxy(xiaohong, {
get(target, key) {
let result = target[key];
//如果是获取 年龄 属性,则添加 岁字
if (key === "age") result += "岁";
if (key === "name") result = "可爱的" + result;
return result;
},
set(target, key, newvalue) {
if (key === "age" && typeof newvalue !== "number") {
throw Error("age字段必须为Number类型");
}
return target[key] = newValue;
},
});
console.log(`我叫${xiaohong.name} 我今年${xiaohong.age}了`);
xiaohong.age = 22;
xiaohong.name = "zw";
console.log(`我叫${xiaohong.name} 我今年${xiaohong.age}了`);
执行结果
- 实例方法
除了上面代码中set 和 get 两个实例方法外,Proxy 对象实例方法如下表显示:
方法 | 描述 |
---|---|
handler.apply() | 拦截 Proxy 实例作为函数调用的操作 |
handler.construct() | 拦截 Proxy 实例作为函数调用的操作 |
handler.defineProperty() | 拦截 Object.defineProperty() 的操作 |
handler.deleteProperty() | 拦截 Proxy 实例删除属性操作 |
handler.get() | 拦截 读取属性的操作 |
handler.set() | 拦截 属性赋值的操作 |
handler.getOwnPropertyDescriptor() | 拦截 Object.getOwnPropertyDescriptor() 的操作 |
handler.getPrototypeOf() | 拦截 获取原型对象的操作 |
handler.has() | 拦截 属性检索操作 |
handler.isExtensible() | 拦截 Object.isExtensible()操作 |
handler.ownKeys() | 拦截 Object.getOwnPropertyDescriptor() 的操作 |
handler.preventExtension() | 拦截 Object().preventExtension() 操作 |
handler.setPrototypeOf() | 拦截Object.setPrototypeOf()操作 |
Proxy.revocable() | 创建一个可取消的 Proxy 实例 |
二、Reflect
- 概述
与Proxy相同,也是ES6新增。 它新增了一些方法,这些方法可以使一些操作更加规范化,更加便利。对象有如下特点:
- 只要Proxy对象具有的代理方法,Reflect对象(
Reflrct是一个实例对象,不能被new
)全部具有,以静态方法的形式存在。这些方法能够执行默认行为,无论Proxy怎么修改默认行为,总是可以通过Reflect对应的方法获取默认行为。 - 新增的方法与现有一些方法功能重复,新增的方法会取代现有的方法,比如Reflect.getPrototypeOf(),Object对象具有同样的方法,功能也相同,但是将getPrototypeOf()方法移植到Reflect更加合理。还有一些新增方法用来取代现有的命令式操作,比如判断属性是否存在的in命令,用Reflect.has()方法替代。
总体来说和Object很像
由于早期js的设计问题,很多api不应该增加到Object上面,es6让全部的操作集中到reflect上面
- 实例方法
方法 | 描述 |
---|---|
Reflect.apply() | 通过指定的参数列表发起对目标函数的调用 |
Reflect.construct() | 此方法行为有点像 new 操作符构造函数,相当于运行 new target(…args) |
Reflect.defineProperty() | 方法功能类似于Object.defineProperty()方法 |
Reflect.deleteProperty() | 功能类似于delete运算符 |
Reflect.get() | 从对象获取指定属性值 |
Reflect.set() | 设置指定对象的属性,比如为对象添加新属性或者修改原有属性的值 |
Reflect.getOwnPropertyDescriptor() | 功能类似于Object.getOwnPropertyDescriptor() |
Reflect.getPrototypeOf() | 获取对象的原型对象 |
Reflect.has() | 用于检查一个对象是否拥有某个属性 |
Reflect.isExtensible() | 判断一个对象是否可扩展 (即是否能够添加新的属性) |
Reflect.ownKeys() | 返回一个由目标对象自身的属性键组成的数组。 |
Reflect.preventExtensions() | 阻止新属性添加到对象 |
Reflect.setPrototypeOf() | 设置对象的原型 |
- receiver参数的理解
recevier指的是代理对象本身
使用了receiver之后,如果 name 属性部署了读取函数(getter),则读取函数的 this 绑定 receiver。
- 不使用receiver
let obj = {
_name: "zw",
age: 17,
get name(){
console.log(this,'get name')// 注意这里的this指代
return this._name
},
set name(newValue){
console.log(this,'get name')// 注意这里的this指代
this._name = newValue
}
};
const objProxy = new Proxy(obj, {
get(target, key) {
// target[key]对原来对象做操作了
console.log("---get");
// 对代理对象做操作
return Reflect.get(target, key);
},
set(target, key, newValue) {
console.log("---set");
const res = Reflect.set(target, key, newValue);
if (res) {
console.log('设置成功')
} else {
console.log('设置失败')
}
},
});
objProxy.name = "zhangwai";
console.log(objProxy.name);
执行结果
- 使用receiver
let obj = {
_name: "zw",
age: 17,
get name(){
console.log(this,'get name')
return this._name // 注意这里的this指代
},
set name(newValue){
console.log(this,'set name')
this._name = newValue // 注意这里的this指代
}
};
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
// target[key]对原来对象做操作了
console.log("---get", receiver);
// 对代理对象做操作
return Reflect.get(target, key, receiver);
},
set(target, key, newValue, receiver) {
console.log("---set");
const res = Reflect.set(target, key, newValue, receiver);
if (res) {
console.log('设置成功')
} else {
console.log('设置失败')
}
},
});
objProxy.name = "zhangwai";
// 先去objProxy get捕获器 再去obj的name方法 里面的this指代obj
// Reflect传递第三个参数receiver 就可以改变obj里面的this指向,指向代理对象
console.log(objProxy.name);
执行结果