1、Proxy
- Proxy 对象用于
创建一个代理对象
- 拦截对象的基本操作(如属性查找、赋值、枚举、函数调用等)
直接监听对象、并非属性(Object.deleteProperty)、不需要递归
- 拦截函数的集合
- 增删改查:get、set、has、deleteProperty
- 属性相关:defineProperty、getOwnPropertyDescriptor、ownkeys
- 原型相关:getPrototypeOf、setPrototypeOf
- apply使用:construct、apply
- 扩展:isExtensible、preventExtensions
var proxy = new Proxy(
{
a: {
aa: {
aaa: "ppp",
},
},
},
{
get(target, property) {
console.log(target, property);
return target[property];
},
set(target, key, newValue) {
if (target[key] === newValue) {
return;
}
target[key] = newValue;
},
...
}
);
console.log(proxy.a.aa.aaa);
get(target, propKey, receiver):读取对象属性时触发
- 拦截条件
- 访问属性: proxy[foo] 和 proxy.bar
- 访问原型链上的属性: Object.create(proxy)[foo]
- Reflect.get()
- 约束
- 当 target 不可配置,则返回的值必须与该目标属性的值 相同
- 如果 get方法中无 return 返回值,则返回值必须为 undefined
var obj = {};
Object.defineProperty(obj, "a", {
configurable: true,
enumerable: false,
value: 10,
writable: false,
});
var p = new Proxy(obj, {
get: function (target, prop) {
return 20;
},
});
console.log(p.a);
set( target, propKey, value, receiver ) :设置对象属性时触发
- 拦截条件
- 指定属性值:proxy[foo] = bar 和 proxy.foo = bar
- 指定继承者的属性值:Object.create(proxy)[foo] = bar
- Reflect.set()
- 约束
- target的 属性为不可写数据属性,则不能改变它的值
- garget 没有配置存储方法,即 [[Set]] 属性的是 undefined,则不能设置值
- 在严格模式下,如果 set() 方法返回 false,那么也会抛出个 TypeError 异常
var p = new Proxy(
{},
{
set: function (target, prop, value, receiver) {
target[prop] = value;
return true;
},
}
);
console.log("a" in p);
p.a = 10;
console.log("a" in p);
console.log(p.a);
has(target, propKey):判断对象属性是否存在时触发
- 拦截条件
- 属性查询: foo in proxy
- 继承属性查询: foo in Object.create(proxy)
- with 检查: with(proxy) { (foo); }
- Reflect.has()
- 约束
- 如果目标对象的某一属性本身不可被配置,则该属性不能够被代理隐藏.
- 如果目标对象为不可扩展对象,则该对象的属性不能够被代理隐藏
var p = new Proxy(
{},
{
has: function (target, prop) {
console.log("called: " + prop);
return true;
},
}
);
console.log("a" in p);
var obj = { a: 10 };
Object.preventExtensions(obj);
var p = new Proxy(obj, {
has: function (target, prop) {
return false;
},
});
"a" in p;
deleteProperty(target, propKey):删除对象属性时触发
- 触发条件
- delete proxy[foo]
- delete proxy.foo
- Reflect.deleteProperty()
- 约束
- 如果目标对象的属性是不可配置的,那么该属性不能被删除
var p = new Proxy(
{},
{
deleteProperty: function (target, prop) {
console.log("called: " + prop);
return true;
},
}
);
delete p.a;
ownKeys(target):获取对象 keys 时触发
- 拦截条件
- Object.getOwnPropertyNames()
- Object.getOwnPropertySymbols()
- Object.keys() // entries、vlaues
- Reflect.ownKeys()
- 约束
- ownKeys 的结果 必须是一个数组,且 元素必须是String或Symbol
- 结果列表必须包含目标对象的所有 不可配置、自有属性的key
- 目标对象不可扩展,返回所有自有属性的key,不能有其它值
var obj = { x: "x", y: "y" };
Object.defineProperty(obj, "z", {
configurable: false,
enumerable: false,
value: "z",
writable: false,
});
var p = new Proxy(obj, {
ownKeys: function (target, prop) {
return ["x", "y", "z"];
},
});
console.log(Object.getOwnPropertyNames(p));
getOwnPropertyDescriptor(target, propKey):获取对象属性描述时触发
- 拦截条件
- Object.getOwnPropertyDescriptor() //getOwnPropertyDescriptors
- Reflect.getOwnPropertyDescriptor() //getOwnPropertyDescriptors
- 约束
- getOwnPropertyDescriptor 必须返回一个 object 或 undefined
- 目标对象的 不可配置 的属性存在,报错
- 目标对象不可扩展,报错
var obj = { x: "x", y: "y" };
Object.defineProperty(obj, "z", {
configurable: false,
enumerable: false,
value: "z",
writable: false,
});
var p = new Proxy(obj, {
getOwnPropertyDescriptor: function (target, prop) {
return { configurable: true, enumerable: true, value: 10 };
},
});
console.log(Object.getOwnPropertyDescriptor(p, "x"));
var obj = { a: 10 };
Object.preventExtensions(obj);
var p = new Proxy(obj, {
getOwnPropertyDescriptor: function (target, prop) {
return undefined;
},
});
Object.getOwnPropertyDescriptor(p, "a");
defineProperty(target, propKey, propDesc):设置对象属性描述时触发
- 拦截条件
-
- Object.defineProperty()
- Reflect.defineProperty()
- proxy.property='value'
- 约束
-
- 如果目标对象 不可扩展, 将不能添加属性。
- 不能修改一个属性为不可配置的目标对象
- 在严格模式下, 返回值为 false 将会抛出 TypeError 异常.
var p = new Proxy(
{},
{
defineProperty: function (target, prop, descriptor) {
console.log("called: " + prop);
return true;
},
}
);
var desc = { configurable: true, enumerable: true, value: 10 };
Object.defineProperty(p, "a", desc);
getPrototypeOf(target):获取对象原型时触发
- 拦截条件
- Object.getPrototypeOf()
- Reflect.getPrototypeOf()
- proto
- Object.prototype.isPrototypeOf()
- instanceof
- 约束
- getPrototypeOf() 方法 返回的 不是对象也不是 null
- 目标对象是不可扩展的,且 getPrototypeOf() 方法返回的原型不是目标对象本身的原型
var obj = {};
var proto = {};
var handler = {
getPrototypeOf(target) {
console.log(target === obj);
console.log(this === handler);
return proto;
},
};
var p = new Proxy(obj, handler);
console.log(Object.getPrototypeOf(p) === proto);
var obj = {};
var p = new Proxy(obj, {
getPrototypeOf(target) {
return "foo";
},
});
Object.getPrototypeOf(p);
var obj = Object.preventExtensions({});
var p = new Proxy(obj, {
getPrototypeOf(target) {
return {};
},
});
Object.getPrototypeOf(p);
setPrototypeOf(target):设置对象原型时触发
- 拦截条件
- Object.setPrototypeOf()
- Reflect.setPrototypeOf()
- 约束
- 如果 target 不可扩展
- 原型参数必须与Object.getPrototypeOf(target) 的值相同
var handlerReturnsFalse = {
setPrototypeOf(target, newProto) {
return false;
},
};
var newProto = {},
target = {};
var p1 = new Proxy(target, handlerReturnsFalse);
Object.setPrototypeOf(p1, newProto);
Reflect.setPrototypeOf(p1, newProto);
apply(target):调用 call、apply 方法时触发
- 拦截条件
- proxy(...args)
- Function.prototype.apply()
- Function.prototype.call()
- Reflect.apply()
- 约束
var p = new Proxy(function () {}, {
apply: function (target, thisArg, argumentsList) {
return argumentsList[0] + argumentsList[1] + argumentsList[2];
},
});
console.log(p(1, 2, 3));
construct(target):实例化函数时触发
- 拦截条件
- new proxy(...args)
- Reflect.construct()
- 约束
var p = new Proxy(function () {}, {
construct: function (target, argumentsList, newTarget) {
return { value: argumentsList[0] * 10 };
},
});
console.log(new p(1).value);
isExtensible(target):判断对象是否可扩展时触发
- 拦截条件
- Object.isExtensible()
- Reflect.isExtensible()
- 约束
var p = new Proxy(
{},
{
isExtensible: function (target) {
return true;
},
}
);
console.log(Object.isExtensible(p));
preventExtensions(target):设置禁止扩展属性时触发
- 拦截条件
- Object.preventExtensions()
- Reflect.preventExtensions()
- 约束
var obj = {};
Object.preventExtensions(obj);
var p = new Proxy(obj, {
preventExtensions: function (target) {
Object.preventExtensions(target);
return true;
},
});
Object.preventExtensions(p);
2、Reflect
- 挂载 object 对象一些内部的操作方法
- Proxy 与 Reflect的作用
- Proxy -
负责拦截操作
- Reflect -
负责执行对象的操作
let People = new Proxy(
{
_name: "zky",
get name() {
return this._name;
},
},
{
get: function (target, prop, receiver) {
return target[prop];
},
}
);
let Man = { _name: "zky_man" };
Man.__proto__ = People;
console.log(Man._name);
console.log(Man.name);
let People = new Proxy(
{
_name: "zky",
get name() {
return this._name;
},
},
{
get: function (target, prop, receiver) {
return Reflect.get(target, prop, receiver);
},
}
);
let Man = { _name: "zky_man" };
Man.__proto__ = People;
console.log(Man._name);
console.log(Man.name);