问题
First of all, I want to clarify, I know that with is deprecated, and using it is generally a bad practice.
However, my question is about a special case: using a special Proxy object as the parameter of with.
Background
I'm working on a project, where I have to limit access of a piece of code to the global scope.
One approach might be to use a loop with eval
, that creates constant variables with the value of undefined
for each property of the global object, but that seems even worse than using with
, and cannot limit access to variables created with let
and const
.
The idea
The idea is to use a Proxy as the argument of with, whose...
has
trap always returnstrue
, therefore it doesn't allow any lookups or assignments to go beyond thewith
statementget
trap operates normally, except that it throwsReferenceError
s when trying to access a non-existing variable (i.e. property)set
trap operates normally (or maybe contains some custom logic)target
object has no[[Prototype]]
(i.e. it was created withObject.create(null)
)target
object has an @@unscopables property, with the value of an empty object, to allow scoping of every property
So, something like this code:
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
}
}
Avoiding contras
There are several contras listed on the MDN's page about the with statement, but this usage of it gets rid of each.
1. Performance
The problem:
Looking up identifiers that aren't a member of
with
statement's parameter object is less performant.Avoidance:
No lookups can go beyond the parameter object.
2. Ambiguity
The problem:
It is hard to decide, which identifier gets looked up of those with the same name.
Avoidance:
All lookups and assignments retrieve or modify the property of the parameter object.
3. Forward compatibility
The problem:
The properties of the parameter object or its prototype might change in the future.
Avoidance:
The parameter object is initially empty and has no prototype, therefore no properties can change.
Question
The above code works perfectly, and the contras listed on MDN don't seem to apply to this case.
So, my question is:
Is it still a bad practice to use the with statement, and if so, what are the downsides of using it in this specific case?
Note: I know that this approach in itself is not secure and can be bypassed. However, this question is limited only to whether it's considered bad for some reason to use the abovementioned Proxy
-with
combination. In this question, I'm not concerned about security (that's a related, but different question).
回答1:
Sounds like the good old lexical vs dynamic scope topic. In general lexical scope is more safe but in some situations dynamic scope makes sense, because it simplifies some solutions very much. I would say your example is one of the cases, where it may be useful.
来源:https://stackoverflow.com/questions/59601933/is-using-with-statement-with-proxies-a-bad-practice