(sies)
Proxies are a meta-programming feature that allow you to change how fundamental JS operations work on a target object.
By default, they don't do much:
let target = {};
let handlers = {};
let proxy = new Proxy(target, handlers);
console.log(proxy.foo); // undefinedfunction createFunction (name) {
    return `
        (function () {
            return function ${name} () {
                console.log('hello ${name}!');
                return createFunction('${name}');
            }
        })()
    `;
}
eval(createFunction('Craig'))();Programs operate on data and data structures.
Meta-programs operate on programs:
Object.keys();function barify (object, key) {
    object[key] = 'bar';
}function doMaths (a, b, c) {
    return a * b + c;
}
doMaths.length; // 3let object = {};
let handlers = {};
let proxy = new Proxy(object, {
    get (target, key) {
        console.log(target, key);
    }
});
proxy.foo; // object, 'foo'Here we have provided a trap for the "get" operation. Whenever a property is accessed on our object, the trap will fire.
get
set
has
deleteProperty
defineProperty
getOwnPropertyDescriptor
ownKeys
getPrototypeOf
setPrototypeOf
isExtensible
preventExtensions
set:
let manners = new Proxy({}, {
    set (target, key, value) {
        console.log(target, key, value);
        if (value.match(/please$/)) {
            Reflect.set(target, key, value);
        } else {
            console.log('nah');
        }
    }
});
manners.foo = 'bar'; // 'nah';
manners.foo = 'bar, please';has:
let object = { foo: 'bar' };
let liar = new Proxy(object, {
    has (target, prop) {
        return !Reflect.has(target, prop);
    }
});
console.log('foo' in liar); // false;
console.log('baz' in liar); // true;Note that in these examples we've used the Reflection API. Every Proxy trap has an equivalent method on the global Reflect object (also part of ES2015)
deleteProperty:
let object = { foo: 'bar' };
let hoarder = new Proxy(object, {
    deleteProperty (target, prop) {
        return false;
    }
});
delete hoarder.foo;
console.log(hoarder.foo); // 'bar'apply:
construct:
var func = function () { };
var trapped = new Proxy(func, {
    apply () {
        console.log('Hello?');
    },
    construct () {
        console.log('What do you want?');
    }
});
console.log(trapped()); // 'Hello?'
console.log(new trapped()); // 'What do you want?'If the following invariants are violated, the proxy will throw a TypeError:
A trap may have a set of invariants, which are rules around behaviour that cannot be modified.
For example, the deleteProperty trap:
and more...
let mock = ineeda();
// [[Get]] trap:
console.log(mock.foo.bar.baz); // Proxies all the way down.
// [[Apply]] trap:
console.log(mock.foo.bar.baz()); // throws Error('Not implemented');
// [[Set]] trap:
mock.value = 42;
console.log(mock.value) // 42;
// Whole bunch of traps:
sinon.stub(mock.some.deeply.nested, 'property');Proxies are powerful, but they aren't omnipotent
function Point (x, y) {
    return new Proxy({ x, y }, {
        add (a, b) {
            return new Proxy(a.x + b.x, a.y + b.y);
        }
    });
}
var p1 = Point(1, 2);
var p2 = Point(3, 4);
console.log(p1 + p2); // { x: 4, y: 6 }operator overloading:
Note: unfortunately, this isn't real JS 😢
var object = {};
var falsy = new Proxy(object, {
    toBoolean (target) {
        return false;
    }
});
console.log(!!object); // true;
console.log(!!falsy); // false;toBoolean:
Note: unfortunately, this isn't real JS 😢