Controlling access to global variables via an ES6 proxy


The following function evalCode() traces the global variables that are accessed while evaluating a piece of JavaScript code.




// Simple solution
const _glob = typeof global !== 'undefined' ? global : self;

function evalCode(code) {
const func = new Function ('proxy',
`with (proxy) {${code}}`); // (A)
const proxy = new Proxy(_glob, {
get(target, propKey, receiver) {
console.log(`GET ${String(propKey)}`); // (B)
return Reflect.get(target, propKey, receiver);
},
set(target, propKey, value, receiver) { // (C)
console.log(`SET ${String(propKey)}=${value}`);
return Reflect.set(target, propKey, value, receiver);
},
});
return func(proxy);
}

The way this works is as follows:



  • The with statement wrapped around the code (line A) means that every variable access that “leaves” the scope of the code becomes a property access of proxy.

  • The proxy observes what properties are accessed via its handler, which traps the operations “get” (line B) and “set” (line C),


Unsing evalCode():



> evalCode('String.prototype')
GET Symbol(Symbol.unscopables)
GET String
undefined
> evalCode('String = 123')
GET Symbol(Symbol.unscopables)
SET String=123
undefined

Explanations:



  • We don’t return what code does, which is why the result is undefined.

  • Symbol.unscopables shows up, because with checks its operand for a property with this key to determine which properties it should not expose as variables to its body. This mechanism is explained in “Exploring ES6”.


This is very hacky! with is a deprecated sloppy mode feature that is used in conjunction with a brand new ES6 feature.


Source of this hack: Vue.js, explained by qgustavor on reddit.


Further reading



Comments

Popular posts from this blog

Steve Lopez and the Importance of Newspapers

The interoperability of Web Component polyfills

Ideas for fixing unconnected computing