Portrait Dr. Axel Rauschmayer
Dr. Axel Rauschmayer
Homepage | Twitter
Cover of book “Exploring ES6”
Book, exercises, quizzes
(free to read online)
Logo of newsletter “ES.next news”
Newsletter (free)
Cover of book “JavaScript for impatient programmers”
Book (free online)

Controlling access to global variables via an ES6 proxy

(Ad, please don’t block)

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