Proxy的has拦截与with关键字
Proxy的has钩子可以拦截下面这些操作:
属性查询:foo in proxy
继承属性查询:foo in Object.create(proxy)
with 检查: with(proxy) { (foo); }
Reflect.has()
本文主要就第三条说明
with关键字
JavaScript 查找某个未使用命名空间的变量时,会通过作用域链来查找,作用域链是跟执行代码的 context 或者包含这个变量的函数有关。'with’语句将某个对象添加到作用域链的顶部,如果在 statement 中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出ReferenceError
异常。
备注: 不推荐使用with
,在 ECMAScript 5 严格模式中该标签已被禁止。推荐的替代方案是声明一个临时变量来承载你所需要的属性。
举例说明
class F {
constructor() {
this.hobby = "ball";
}
}
class C extends F {
constructor() {
super();
this.name = "Hello"
}
}
const obj = new C();
const name = "Nice";
const age = 20;
function withTest() {
console.log(name); // Nice
console.log(age); // 20
// console.log(hobby) // Uncaught ReferenceError: hobby is not defined
with (obj) {
// 此时 这个块中的context对象是 obj
// 查找变量时会优先在 obj 上查找,找不到再沿着作用域链往上找
console.log(name); // Hello
console.log(age); // 20
console.log(hobby) // ball
}
}
withTest();
has拦截举例
const obj = {
name: "Eric",
age: 20
};
const proxy = new Proxy(obj, {
// 调用 "name" in proxy 会被has方法拦截
has(target, key) {
return true;
}
})
console.log("name" in proxy); // 恒为true
console.log("name1" in proxy); // 恒为true
console.log("name2" in proxy); // 恒为true
has拦截with关键字
const age = 20;
class F {
constructor() {
this.hobby = "ball";
}
}
class C extends F {
constructor() {
super();
this.name = "Hello"
}
}
const obj = new C();
const proxy = new Proxy(obj, {
has(target, key) {
// 在这里可以做些处理,比如proxy 如果没有 age 属性,不让继续往上层作用域查找
// 直接抛出一个异常
if (!target.hasOwnProperty(key)) {
throw new Error(`${key} is not defined!!!!!`);
};
return true;
}
})
with(proxy) {
name; // 无异常
age; // 抛出异常
}
总结&应用场景
讲了几个碎片化的小知识点,应用场景可以是在做沙盒环境隔离这方面。
比如我想要一个干净的隔离环境,只可以访问定义的环境变量,并且不能通过作用域链访问上层变量,此时可以借助with关键字和Proxy的has拦截器做些事情。