The native JavaScript function indexOf , applied to a String, returns the index of the first occurrence of a specified value. Useful as it is, I often find myself wishing for a variant method that will return the index after the occurrence so that I can pass the result to a slice call and return everything after a given character.

With this in mind, I created a method called express (as in expression, and alsoquick) which returns a new function by applying the expression argument to the result of the old function. Its partly inspired by the Haskell language and by Oliver Steele’s lambda function.

String.prototype.indexAfter = String.prototype.indexOf.express('r + 1');

(Note: this returns string.indexOf + 1, not string.indexOf + searchString.length)

The implementation is deceptively simple but packs a lot of power. The expr argument manipulates a variable r which is a proxy for the return value of the original function. I think its a nice illustration of why eval is not always evil – and how when used judiciously it can actually be a good friend. [Edit 05/12/10: Several readers have pointed out that the r reference could break down if you js minify. I’ve since addressed this issue using a minify-safe evalR function, which will always inject the given variable as “r”, no matter what]

//minify-safe version of eval var evalR = function(x, expr) { var expr = expr.replace(/\br\b/g,"arguments[0]"); return eval(expr); } Function.prototype.express = function(expr) { var __method = this; return function() { return evalR(__method.apply(this,arguments), expr); } }

Using express you can create new functions that modify the results of existing functions in almost any conceivable way.

var loudly = String.prototype.toUpperCase.express('"** " + r + "!! **"'); loudly.call("Can you hear me?"); //"** CAN YOU HEAR ME?!! **" var randomPercentage = Math.random.express('Math.round(100*r) + "%"'); randomPercentage(); //23% isPerfectSquare = Math.sqrt.express('r == Math.round(r)'); isPerfectSquare(25) //true

Keep in mind that when there is already an existing function that will perform the required modification, compose might be a better option (especially if you’re skittish about eval). What do you think?

//using express var roundedSqrt = Math.sqrt.express('Math.round(r)'); roundedSqrt(34); //6 //using compose var roundedSqrt = Math.round.compose(Math.sqrt); roundedSqrt(34); //6

I also created a global express function in which the expression is not applied to a function result but instead manipulates the first argument directly.

var express = function(expr) { return function() { return evalR(arguments[0], expr); } } var inverse = express('1/r'); inverse(5); //0.2 var toFarenheit = express('(r*9/5)+32'); toFarenheit(10); //50 var circleArea = express('Math.PI*r*r'); circleArea(4).toFixed(2); //50.27

As with any technique, its easy to overdo it. I wouldn’t necessarily recommend using global express in production code (its perfectly robust but your team might not appreciate the unfamiliar syntax or reliance on eval). However it does illustrate the beauty of the functional approach, moreover it’s an excellent aid in debugging, testing and experimentation on the console.

Now lets go back to the indexAfter method we defined at the beginning. Here’s a nifty example that combines compose, curry and express to define a function that will extract the domain part of an email address.

var domainFromEmail = String.prototype.slice.compose( String.prototype.indexOf.express('r+1') ).curry('@'); domainFromEmail.call("president@whitehouse.gov"); //"whitehouse.gov" domainFromEmail.call("mmouse@disney.com"); //"disney.com"

To me this is the height of elegance. Pure functional programming. However its worth pointing out that at this point its actually no more concise than the old fashioned way:-

var domainFromEmail = function(email) { return email.slice(email.indexOf('@') + 1); } domainFromEmail("president@whitehouse.gov"); //"whitehouse.gov" domainFromEmail("mmouse@disney.com"); //"disney.com"

It’s a matter of preference and balance. Use the implementation that is the most expressive for you and allows for the most re-use, and be careful not to overuse any one technique.

Speaking of re-use let’s end by defining a generic function that returns everything after a character. Its useful enough to add to String prototype:-

String.prototype.sliceAfterChar = String.prototype.slice.compose(String.prototype.indexOf.express('r+1')); var domainFromEmail = String.prototype.sliceAfterChar.curry('@'); var queryParams = String.prototype.sliceAfterChar.curry('?'); //assumes we don't want '?'