Skip to content

Instantly share code, notes, and snippets.

@mikaelbr
Last active July 7, 2017 12:38
Show Gist options
  • Save mikaelbr/94dc42234e226676f4567c3ecdc63c66 to your computer and use it in GitHub Desktop.
Save mikaelbr/94dc42234e226676f4567c3ecdc63c66 to your computer and use it in GitHub Desktop.
Playing with JavaScript Proxies, implementing multi-methods
const fib = multiMethod();
fib[0] = 0;
fib[n => n <= 1] = 1;
fib[_ => true] = (n) => fib(n-1) + fib(n-2);
console.log(fib(20));
//=> 6765
function multiMethod () {
let predicates = [];
const handler = {
get: function (target, name) {
if (name in target) return target[name];
for (var i = 0; i < predicates.length; i++) {
const { result, value } = predicates[i](name);
if (result) return value;
}
},
set: function (target, name, value) {
const fn = getCompiledFunction(name);
if (typeof fn !== 'function') {
target[name] = value;
return;
}
predicates = predicates.concat((key) => ({
result: fn(key),
value: value
}));
}
};
var proxied = new Proxy(function getValue (n) {
var val = proxied[n];
if (typeof val === 'function') {
return val(n);
}
return val;
}, handler);
return proxied;
}
function getCompiledFunction (key) {
try {
return eval(key);
} catch (ex) {
}
}
const fib = multiMethod();
fib.when(0, 0)
.when(n => n == 1, 1)
.when(_ => true, n => fib(n-1) + fib(n-2));
console.log(fib(20));
//=> 6765
function multiMethod () {
let predicates = [];
function getValue (name) {
for (var i = 0; i < predicates.length; i++) {
const { result, value } = predicates[i](name);
if (!result) continue;
if (typeof value === 'function') return value(name);
return value;
}
}
getValue.when = function (fn, val) {
if (typeof fn !== 'function') {
const scalar = fn;
fn = (key) => key == scalar;
}
predicates = predicates.concat((key) => ({
result: fn(key),
value: val
}));
return getValue;
}
return getValue;
}
// Functions x 549 ops/sec ±5.04% (73 runs sampled)
// Proxy x 66.98 ops/sec ±4.32% (66 runs sampled)
// Fastest is Functions
const Benchmark = require('benchmark');
const m1 = require('./multi-method-proxy');
const m2 = require('./multi-method-functions');
const suite = new Benchmark.Suite;
suite.add('Functions', function() {
const fib = m2();
fib.when(0, 0)
.when(n => n == 1, 1)
.when(_ => true, n => fib(n-1) + fib(n-2));
fib(20);
})
.add('Proxy', function() {
const fib = m1();
fib[0] = 0;
fib[n => n <= 1] = 1;
fib[_ => true] = (n) => fib(n-1) + fib(n-2);
fib(20);
})
.on('cycle', function (event) {
console.log(String(event.target));
})
.on('complete', function () {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
.run({ 'async': true });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment