Splats...
Sometimes when developing a function we are not sure just how many arguments we are going to need. Sometimes we might get one argument, other times we might get a hundred. To help us easily solve this problem CoffeeScript gives us the option of using splats when defining the argument list for a function. Splatted arguments are denoted by placing ... after the method definition.
When would you use splats? Splats can be used whenever your function will be taking in a variable number or arguments. Before we take a look at a detailed example, let’s look quickly at a simple function that takes a splatted argument:
Example: (source: splats.coffee)
splatter = (etc...) -> console.log "Length: #{etc.length}, Values: #{etc.join(', ')}" splatter() splatter("a", "b", "c")
Example: (source: splats.js)
(function() { var splatter, __slice = Array.prototype.slice; splatter = function() { var etc; etc = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return console.log("Length: " + etc.length + ", Values: " + (etc.join(', '))); }; splatter(); splatter("a", "b", "c"); }).call(this);
Output: (source: splats.coffee)
Length: 0, Values: Length: 3, Values: a, b, c
As you can see, whatever arguments we pass into our function will automatically get put into an array and should we not send any arguments we simply get an empty array.
Unlike other languages that support a similar construct CoffeeScript, does not force you to only use splats as the last argument in the argument list. In fact, splatted arguments can appear anywhere in your argument. A small caveat to that is that you can only have one splatted argument in the argument list.
To help illustrate how splats can be used in any part of the argument list let’s write a method that will take some arguments and spit out a string. When building this string we make sure that the first and last arguments are uppercased; any other arguments will be lowercased. Then we’ll concatenate the string using forward slashes.
Example: (source: splats_arg_join.coffee)
joinArgs = (first, middles..., last) -> parts = [] if first? parts.push first.toUpperCase() for middle in middles parts.push middle.toLowerCase() if last? parts.push last.toUpperCase() parts.join('/') console.log joinArgs("a") console.log joinArgs("a", "b") console.log joinArgs("a", "B", "C", "d")
Example: (source: splats_arg_join.js)
(function() { var joinArgs, __slice = Array.prototype.slice; joinArgs = function() { var first, last, middle, middles, parts, _i, _j, _len; first = arguments[0], middles = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), last = arguments[_i++]; parts = []; if (first != null) parts.push(first.toUpperCase()); for (_j = 0, _len = middles.length; _j < _len; _j++) { middle = middles[_j]; parts.push(middle.toLowerCase()); } if (last != null) parts.push(last.toUpperCase()); return parts.join('/'); }; console.log(joinArgs("a")); console.log(joinArgs("a", "b")); console.log(joinArgs("a", "B", "C", "d")); }).call(this);
Output: (source: splats_arg_join.coffee)
A A/B A/b/c/D
Ok, I admit that is a bit of a heavy example, but it illustrates how splats work. When we call the joinArgs function the first argument we pass into the function call gets assigned to the first variable, the last argument we pass in get assigned to the last variable, and if there are any other arguments passed in between the first and the last arguments then those are put into an array and assigned to the middles variable.
Finally, when dealing with splats you might have an array that you would like to passed in as individual arguments. That is possible.
Let’s take a quick look at an example:
Example: (source: splats_array.coffee)
splatter = (etc...) -> console.log "Length: #{etc.length}, Values: #{etc.join(', ')}" a = ["a", "b", "c"] splatter(a) splatter(a...)
Example: (source: splats_array.js)
(function() { var a, splatter, __slice = Array.prototype.slice; splatter = function() { var etc; etc = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return console.log("Length: " + etc.length + ", Values: " + (etc.join(', '))); }; a = ["a", "b", "c"]; splatter(a); splatter.apply(null, a); }).call(this);
Output: (source: splats_array.coffee)
Length: 1, Values: a,b,c Length: 3, Values: a, b, c
Using our splatter example from earlier we can try first passing in an array, but as you can see the splatter function sees the array as a single argument, because that is what it is. However, if we append ... to the array as we pass it into our function call, the CoffeeScript will split up the array into separate arguments and pass them into the function.