Last active
July 7, 2017 12:38
-
-
Save mikaelbr/94dc42234e226676f4567c3ecdc63c66 to your computer and use it in GitHub Desktop.
Playing with JavaScript Proxies, implementing multi-methods
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) { | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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