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

FZs*_*FZs 9 javascript with-statement es6-proxy

首先,我要澄清,我知道,with已被弃用,并使用它通常一个糟糕的做法

但是,我的问题是关于一个特殊情况:使用特殊Proxy对象作为with.


背景

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

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

想法

这个想法是使用 aProxy作为 的参数with,其...

  • hastrap 总是返回true,因此它不允许任何查找或赋值超出with语句
  • gettrap 正常运行,除了它ReferenceError在尝试访问不存在的变量(即属性)时抛出s
  • set trap 正常运行(或者可能包含一些自定义逻辑)
  • 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
  }
}
Run Code Online (Sandbox Code Playgroud)

避免反义词

MDN 的页面with上列出了几个关于statementcontras,但是它的这种用法摆脱了每一个。

1. 性能

  • 问题:

    查找不是with语句参数对象成员的标识符的性能较低。

  • 回避:

    任何查找都不能超出参数对象。

2. 歧义

  • 问题:

    很难决定哪个标识符会在同名的标识符中查找。

  • 回避:

    所有查找和分配都会检索或修改参数对象的属性。

3.向前兼容

  • 问题:

    参数对象或其原​​型的属性将来可能会发生变化。

  • 回避:

    参数对象最初是空的,没有原型,因此没有属性可以改变。

上面的代码完美运行,MDN 上列出的 contras 似乎不适用于这种情况。

所以,我的问题是:

使用该with语句是否仍然是一种不好的做法,如果是,在这种特定情况下使用它有什么缺点?


注意:我知道这种方法本身并不安全,可以绕过。但是,这个问题仅限于使用上述Proxy-with组合是否出于某种原因被认为是不好的。在这个问题中,我不关心安全性(这是一个相关但不同的问题)。

cev*_*ing 1

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