Free email newsletter: “ES.next News

2016-11-27

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

No comments: