Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's an example on how you could make any object methods chainable dynamically.</p> <p>Calling <code>chainable(obj)</code> will internally create a new object that exposes the same API as <code>obj</code>, however every function will now return that new object which in turns allow chaining. If you want to call a function and get the raw result of that function, you can call <code>endChain()</code>.</p> <p>The following implementation is not very efficient since it has to loop over all members of <code>obj</code>. <strong>A better approach would be to make your methods chainable by returning the current instance (<code>this</code>) from the functions you want to be chainable.</strong></p> <p><a href="http://jsfiddle.net/VxgyA/" rel="nofollow"><strong>DEMO</strong></a></p> <pre><code>var chainable = (function () { function wrapFn(fn, obj) { return function () { var result = this._result = fn.apply(obj, arguments); return this; }; } function Chainable(obj) { var k, v; for (k in obj) { if (typeof (v = obj[k]) !== 'function') continue; this[k] = wrapFn(obj[k], obj); } } Chainable.prototype.endChain = function () { return this._result; }; return function (obj) { return new Chainable(obj); }; })(); var o = { setTest: function (test) { this.test = test; }, getTest: function () { return this.test; } }; console.log(chainable(o).setTest('test').getTest().endChain()); </code></pre> <p>Here's a different implementation that doesn't require to iterate over the object members. However it's less appealing syntaxically and I am not sure that it's more efficient since it has to <code>slice</code> arguments.</p> <p><strong><a href="http://jsfiddle.net/VxgyA/1/" rel="nofollow">DEMO</a></strong></p> <pre><code>var chainable = (function (slice) { var Chainable = { init: function (obj) { this._obj = obj; return this; }, chain: function (fn) { var obj = this._obj; this._result = obj[fn].apply(obj, slice.call(arguments, 1)); return this; }, end: function () { return this._result; } }; return function (obj) { return Object.create(Chainable).init(obj); }; })(Array.prototype.slice); var o = { setTest: function (test) { this.test = test; }, getTest: function () { return this.test; } }; console.log(chainable(o).chain('setTest', 'test').chain('getTest').end()); </code></pre> <p>EDIT:</p> <blockquote> <p>Using and mixing the great examples from @plalx and @Connor, I've managed to get this snippet working, and as you can see, is missing the "chainable part" of @plalx example.</p> </blockquote> <p>You do not need something like <code>chainable</code> if your code <strong>is already written in a way it can be chained (e.g. already returning <code>this</code> from some functions)</strong>. I should have made it more clear. I just wrote the <code>chainable</code> implementation as an example on how chaining works.</p> <p>However, with <code>chainable</code> you can make <strong>any</strong> object chainable, even if none of their functions explicitely return <code>this</code>. It could be useful if you want to use chaining with objects that aren't supporting it through their API.</p> <p>E.g.</p> <pre><code>var o = { fn1: function () { console.log('fn1'); }, fn2: function () { console.log('fn2'); } }; //chainable(o).fn1().fn2(); //other implementation chainable(o).chain('fn1').chain('fn2'); </code></pre> <p><strong>Here's a <a href="http://jsperf.com/dynamic-chain" rel="nofollow">performance test</a> that shows making your object dynamically chainable has a huge negative performance impact. For that reason I wouldn't recommend using that experimental approach.</strong></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload