将"with"语句与代理一起使用是一种不好的做法吗?



首先,我想澄清一下,我知道with已被弃用,使用它通常是一种不好的做法

但是,我的问题是关于一种特殊情况:使用特殊Proxy对象作为with的参数。

<小时 />

背景

我正在做一个项目,我必须将一段代码的访问限制在全局范围内。

一种方法可能是使用带有eval的循环,为全局对象的每个属性创建值为undefined的常量变量,但这似乎比使用with更糟糕,并且不能限制对使用letconst创建的变量的访问。

这个想法

这个想法是使用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组合是否被认为是不好的。在这个问题上,我不关心安全性(这是一个相关但不同的问题(。

听起来像是古老的词汇与动态范围主题。一般来说,词法范围更安全,但在某些情况下,动态范围是有意义的,因为它大大简化了一些解决方案。我想说你的例子是其中一种情况,它可能有用。

相关内容

最新更新