Thew new Proxy api presented in ecmascript6 allows us to do some really sick stuff to JavaScript’s syntax, which in my point of view is great.
I love meta-programming and up until now it was an extremely problematic/hack-ish thing to in JavaScript.
If you want to try out the code-snippets I will post in this article, you will have to use Chrome/Chromium and enable the “Experimental JavaScript” flag in your browser.
You can do it simply by typing chrome://flags/ in your address bar and CTRL+F-ing “Experimental JavaScript”.
Proxies allow us to define JS objects in a way that were impossible before.
Below is a small example made by Mozilla:
var proxy;
var handler = {
has: function (name) {
return name == 'foo';
},
get: function (rcvr, name) {
if (name != 'foo')
return undefined;
print(proxy !== rcvr);
return "bye";
},
};
proxy = Proxy.create(handler);
var c = Object.create(proxy);
print(c.foo); // prints: 'true' (from "proxy !== rcvr") and 'bye' (from "c.foo").
// In this example, the get trap rcvr argument is the c object while proxy is its prototype
Implementing Pipes
After fiddling around with the Proxy API myself, I was able to get some pretty cool results.
First thing I wanted to try is to implement pipes in JS.
I already done it once using pseudo operator overloading (you can see the result here but I wanted to see how easy it will be with proxies. The answer is “pretty damn easy”.
You can see the result below:
var pipe = (function () {
var pipe;
return function (value) {
pipe = [];
return Object.create(Proxy.create({
get: function (pipeObject, fnName) {
if (fnName == "get")
return pipe.reduce(function (val, fn) { return fn(val); }, value);
pipe.push(window[fnName]);
return pipeObject;
}
}));
}
}());
var double = function (n) { return n*2 },
pow = function (n) { return n*n },
reverseInt = function (n) { return n.toString().split('').reverse().join('')|0 };
var pipedExample = pipe(3) . double . pow . reverseInt . get
console.log(pipedExample); //63
Well that’s cool, but how far can you take it?
As far as overloading getters on objects allows us, which is pretty far.
Using Proxies I was able to create a query like syntax for filtering repositories represented in JSON.
Here is the result:
var ChristmasList = Repository([
{
name: "Daniel",
age: 12,
wants: "a dog",
},
{
name: "Julia",
age: 8,
wants: "a bottle of rum"
},
{
name: "Vitaly",
age: Infinity,
wants: "a dog"
},
{
name: "Ina",
age: 20,
wants: "Vitaly"
}
]);
ChristmasList.wants['a dog'].get; // [ {age: 12, name: "Daniel",wants: "a dog"}, {age: Infinity, name: "Vitaly", wants: "a dog"} ]
ChristmasList.age['<']['12'].get; // {name: "Julia", age: 8, wants: "a bottle of rum"}
ChristmasList.wants['a dog'].age[">"]["12"].get; // {name: "Vitaly", age: Infinity, wants: "a dog"};
ChristmasList.wants[
ChristmasList.wants['a dog'].age[">"]["12"].get.name
].get // {name: "Ina", age: 20, wants: "Vitaly"}
For the implementation that allowed the code above to happen, feel free to check the Github repository.
Don’t forget to star it and feel free to fork it (: