Note: This isn't a question about best practices. The with statement is obviously something we should avoid in regular JS usage. I'm interested in its behaviour because I'm writing a simple DSL and seeing how I can push JavaScript's limits to make certain features work.
Consider the following code:
var obj = {prop:0};
with(obj) { prop = 1; }
// obj.prop === 1
Whenever we use a variable inside the with block (like prop, above), it first looks to see if that variable is a property of obj. If it is, then it basically converts that variable to obj.prop.
However, if the variable is not found within obj, then the JS engine surfs up the scope chain looking for prop until it reaches the global object as a last resort:
var obj = {};
with(obj) { prop = 1; }
// obj.prop === undefined
// window.prop === 1
Here's my question: In the above example, the JS engine looks for prop within obj. Is there a way to intercept this lookup? I'd like to "trick" the JS engine (in a spec-compliant way, of course) into thinking that obj has every property in existence, so that all variables references withing the with statement are interpreted as obj.variable. Basically, I want this behaviour:
var obj = {};
with(obj) { prop = 1; }
// obj.prop === 1
I thought this would be as simple as proxying obj and intercepting gets, since (I figured) the engine would do a get to see is obj has prop. I thought that I could simply return something other than undefined, and then the with would treat obj as having all properties:
var prox = new Proxy({}, {
set(target, property, value) { target[property] = value; },
get(target, property) { return target[property] !== undefined ? target[property] : null; },
});
with(prox) { prop = 1; }
But that doesn't seem to work. Any ideas?