调用 new Proxy() 可常见代替其它目标 (target) 对象的代理,它虚拟化了目标,所以二者看起来功能一致。代理可拦截JS引擎内部目标的底层对象操作,这些底层操作被拦截后会触发响应特定操作的陷阱函数。
代理和反射的定义
应用
let target = {}; let p = new Proxy(target, {});
p.a = 37; // 操作转发到目标 console.log(target.a); // 37. 操作已经被正确地转发
-
get() 方法用于拦截对象的读取属性操作
-
set() 方法用于拦截设置属性值的操作
-
has() 方法可以看作是针对 in 操作的钩子
-
deleteProperty() 方法用于拦截对对象属性的 delete 操作
let target = { name: 'target', color: 'blue', size: 50, skill: 'drink' } let proxy = new Proxy(target, { set: function(trapTarget, key, value, receiver) { // 忽略不希望受到影响的已有属性 if(!trapTarget.hasOwnProperty(key)) { if(isNaN(value)) { throw new TypeError('属性必须是数字!')
}
} //添加属性 return Reflect.set(trapTarget, key, value, receiver)
}, get: function(trapTarget, key, receiver) { if(!(key in receiver)) { throw new TypeError(key + '属性不存在!')
} return Reflect.get(trapTarget, key, receiver)
}, has: function(trapTarget, key) { if(key === 'color') { return false }else { return Reflect.has(trapTarget, key)
}
}, deleteProperty: function(trapTarget, key) { if(key === 'skill') { return false }else { return Reflect.deleteProperty(trapTarget, key)
}
}
}); //添加一个新属性 proxy.count = 1 console.log(target.count) //1 proxy.name = 'proxy' console.log(proxy.name) //proxy console.log(target.name) //proxy proxy.anotherName = 'proxy' //抛出错误: 属性必须是数字! console.log(proxy.age) //抛出错误:age属性不存在! console.log('name' in proxy) //true console.log('color' in proxy) //false console.log('size' in proxy) //true let result1 = delete proxy.size console.log('size' in proxy) //false console.log('skill' in proxy) //true let result2 = delete proxy.skill console.log('skill' in proxy) //true
参考