定义
Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。
语法
let p = new Proxy(target, handler);
参数
target : 需要使用Proxy包装的目标对象
handler : 定义代理的行为的函数
通俗理解
其实就是拦截目标对象对其进行过滤和改写,这样就可以不直接操作对象本身,而是通过代理对象来间接来操作对象
handler对象中的代理操作
1、apply(target, thisArg, argumentsList)
用于拦截函数的调用,当目标target为函数,且被调用时触发。
function sum(a, b) {
return a + b;
}
const handler = {
apply: function(target, thisArg, argumentsList) {
//target为目标对象sum函数
//thisArg为target函数调用时绑定的this对象
//argumentsList为目标对象参数数组 [1,2]
console.log(`Calculate sum: ${argumentsList}`);
return target(argumentsList[0], argumentsList[1]) * 10;
}
};
var proxy1 = new Proxy(sum, handler);
console.log(proxy1(1, 2));
2、construct(target, argumentsList, newTarget)
用于拦截new 操作符,给target为构造函数的代理对象构造实例时触发
function monster1(disposition) {
this.disposition = disposition;
}
const handler1 = {
construct(target, args) {
//args为实例化所传参数 ['fierce']
return new target(...args);
}
};
const proxy1 = new Proxy(monster1, handler1);
console.log(new proxy1('fierce').disposition);
示例
1、基础示例
let obj = {
a : 1
}
let proxyObj = new Proxy(obj,{
get : function (target,key) {
return key in target ? target[key] : 0
},
set : function (target,key,value) {
target[key] = 888;
}
})
console.log(proxyObj.a); // 1
console.log(proxyObj.b); // 0
proxyObj.a = 666;
console.log(proxyObj.a) // 888
2、无操作转发代理
let target = {};
let p = new Proxy(target, {});
p.a = 37; // 操作转发到目标
console.log(target.a); // 37. 操作已经被正确地转发
3、数据合法性校验
let validator = {
set: function(obj, key, value) {
if (key === 'age') {
if (!Number.isInteger(value)) {//Number.isInteger(value)判断一个数是否为整数
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// The default behavior to store the value
obj[key] = value;
}
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age);// 100
person.age = 'young';// 抛出异常: Uncaught TypeError: The age is not an integer
person.age = 300;// 抛出异常: Uncaught RangeError: The age seems invalid
4、拓展构造函数
function extend(sup,base) {
var descriptor = Object.getOwnPropertyDescriptor(//返回目标对象自有属性对应的属性描述符
//configurable enumerable value writable
base.prototype,"constructor"
);
base.prototype = Object.create(sup.prototype);
//new Object() 通过构造函数来创建对象, 添加的属性是在自身实例下。
//Object.create(proto,[propertiesObject]) es6创建对象的另一种方式,可以理解为继承一个对象, 添加的属性是在原型下。
//proto:必须。表示新建对象的原型对象,即该参数会被赋值到目标对象的原型上
//propertiesObject可选。添加到新创建对象的可枚举属性对象的属性描述符以及相应的属性名称。
//eg:var o = Object.create({}, { p: { value: 42 } })
var handler = {
construct: function(target, args) {
var obj = Object.create(base.prototype);
this.apply(target,obj,args);
return obj;
},
apply: function(target, that, args) {
sup.apply(that,args);
base.apply(that,args);
}
};
var proxy = new Proxy(base,handler);
descriptor.value = proxy;
Object.defineProperty(base.prototype, "constructor", descriptor);
return proxy;
}
var Person = function(name){
this.name = name
};
var Boy = extend(Person, function(name, age) {
this.age = age;
});
Boy.prototype.sex = "M";
var Peter = new Boy("Peter", 13);
console.log(Peter.sex); // "M"
console.log(Peter.name); // "Peter"
console.log(Peter.age); // 13