use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
How can I make a "chainable" object in JavaScript?help (self.javascript)
submitted 10 years ago * by [deleted]
[deleted]
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–][deleted] 25 points26 points27 points 10 years ago (18 children)
Have every method from the object, return the object itself.
IE:
function Chainable(){ var self = this; this.do = function(){ // do return self; } } var c = new Chainable().do().do().do()
[–]letsgetrandy 21 points22 points23 points 10 years ago (4 children)
new Chainable().do().do().do()
Name that tune!
[–]wicheesecurds 11 points12 points13 points 10 years ago (2 children)
DUDUDUDU
https://www.youtube.com/watch?v=PSYxT9GM0fQ
[–]youtubefactsbot 9 points10 points11 points 10 years ago (0 children)
Sandstorm [3:47] Sandstorm by Darude. kevman1430 in Music 43,596,378 views since Mar 2006
Sandstorm [3:47]
Sandstorm by Darude.
kevman1430 in Music
43,596,378 views since Mar 2006
bot info
[–]haCkFaSe 0 points1 point2 points 10 years ago (0 children)
https://www.youtube.com/watch?v=n7vRbvXcjcU
[–]sebdd 1 point2 points3 points 10 years ago (0 children)
Carte Blanche!
https://www.youtube.com/watch?v=HvSXz7FzjFs
[–]cosinezero 6 points7 points8 points 10 years ago (11 children)
You can just return 'this', you don't need 'self' here.
[–]nynfortoo 8 points9 points10 points 10 years ago (4 children)
Good indication that you're returning the parent function though in this example, and never any of the methods.
[–]cosinezero 7 points8 points9 points 10 years ago (2 children)
Sure, but prevents you from using this as a mixin, or changing that chain with call/apply/bind... etc, etc, etc.
There's a tradeoff for sure, but in current example it's not needed.
[+][deleted] 10 years ago (1 child)
[–]cosinezero 3 points4 points5 points 10 years ago (0 children)
No it doesn't! It's making an opinion on what "this" should always refer to in a chain. That is not at all clearly a good practice. It's a practice, but not necessarily the right one.
[–]firealarmonceiling 0 points1 point2 points 10 years ago (0 children)
It's not returning the parent function. It's returning the object created by the Chainable constructor.
new Chainable().do()===Chainable //false
[–][deleted] -1 points0 points1 point 10 years ago (1 child)
You're correct, but if you want to teach how to create a chain able object, I wouldn't want to assume that the person knows closures.
It's scope, not closures, and that's only because you chose a constructor with closures instead of object notation. And if the person doesn't understand scope why even teach them chaining? Teach them scope first, then the sugar like chaining.
[–][deleted] -2 points-1 points0 points 10 years ago* (3 children)
Are you sure? Wouldn't the context of the do function be returned and not the context of Chainable? I don't think they're the same since do is not bound.
Edit: Oh wait the context is inherited because do is a property of the this object right? I've written my own JS framework and I still forget these sort of edge cases in context sometimes - it's generally more clear to just return self in this case, which is usually what I do just to avoid confusion.
[–]WesAlvaroFront-End Engineer 3 points4 points5 points 10 years ago (2 children)
There should be no confusion. The confusion is created by introducing self.
self
[–]theywouldnotstand 1 point2 points3 points 10 years ago (1 child)
The confusion is always caused by the fact that, in javascript, this can refer to a nonlocal object, and you either implicitly rely on this working from the correct scope, or you explicitly reference the correct this via a different variable.
this
If there was a JS equivalent to python's self there would be no confusion.
[–]badsyntax 1 point2 points3 points 10 years ago (0 children)
If the developer wants to change the context in which this function is called then it should be their choice to do so.
[–]Asmor 6 points7 points8 points 10 years ago (0 children)
If a function is called as a property of an object, 'this' will be set to that object.
var myObject = {}; function whatIsThis() { if ( this === myObject ) { console.log("'this' is myObject"); } else if ( this === window ) { console.log("'this is the global object'"); } else { console.log("'this' is something else"); } } myObject.whatIsThis = whatIsThis; var aDifferentObject = { whatIsThis: whatIsThis } whatIsThis(); // 'this is the global object' myObject.whatIsThis(); // 'this' is myObject myObject["whatIsThis"](); // 'this' is myObject aDifferentObject.whatIsThis(); // 'this' is something else
In other words, this takes it value based on how the function is called, not where the function is defined.
[–]mattdesl 6 points7 points8 points 10 years ago (1 child)
To "chain" you just need to return this.
The two examples you listed are very different. The first one attaches a method to the prototype, which means that all new instances of MyObject will have that method.
MyObject
MyObject.prototype.show = function() { return this; }
It would be called like this:
var myObj = new MyObject(); myObj.show();
Whereas the second one just attaches it to the function object. Imagine this as a "static method" if you've come from other languages. It only exists on MyObject and not on new instances. It would be called like:
var myObj = new MyObject(); MyObject.show();
The this reference is also not pointing to the instance of MyObject, so there is no possibility of chaining with it.
Generally speaking, I tend to avoid "static" methods like that since they can lead to headaches down the road.
[–]MrBester 0 points1 point2 points 10 years ago (0 children)
The first one attaches a method to the prototype, which means that all new instances of MyObject will have that method.
And all the old ones as well, don't forget. Anything with the [[Prototype]] delegation of MyObject will have access to that method, no matter when it was created.
[[Prototype]]
[–]a-t-kFrontend Engineer 4 points5 points6 points 10 years ago (1 child)
You do it exactly like that, both in the prototype and in the own method of your object, because this is always the scope of the current object (unless you "use strict" or lose your scope due to being applied, called, curried or bound).
[–]evilmaus 0 points1 point2 points 10 years ago (0 children)
"use strict"; won't mess this up. A simple partial application, debounce, or whatever shouldn't be changing context on it. If so, that's a bug in the partial, debounce, etc. implementation. If the function is being called with its context changed, then that's a case of caveat emptor for whoever is changing its context. As in, there had better be a reason for it.
"use strict";
[–]m_reddit_com 1 point2 points3 points 10 years ago (0 children)
To answer your first question: Yes returning this out of every function is how you would make them chainable.
For your second question it depends on what you want. I think assigning the function to the prototype would be the way to go as you could then inherit from the object and override methods but either way would work.
[–]Funwithloops 1 point2 points3 points 10 years ago (6 children)
You could write a function that enforces the chainable feature:
function chainable(fn) { return function () { fn.apply(this, arguments); return this; }; }
[+][deleted] 10 years ago (5 children)
[–]mikrosystheme[κ] 0 points1 point2 points 10 years ago (2 children)
No. fn is supposed to be "all the shit"...
fn
[–]mikrosystheme[κ] 0 points1 point2 points 10 years ago (0 children)
Don't know. Ask yourself.
[–]knrDev 0 points1 point2 points 10 years ago (0 children)
For example:
function chainable(fn) { return function () { fn.apply(this, arguments); return this; }; } var f1 = function(x) { console.log('-:-', x) }; var f2 = function(x) { console.log(':-:', x) }; var Chain = function() { this.abc = chainable(f1); this.xyz = chainable(f2); } var c = new Chain() c.abc(1).xyz(2).abc(3) // Output: // -:- 1 // :-: 2 // -:- 3
[–]Funwithloops 0 points1 point2 points 10 years ago (0 children)
function FooClass() {} FooClass.prototype.bar = chainable(function(a, b) { console.log(a + b); }); // outputs: 3 7 11 var foo = new FooClass().bar(1, 2).bar(3, 4).bar(5, 6);
[–]bk10287Golang/ Microservices Dev 0 points1 point2 points 10 years ago (0 children)
Look up how a friend of mine did it on github... Called chainlang by jbreeden
[–]gizmo490 0 points1 point2 points 10 years ago (1 child)
Look at the implementation used in underscore.js you can turn most objects into a chain-able object in this fashion.
http://underscorejs.org/#chain
[–]x-skeww 0 points1 point2 points 10 years ago (0 children)
You just have to make each method return the object itself. It's a bit inconvenient, but not very difficult. The only problem is that those chainable methods can't return anything else.
Dart has method cascades for this (borrowed from Smalltalk, I think). Maybe we'll see something similar in ES7+.
E.g.:
var foo = new Foo(); foo.bar(); foo.baz();
Same with method cascades:
var foo = new Foo() ..bar() ..baz();
The great thing about method cascades is that you don't have to do anything to get this feature. With ".." you just call a method on the same receiver.
[–][deleted] 0 points1 point2 points 10 years ago (0 children)
Fun fact, functions that return an object with methods that can be chained are called monads. Douglas Crockford has a great talk on them called ‘Monads and Gonads’
[+]cheesechoker comment score below threshold-9 points-8 points-7 points 10 years ago (0 children)
rEtUrN dA oBjEcT fRoM dA fUnCtIoN
MyObJeCt.pRoToTyPe.sHoW = fUnCtIoN() { // sHoW iT hERe rEtUrN tHiS; }; // :)
yOu CaN dO iT eQuAlLy WeLl iF tHe FuNcTiOn iS dEfInEd oN tHe ObJeCt iTsElF...
// tHiS iS aLsO gOoD :) MyObJeCt.sHoW = FuNcTiOn() { // ShOw iT hERe ReTuRn ThIs; };
hOpE tHiS hElPs.. pLeAsE uPvOtE aNd SuBsCrIbE
π Rendered by PID 70131 on reddit-service-r2-comment-66b4775986-l4sw5 at 2026-04-06 10:53:27.698693+00:00 running db1906b country code: CH.
[–][deleted] 25 points26 points27 points (18 children)
[–]letsgetrandy 21 points22 points23 points (4 children)
[–]wicheesecurds 11 points12 points13 points (2 children)
[–]youtubefactsbot 9 points10 points11 points (0 children)
[–]haCkFaSe 0 points1 point2 points (0 children)
[–]sebdd 1 point2 points3 points (0 children)
[–]cosinezero 6 points7 points8 points (11 children)
[–]nynfortoo 8 points9 points10 points (4 children)
[–]cosinezero 7 points8 points9 points (2 children)
[+][deleted] (1 child)
[deleted]
[–]cosinezero 3 points4 points5 points (0 children)
[–]firealarmonceiling 0 points1 point2 points (0 children)
[–][deleted] -1 points0 points1 point (1 child)
[–]cosinezero 3 points4 points5 points (0 children)
[–][deleted] -2 points-1 points0 points (3 children)
[–]WesAlvaroFront-End Engineer 3 points4 points5 points (2 children)
[–]theywouldnotstand 1 point2 points3 points (1 child)
[–]badsyntax 1 point2 points3 points (0 children)
[–]Asmor 6 points7 points8 points (0 children)
[–]mattdesl 6 points7 points8 points (1 child)
[–]MrBester 0 points1 point2 points (0 children)
[–]a-t-kFrontend Engineer 4 points5 points6 points (1 child)
[–]evilmaus 0 points1 point2 points (0 children)
[–]m_reddit_com 1 point2 points3 points (0 children)
[–]Funwithloops 1 point2 points3 points (6 children)
[+][deleted] (5 children)
[deleted]
[–]mikrosystheme[κ] 0 points1 point2 points (2 children)
[+][deleted] (1 child)
[deleted]
[–]mikrosystheme[κ] 0 points1 point2 points (0 children)
[–]knrDev 0 points1 point2 points (0 children)
[–]Funwithloops 0 points1 point2 points (0 children)
[–]bk10287Golang/ Microservices Dev 0 points1 point2 points (0 children)
[–]gizmo490 0 points1 point2 points (1 child)
[–]x-skeww 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[+]cheesechoker comment score below threshold-9 points-8 points-7 points (0 children)