Skip to content

Instantly share code, notes, and snippets.

@adityavm
Last active February 17, 2018 16:43
Show Gist options
  • Save adityavm/11784b33e29e52fa72349f92e95b7de4 to your computer and use it in GitHub Desktop.
Save adityavm/11784b33e29e52fa72349f92e95b7de4 to your computer and use it in GitHub Desktop.
How to build properties that can be called or chained
/**
* Executors
* ---
* These perform the final action at each step of the chain.
*/
const keys = Object.create(null);
keys.red = function(str) { return `red(${str})`; },
keys.red.type = "red";
keys.blue = function(str) { return `blue(${str})`; };
keys.blue.type = "blue";
keys.yellow = function(str) { return `yellow(${str})`; };
keys.yellow.type = "yellow";
/**
* Module
* ---
* This exports a module the properties of which can be chained or called.
*/
// Initialise module
function Module(){};
Module.q = [];
// Build chain
function Chain(q, key) {
// Calling this ends the chain
function execute(str) {
q.push(keys[key](str));
return q.join(",");
}
// Otherwise add new value to chain, and pass on
execute.q = [...q, key];
return execute;
}
// Define properties. Each property is callable, but also has
// a circular prototype to initial keys
const init = {};
for(const key of Object.keys(keys)) {
init[key] = {
get(){
const self = this; // keep context so the chain remains
function fn3(){ return Chain(self.q, key); } // add this call's properties in the chain
fn3.__proto__ = init; // create circular properties to allow chaining
return fn3(); // build a link in the chain
}
};
}
Object.defineProperties(Module.__proto__, init); // Assign first layer of properties to module
module.exports = Module;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment