Proxy
什么是Proxy?
Proxy 是 ES6 中新增的功能,它可以用来自定义对象中的操作。(用来修改某些操作的默认行为)
等同于在语言层面修改,所以属于“元编程”,即对编程语言进行编程。
Proxy可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理,它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时可以添加一些需要的额外的操作。
Proxy可以理解为在目标对象前架设一个“拦截”层,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和修改。
基本使用
Proxy构造函数。
let p = new Proxy(target,handler);//返回一个对象(一个Proxy实例)
target:表示所要拦截(代理)的目标对象
handler:是一个对象,用来定制拦截(代理)行为(如set()、get()、deleteProperty()等方法)
Proxy实例的部分方法使用
** set()、get()、apply()、has()**
-
get(target, property):
读取代理的目标对象时所要做的事情 -
set(target,property,value,receiver):
设置代理目标属性是要做的事情
参数receiver表示原始操作行为所在对象,一般是Proxy实例本身。 -
apply(tartget,ctx,args):
用于拦截函数的调用、call和apply操作。target:目标对象;ctx:目标对象的上下文对象;args:目标对象的参数数组 -
has(target,propKey):
拦截propKey in proxy 的操作(拦截HasProperty操作,即判断对象是否具有某一个属性时,返回一个布尔值。不判断继承属性。不拦截for...in循环。
5.deleteProperty(target,property):
用于拦截delete操作,如果这个方法抛出错误或者返回false,propKey属性就无法被delete操作删除。 -
construct(target,args):
用于拦截new命令。返回值必须为对象。let obj = { name: '张三' }; let p = new Proxy(obj, { get(target, property) { //读取代理的目标对象时所要做的事情 //console.log(`读取${property}属性`); //console.log(target[property]); if (property in target) { console.log(target[property]); } else { // throw new Error("没有这个属性"); console.error("没有这个属性"); } }, set(target, property, value) { //设置代理目标属性是要做的事情 console.log("修改属性值"); if (property === 'age') { if (!Number.isInteger(value)) { // console.error("年龄必须为整数"); throw new Error("年龄必须为整数"); } if (value > 200) { console.error("年龄超标了,必须小于200岁") } else { target[property] = value; } } //target[property] = value; }, has(target, propKey) { //拦截propKey in proxy 的操作(拦截HasProperty操作,即判断对象是否具有某一个属性时,返回一个布尔值 console.log(propKey in target); }, deleteProperty(target, proKey) { console.log(`要删除${proKey}属性`); delete target[proKey]; } }) const fn1 = function() { return 'I am the target'; } let p2 = new Proxy(fn1, { apply(target, ctx, args) { //拦截函数的调用、call和apply操作 //target:目标对象;ctx:目标对象的上下文对象;args:目标对象的参数数组 console.log("拦截调用"); console.log(target()); //I am the target } }) let fn2 = function(a, b) { return a + b; } let p3 = new Proxy(fn2, { apply(taregt, ctx, args) { console.log(ctx); //p3(1,2):undefined ;p3(null,5,6):null ;Reflect.apply(p3, null, [9, 10]):null console.log(args); //[1,2] [5,6] [9,10] console.log(Reflect.apply(...arguments) * 2); //6 22 38 } }) p.name; p.a; p.name = "李四"; p.name; console.log(p); //Proxy {name: "李四"} for (let i in p) { //has拦截对for...in循环不生效 console.log(i); //name } 'name' in p; //true 'a' in p; //false p2(); //p2是proxy的实例,作为函数调用时会被apply方法拦截 p3(1, 2); p3.call(null, 5, 6); Reflect.apply(p3, null, [9, 10]);
应用:拦截空对象创建DOM元素
//实例 创建dom元素
const DOM = new Proxy({}, { //拦截一个空对象
get(target, property) {
//property: DOM.xxx 里面的 xxx
//返回一个创建元素的函数
return function(attr = {}, ...children) { //属性默认为空,rest参数
console.log(attr, children);
const el = document.createElement(property);
for (let i in attr) {
el.setAttribute(i, attr[i]);
}
for (let child of children) {
if (typeof child === 'string') {
child = document.createTextNode(child);
}
el.appendChild(child);
}
return el;
}
}
})
let el = DOM.div({
id: 'box',
class: 'box'
}, '哈哈哈', '呵呵呵',
DOM.a({
href: 'http://www.baidu.com'
}, "百度")); //拦截div方法
console.log(el); //
let el2 = DOM.ul({
id: 'ul'
}, DOM.li({}, '1'), DOM.li({}, '2'), DOM.li({}, '3'));
window.onload = function() {
document.body.appendChild(el);
document.body.appendChild(el2);
}


浙公网安备 33010602011771号