Introducción

Dentro de las numerosas “mejoras” que provee CoffeeScript con respecto a JavaScript plano, podemos mencionar el operador `splat` (nombre que toma de Ruby) también conocido como `spread`, que básicamente permite agrupar los argumentos que excedan los declarados en la firma del método/función en un único argumento en forma de lista (un array en JavaScript, para ser más preciso).

Un ejemplo sencillo se puede observar en el siguiente ejemplo dela documentación de CoffeeScript, donde runners:

race = (winner, runners...) ->
  console.log winner, runners

race "foo", "bar", "baz", "me" # foo ["bar", "baz", "me"]

La sintaxis varía de lenguaje a lenguaje, teniendo algunas diferencias, como el hecho que algunos solo soportan el operador como último argumento. Algunas breves muestras:

CoffeeScript

test = (...args) ->
	#...

Ruby

def test(*rest)
	#...
end

Java

void test (int ... numbers) {
	//...
}

ActionScript3+

function test(... args):void
{
	// ...
}

Por lo general, el uso de este operador suele darse en el último argumento de las funciones, siendo las mismas de la forma:

fun(arg1, arg2, ...splat)

Que básicamente equivale a:

fun(arg1, arg2[, item[, item[, ...]]])

Por suerte, este comportamiento no está limitado al caso expuesto, sino que podemos aplicar dicho operador a argumentos intermedios, de la forma:

fun(arg1, ...splat, arg2, arg3)

Que equivale a:

fun(arg1, [item[, item[, ...,]]] arg2, arg3)

Dicha forma aplicará la firma dependiendo la cantidad que reciba

fun(1, 2) -> 1, void, 2, void
fun(1, 2, 3) -> 1, void, 2, 3
fun(1, 2, 3, 4) -> 1, [2], 3, 4
fun(1, 2, 3, 4, 5) -> 1, [2, 3], 4, 5
fun(1, 2, 3, 4, 5, 6) -> 1, [2, 3, 4], 5, 6

Desgraciadamente en JavaScript no tenemos este magnifico feature de forma nativa (todavía…), y si bien podemos emularlo, el resultado es bastante más engorroso de lo deseable.

Implementación

Para implementar este tipo de funcionalidad, basta con echar mano a los function decorators, tema del cual se hablo con anterioridad en este blog. La idea del function decorator es crear una función que envuelva a otras, alterando o no el proceso de entrada/salida de la misma.

Nuestro decorator inicial se corresponderia con el siguiente caso de uso (limitado al último argumento):

function splatify(fn) {
	// implementacion
}

function race(winner, runners) {
	console.log(winner, runners);
}

var splattedRace = splatify(race);

race(1, 2, 3, 4); // 1, 2
splattedRace(1, 2, 3, 4); // 1, [2, 3, 4]

Para llevar a cabo esta simple implementación, vamos a echar mano a la propiedad `length` del objeto Function, que nos dice cuantos argumentos espera la función.

Nuestro decorador recibe la función, la envuelve con otra que genera los nuevos argumentos y la devuelve lista para usar:

function splatify(fn) {
	return function() {
		// Convertimos el objeto arguments en un array
		var args = [].slice.call(arguments);

		// En esta version simplificada utilizamos siempre
		// el ultimo argumento
		var index = fn.length - 1;

		// Nuestros nuevos argumentos, completamos todos los
		// argumentos, menos el ultimo
		var splattedArguments = args.slice(0, index);

		// Y completamos el ultimo con el resto
		splattedArguments = splattedArguments.concat([ args.slice(index) ]);

		// Finalmente ejecutamos la funcion con los nuevos
		// argumentos
		return fn.apply(this, splattedArguments)
	}
}

Esta implementación es bastante simple, pero sería mejor si tuviese soporte para splats en cualquier posición, lo cual modifica un poco la sintaxis final:

function splat(fn) {
	// implementacion
}

var splattedRace = splat(race).byName('winner');
splattedRace(1, 2, 3, 4); // [1, 2, 3], 4

// O agregando la funcion al Function#prototype
Function.prototype.splat = function(target) {
	return splat(this)(target);
};

race.splat(-1)(1, 2, 3, 4); // 1, [2, 3, 4]

Esta implementación la dejo directamente en GitHub, disponible para toda aquella persona que quiera ver y criticar:

Splat.js en GitHub (Gist)

Hace ya un tiempo, publiqué este pequeño snippet de código para generar namespaces desde strings:

function namespace(path, root) {
    // valor por defecto
    root = root || this;

    var
        parts = path.split("."),
        l = parts.length,
        leaf;

    for(i = 0; i < l; i++) {
        leaf = parts[i];

        if(!root[leaf]) {
            root[leaf] = {};
        }

        root = root[leaf]
    }

    return root;
}

Refactor mediante, dicho snippet se puede reducir en gran manera gracias al fabuloso método Array#reduce:

function namespace(path, root) {
	return path.split('.').reduce(function(memo, current) {
		return memo[current] || (memo[current] = {});
	}, root || this);
};

El caso de uso es similar al snippet anterior:

namespace('foo');
foo; // Object {}

// El ultimo eslabon esta disponible
namespace('foo.bar.baz.bax').value = 1;
foo.bar.baz.bax.value; // 1

Obviamente (y como el título indica), este snippet es válido para todas los entornos que implementen Ecma-262 en su versión 5 o posterior (esto excluye a IE < 9).

JSConf.ar

Gracias a la organización de Guillermo Rauch (learnboost.com, Socket.io, Express, etc), el 19 y 20 del mes de mayo tendremos entre nosotros la JSConf.ar. Esta conferencia (como bien se puede adivinar) tendrá charlas relacionadas a JavaScript y todo su entorno inmediato (HTML5, node.js, mobile, etc).

Con algo de suerte, tendremos entre los speakers locales a figuras como el propio Guillermo, Maximiliano Firtman (mobilexweb.commobilehtml5.org, Programming the Mobile Web, etc), Nicolas Garcia Belmonte (thejit.org, Sencha, etc), Andres Pagella (Making Isometric Social Real-Time Games using HTML5, CSS3 and JavaScript).

Por el momento, habrá traducción en vivo para las charlas:

Traducciones en vivo

Este evento de dos días tendrá sede en el Centro Metropolitano de Diseño, ubicado en el sur de la ciudad de Buenos Aires:

Centro Metropolitano de Diseño

Esperemos que pronto haya novedades sobre los tickets y speakers así como también que la concurrencia haga justicia a este gran evento.

Leer más:

 

WTFs/mVisto en Clean Code: A Handbook of Agile Software Craftsmanship (Robert C. Martin)

Siendo ya una semana desde que deje de trabajar en Ienter, me gustaría plasmar el agradecimiento para algunas personas con las cuales traté los últimos (casi) tres años.Ienter - Internet Solutions

Me gustaría agradecerle al equipo de desarrollo, por ayudarme a crecer como persona y profesional, ya sea directa o indirectamente. Espero no olvidarme de nadie, gracias Nicolás, Diego, Francisco, Patricio, Alejandro, Jorge, Adrián, Maximiliano y Daniel.
Espero encontrar un grupo de gente no menos apasionada que ustedes, donde aprender sea parte del día a día. Y que ustedes encuentren gente que valore el esfuerzo, capacidad y compromiso que llevan.

Gracias totales.

  • Buscar

  • Ultimos Twits

  • Por fecha

    • 2012 (5)
    • 2011 (63)
    • 2010 (13)
  • Tags

  • Documentacion Javascript

    JavaScript Reference, JavaScript Guide, JavaScript API, JS API, JS Guide, JS Reference, Learn JS, JS Documentation