首先,我想澄清一下,我知道with
已被弃用,使用它通常是一种不好的做法。
但是,我的问题是关于一种特殊情况:使用特殊Proxy
对象作为with
的参数。
背景
我正在做一个项目,我必须将一段代码的访问限制在全局范围内。
一种方法可能是使用带有eval
的循环,为全局对象的每个属性创建值为undefined
的常量变量,但这似乎比使用with
更糟糕,并且不能限制对使用let
和const
创建的变量的访问。
这个想法
这个想法是使用Proxy
作为with
的论据,谁...
has
陷阱总是返回true
,因此它不允许任何查找或赋值超出with
语句get
陷阱运行正常,除了在尝试访问不存在的变量(即属性(时抛出ReferenceError
set
陷阱正常运行(或者可能包含一些自定义逻辑(target
对象没有[[Prototype]]
(即它是用Object.create(null)
创建的(target
对象具有一个@@unscopables
属性,其值为空对象,以允许每个属性的范围
所以,像这样的代码:
const scope = Object.create(null)
Object.assign(scope, {
undefined,
console,
String,
Number,
Boolean,
Array,
Object,
/* etc. */
[Symbol.unscopables]: Object.create(null)
})
const scopeProxy = new Proxy(scope, {
get: (obj, prop) => {
if (prop in obj)
return obj[prop]
else
throw new ReferenceError(`${prop} is not defined`)
},
set: Reflect.set,
has: () => true
})
with(scopeProxy) {
//Sandboxed code
foo = Number('42')
console.log(foo) //42
try{
console.log(scopeProxy) //Inaccessible
}catch(e){
console.error(e) //ReferenceError: scopeProxy is not defined
}
}
避免反政府武装
MDN 的页面上列出了几个关于with
语句的反对意见,但这种用法摆脱了每一个。
1. 性能
问题:
查找不是语句参数对象成员
with
标识符的性能较低。避免:
任何查找都不能超出参数对象。
阿拉伯数字。多义性
问题:
很难决定,哪个标识符被查找具有相同名称的标识符。
避免:
所有查找和赋值都检索或修改参数对象的属性。
3.向前兼容性
问题:
参数对象或其原型的属性将来可能会更改。
避免:
参数对象最初为空,没有原型,因此无法更改任何属性。
问题
上面的代码运行良好,MDN 上列出的反政府似乎不适用于这种情况。
所以,我的问题是:
使用with
语句是否仍然是一种不好的做法,如果是这样,在这种特定情况下使用它有什么缺点?
注意:我知道这种方法本身并不安全,可以绕过。但是,这个问题仅限于出于某种原因使用上述Proxy
-with
组合是否被认为是不好的。在这个问题上,我不关心安全性(这是一个相关但不同的问题(。
听起来像是古老的词汇与动态范围主题。一般来说,词法范围更安全,但在某些情况下,动态范围是有意义的,因为它大大简化了一些解决方案。我想说你的例子是其中一种情况,它可能有用。