# Fewer Lambdas in D3.js: How to type less and make your code simpler.

posted 2012-Feb-29

In D3.js you see a lot of functions that take an argument and return a property or method invocation on that argument, or even just the argument itself. Calls that look like this:

.data(function(d) { return d; })
.attr('title', function(d) { return d.value; })
.text(function(d) { return d.toFixed(); })


Rubyists have the sweet Symbol#to_proc method for converting a symbol into a function that accesses that method/property; they could write the latter two as:

.attr('title',&:value)
.text(&:toFixed)


We can make similar—and even more powerful—shortcuts in JavaScript so that our D3 code is easier to type, easier to read, and easier to maintain.

// Create a function that returns a particular property of its parameter.
// If that property is a function, invoke it (and pass optional params).
function ƒ(name){
var v,params=Array.prototype.slice.call(arguments,1);
return function(o){
return (typeof (v=o[name])==='function' ? v.apply(o,params) : v );
};
}

// Return the first argument passed in
function I(d){ return d }


Note that the name of the first function—ƒ—is a legal JavaScript identifier that is also easy-to-type on OS X (option-f) and unlikely to collide with other names.

With this the original code can be written far more simply:

.data(I)
.attr('title', ƒ('value'))
.text(ƒ('toFixed'))       // round to integer
.text(ƒ('toFixed',2))     // round to 2 decimal places

 Gavin Kistner 05:13PM ET2012-May-21 Note that if you just want to round a number to the nearest integer you can more simply use .text(Math.round). David Turgeon 09:24PM ET2013-Dec-27 This function combines both ƒ & I doing double-duty. It also allows an args array override and tolerates missing names. function F(name) { var args, prop; args = Array.prototype.slice.call(arguments, 1); return function (obj, arr) { prop = obj && name ? obj[name] : obj; arr = arr && arr.length ? arr : args; return (typeof prop === 'function' ? prop.apply(obj, arr) : prop); }; } var test; test = F('toFixed', 2); test(3.6) === “3.60”; test = F('toFixed'); test(3.6) === “4” && test(3.6, [1]) === “3.6”; test = F('console'); test(window) === window.console && test(window.console) === undefined; function mock() { var args = Array.prototype.slice.call(arguments); return 'STUB' + (args[0] ? ':' + args : ''); } test = F(); test(3) === 3 && test(this) === this && test(mock) === 'STUB' && test(mock, [3,4,5]) === 'STUB:3,4,5'; David Turgeon 11:51AM ET2013-Dec-28 Thanks for fixing the code format! (BTW: the double quoted strings got curled on lines 14,17,18 of code block.)