Reputation:
I came across a javascript puzzle asking:
Write a one-line piece of JavaScript code that concatenates all strings passed into a function:
function concatenate(/*any number of strings*/) {
var string = /*your one line here*/
return string;
}
@ meebo
Seeing that the function arguments are represented as an indexed object MAYBE an array, i thought can be done in a recursive way. However my recursive implementation is throwing an error. --"conc.arguments.shift is not a function" --
function conc(){
if (conc.arguments.length === 0)
return "";
else
return conc.arguments.shift() + conc(conc.arguments);
}
it seems as though conc.arguments is not an array, but can be accessed by a number index and has a length property??? confusing -- please share opinions and other recursive implementations.
Thanks
Upvotes: 6
Views: 7676
Reputation: 3735
It works with at least 6 different methods of Array.prototype
(I suspect there are more), namely join
, slice
, splice
, concat
, reduce
, flat
. Probably the shortest way is using join
, which is @svinto's solution above. g
is identical to @GeorgSchölly's answer.
Voilà the six solutions:
function f(){
return [].join.call(arguments,'');
}
function g(){
return [].slice.call(arguments).join('');
}
function h(){
return [].splice.call(arguments,0).join('');
}
function i(){
return [].concat.apply([], arguments).join('');
}
function j(){
return [].reduce.call(arguments,function(buff,x){return buff+x},'');
}
function k(){
return [].flat.call(arguments).join('');
}
document.getElementById('F').textContent = f('a','b','c');
document.getElementById('G').textContent = g('a','b','c');
document.getElementById('H').textContent = h('a','b','c');
document.getElementById('I').textContent = i('a','b','c');
document.getElementById('J').textContent = j('a','b','c');
document.getElementById('K').textContent = k('a','b','c');
<pre id='F'></pre>
<pre id='G'></pre>
<pre id='H'></pre>
<pre id='I'></pre>
<pre id='J'></pre>
<pre id='K'></pre>
Upvotes: 0
Reputation: 179169
arguments
is said to be an Array-like object. As you already saw you may access its elements by index, but you don't have all the Array methods at your disposal. Other examples of Array-like objects are HTML collections returned by getElementsByTagName() or getElementsByClassName(). jQuery, if you've ever used it, is also an Array-like object. After querying some DOM objects, inspect the resulting jQuery object with Firebug in the DOM tab and you'll see what I mean.
Here's my solution for the Meebo problem:
function conc(){
if (arguments.length === 0)
return "";
else
return Array.prototype.slice.call(arguments).join(" ");
}
alert(conc("a", "b", "c"));
Array.prototype.slice.call(arguments)
is a nice trick to transform our arguments
into a veritable Array object. In Firefox Array.slice.call(arguments)
would suffice, but it won't work in IE6 (at least), so the former version is what is usually used. Also, this trick doesn't work for collection returned by DOM API methods in IE6 (at least); it will throw an Error. By the way, instead of call
one could use apply
.
A little explanation about Array-like objects. In JavaScript you may use pretty much anything to name the members of an object, and numbers are not an exception. So you may construct an object that looks like this, which is perfectly valid JavaScript:
var Foo = {
bar : function() {
alert('I am bar');
},
0 : function() {
alert('I am 1');
},
length : 1
}
The above object is an Array-like object for two reasons:
length
property, without which you cannot transform the object into a veritable Array with the construct: Array.prototype.slice.call(Foo);
The arguments object of a Function object is pretty much like the Foo object, only that it has its special purpose.
Upvotes: 13
Reputation: 12478
This works:
function concatenate(){
return [].join.call(arguments, "");
}
alert(concatenate("one", "two", "three"));
Upvotes: 6
Reputation: 655499
You could do this:
function concatenate() {
if (arguments.length > 1) {
return arguments[0] + concatenate.apply(this, Array.prototype.splice.call(arguments, 1));
}
return arguments[0];
}
Upvotes: 1
Reputation: 126145
The arguments object is not an array. It is similar to an array, but does not have any array properties except length. For example, it does not have the pop method. However it can be converted to an real array:
var args = Array.prototype.slice.call(arguments);
Therefore the solution to your problem is fairly simple:
var string = Array.prototype.slice.call(arguments).join("");
BTW: It further states:
The arguments object is a local variable available within all functions; arguments as a property of Function can no longer be used.
You should only use arguments
instead of func.arguments
Upvotes: 7
Reputation: 86276
The arguments list is not a genuine array. I think you can borrow the array methods and use them on arguments with "call" or "apply."
Upvotes: 1