apply(target, object, args):三个参数,分别是
目标对象(目标对象得是函数)
目标对象的上下文对象(this)(需要手动设置的)
目标对象的参数数组。
用于拦截函数的调用、call 和 reply 操作。target 表示目标对象,ctx 表示目标对象上下文,args 表示目标对象的参数数组。
拦截 Proxy 实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)。
let target = function () {
console.log("猫抓老鼠!");
};
let p = new Proxy(target, {
apply: function () {
target();
function dog() {
console.log("狗管闲事!");
}
dog();
},
});
//拦截target函数。
p();//猫抓老鼠
//狗管闲事!
用于拦截 HasProperty 操作,即在判断 target 对象是否存在 propKey 属性时,会被这个方法拦截。此方法不判断一个属性是对象自身的属性,还是继承的属性
注意:此方法不拦截 for … in 循环。
let obj = {
_porp: "foo", porp: "foo" };
let p = new Proxy(obj, {
has : function(target, key){
// 添加新的功能
if(key[0] == "_"){
return false;
}
return key in target;
}
});
console.log('_porp' in p);
construct方法可以接受两个参数。
target:目标对象
args:构造函数的参数对象
construct方法返回的必须是一个对象,否则会报错。
function Person(name) {
this.name = name;
}
let p = new Proxy(Person, {
construct : function(target, args){
target.prototype.say = function(){
console.log("我会说虎牙!");
}
// return new target(...args);
return Reflect.construct(target,[...args]);
}
});
let zhangsan = new p("张三");
console.log(zhangsan.name);
zhangsan.say();
deleteProperty方法用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。
let obj = {
_porp: "123",
};
console.log(obj);
delete obj._porp
console.log(obj);
let p = new Proxy(obj, {
deleteProperty: function (target, key) {
if (key[0] == "_") {
throw new Error("删除错误!或者该属性不能删除!");
}
delete target[key];
},
});
console.log(p);
delete p._porp;
console.log(p);
{
var handler = {
defineProperty:function(target,key,descriptor) {
console.log(descriptor);
target[key] = descriptor.value;
// return true;无效
// return false;
}
};
var target = {
};
var proxy = new Proxy(target,handler);
proxy.foo = 'bar'
console.log('proxy添加新的属性:',proxy);
console.log(target.foo);
}
Proxy代理内的definneProperty方法return true/false并没有任何意义。
当目标对象添加属性的方法被拦截defineProperty方法若不添加 target[key] = descriptor.value;,则不能添加属性。
注意,如果目标对象不可扩展(non-extensible),则defineProperty不能增加目标对象上不存在的属性
否则会报错。另外,如果目标对象的某个属性不可写(writable)或不可配置(configurable),
则defineProperty方法不得改变这两个设置。
输出结果
getOwnPropertAyDescriptor方法拦截Object.getOwnPropertyDescriptor(),返回一个属性描述对象或者undefined。
let obj = {
_porp: "foo", porp: "foo" };
let p = new Proxy(obj, {
getOwnPropertyDescriptor: function (target, key) {
if (key[0] == "_") {
throw new Error("查找错误!或者该属性不能查找!");
}
return Object.getOwnPropertyDescriptor(target, key);
},
});
console.log(Object.getOwnPropertyDescriptor(p, "porp"));
function a() {
console.log("开始游戏!");
}
if (init == true) {
a();
}
let init = true;
let p = new Proxy(a, {
apply: function (target) {
if(init == true){
target();
}else{
console.log("武器系统还没冷却!");
}
},
});
//
p();
getPrototypeOf方法主要用来拦截获取对象原型。具体来说,拦截下面这些操作。
Object.prototype.proto
Object.prototype.isPrototypeOf()
Object.getPrototypeOf()
Reflect.getPrototypeOf()
instanceof
左侧代码中,getPrototypeOf方法拦截Object.getPrototypeOf(),返回proto对象。
注意: getPrototypeOf方法的返回值必须是对象或者null,否则报错。另外,如果目标对象不可扩展(non-extensible), getPrototypeOf方法必须返回目标对象的原型对象。
isExtensible方法拦截Object.isExtensible操作。
左侧代码设置了isExtensible方法,在调用Object.isExtensible时会输出called。
注意,该方法只能返回布尔值,否则返回值会被自动转为布尔值。
这个方法有一个强限制,它的返回值必须与目标对象的isExtensible属性保持一致,否则就会抛出错误( 如下所示 )
ownKeys方法用来拦截对象自身属性的读取操作。具体来说,拦截以下操作。
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
for…in循环
注意,使用Object.keys方法时,有三类属性会被ownKeys方法自动过滤,不会返回。
目标对象上不存在的属性
属性名为 Symbol 值
不可遍历(enumerable)的属性
let obj = {
_a: 1, b: 2, c: 3 };
Object.defineProperty(obj, "_a", {
//遍历
enumerable : false
});
// for (let key in obj) {
// console.log(key, obj[key]);
// }
let p = new Proxy(obj, {
ownKeys : function(target){
console.log(target)
return ["_a", "b", "c", "d"];
}
});
// console.log(Object.keys(p))
for (let key in p) {
console.log(key, obj[key]);
}
preventExtensions方法拦截Object.preventExtensions()。该方法必须返回一个布尔值,否则会被自动转为布尔值。
这个方法有一个限制,只有目标对象不可扩展时(即Object.isExtensible(proxy)为false),proxy.preventExtensions才能返回true,否则会报错。
setPrototypeOf方法主要用来拦截Object.setPrototypeOf方法
注意,该方法只能返回布尔值,否则会被自动转为布尔值。另外,如果目标对象不可扩展(non-extensible),setPrototypeOf方法不得改变目标对象的原型。
Proxy.revocable方法返回一个可取消的 Proxy 实例。
Proxy.revocable方法返回一个对象,该对象的proxy属性是Proxy实例,revoke属性是一个函数,可以取消Proxy实例。上面代码中,当执行revoke函数之后,再访问Proxy实例,就会抛出一个错误。
Proxy.revocable的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。
ES6 中将 Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上(当前某些方法会同时存在于 Object 和 Reflect 对象上),未来的新方法会只部署在 Reflect 对象上。
Reflect 对象对某些方法的返回结果进行了修改,使其更合理。
说明:比如,Object.defineProperty(obj, name, desc)
在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)
则会返回false
。
Reflect 对象使用函数的方式实现了 Object 的命令式操作。
保持和proxy对象的方法一一对应
Reflect
对象的方法与Proxy
对象的方法一一对应,只要是Proxy
对象的方法,就能在Reflect
对象上找到对应的方法。
Proxy(target, {
set: function(target, name, value, receiver) {
var success = Reflect.set(target, name, value, receiver);
if (success) {
console.log('property ' + name + ' on ' + target + ' set to ' + value);
}
return success;
}
});
静态方法:
Reflect
对象一共有 13 个静态方法。
arget, name, desc)
这部分具体请google