26

Lets imagine function like this:

function foo(x) {
    x += '+';
    return x;
}

Usage of it would be like:

var x, y;
x = 'Notepad';
y = foo(x);
console.log(y); // Prints 'Notepad+'.

I'm looking for a way to create function that's chainable with other functions.

Imagine usage:

var x, y;
x = 'Notepad';
y = x.foo().foo().toUpperCase(); // Prints 'NOTEPAD++'.
console.log(y);

How would I do this?

3 Answers 3

27

Sure, the trick is to return the object once you're done modifying it:

String.prototype.foo = function() {
    return this + "+";
}

var str = "Notepad";
console.log(str.foo().foo().toUpperCase());

http://jsfiddle.net/Xeon06/vyFek/

To make the method available on String, I'm modifying it's prototype. Be careful not to do this on Object though, as it can cause problems when enumerating over their properties.

Sign up to request clarification or add additional context in comments.

11 Comments

it's a good idea to at least check for a property on the native types before adding it, i.e. if ( !('foo' in String.prototype) ) {String.prototype.foo = function() {...} }
If you want to extend an object without breaking the enumeration, use the (semi-modern) Object.defineProperty: Object.defineProperty( String.prototype, {value:function(){ return this+"+"; } } ). By default the enumerable flag is set to false.
@keeganwatkins yes it is :). I assume the OP was only asking about strings as an example, so I kept the warnings to a minimum, but that's a good point.
Good solution, mine was too generic
You can't assign this in a string. Return the result instead. If you need to do multiple operations, store it in a temporary variable and return that instead. For example, var str = this; str += "foo"; return str;
|
11

If I remember correctly, you can use "this" as a context of a function (object it belongs to) and return it to make the function chainable. In other words:

var obj = 
{
    f1: function() { ...do something...; return this;},
    f2: function() { ...do something...; return this;}
}

then you can chain the calls like obj.f1().f2()

Keep in mind, you won't be able to achieve what you are expecting by calling obj.f1().toUpperCase() - it will execute f1(), return "this" and will try to call obj.toUpperCase().

1 Comment

What would be the best practice to add .toUpperCase function?
1

Here's a way to do it without messing with String.prototype, by returning an object similar to a string, with an additional method foo(). However, there are some downsides to this approach related to it not returning an actual string.

// Returns an object similar to a string, with an additional method foo()
function foo(str) {
  return Object.assign(`${str ?? this}+`, {
    foo
  });
}

var str = "Notepad";
console.log(
  "EXAMPLE - foo(str).foo().toUpperCase():",  
  foo(str).foo().toUpperCase()
);

console.log("---");

console.log("Some issues with this solution:");
console.log("typeof foo(str):", typeof foo(str));
console.log("foo(str).foo():", foo(str).foo());

console.log(
  "You may need to use toString() - foo(str).foo().toString():",
  foo(str).foo().toString()
);
.as-console-wrapper { min-height: 100% }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.