Proxy
Proxy用于修改某些操作的默认行为 ,等同于在语言层面做出修改,所以属于”元编程”,即是对编程语言进行编程。
Proxy可以理解成,在目标对象之前架设一层”拦截”,外界对对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。原意是代理,表示由它来”代理”某些操作。
ES6原生提供Proxy构造函数,用来生成Proxy实例。
var proxy = new Proxy(target, handler);
Proxy对象的所有写法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
拦截读取属性的例子。
var proxy = new Proxy({}, {
get: function(target, property) {
return 35;
}
});
proxy.time // 35
proxy.name // 35
proxy.title // 35
Proxy作为构造函数,接受两个参数。第一个参数是所要代理的目标对象(例子中的空对象),第二个参数是一个配置对象,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操纵。
上面代码中,配置对象有一个get方法,用来拦截对目标对象属性的访问请求。get方法的两个参数分别是目标对象和所要访问的属性。由于拦截函数总是返回35,所以访问任何属性都会得到35。
Proxy实例的方法
get()
get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象,属性名和proxy实例本身(可选)。
拦截读取操作的例子:
var person = {
name: "张三"
};
var proxy = new Proxy(person, {
get: function(target, property) {
if (property in target) {
return target[property];
} else {
throw new ReferenceError("Property \"" + property + "\" does not exist.");
}
}
});
proxy.name // "张三"
proxy.age // 抛出一个错误
上面代码表示, 如果访问目标对象不存在的属性,会抛出一个错误。如果没有这个拦截函数,访问不存在的属性,只会返回undefined。
set()
set方法用来拦截某个属性的赋值操作,可以接受四个参数。依次为目标对象、属性名、属性值和Proxy实例本身(可选)。
假定Person对象有一个age属性,该属性应该是一个不大于200的整数,那么可以使用Proxy保证age的属性值符合要求。
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// 对于满足条件的 age 属性以及其他属性,直接保存
obj[prop] = value;
}
};
let person = new Proxy({}, validator);
person.age = 100;
person.age // 100
person.age = 'young' // 报错
person.age = 300 // 报错
上面代码中,由于设置了存值函数set,任何不符合要求的age属性赋值,都会抛出一个错误,这是数据验证的一种实现方法。利用set方法,还可以数据绑定,即每当对象发生变化时,会自动更新DOM。
apply()
apply方法拦截函数的调用、call和apply操作。
apply方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组。
例子:
var target = function () { return 'I am the target'; };
var handler = {
apply: function () {
return 'I am the proxy';
}
};
var p = new Proxy(target, handler);
p()
// "I am the proxy"
上面代码中,变量p是Proxy的实例,当它作为函数调用时p(),就会被apply拦截,返回一个字符串。