Why doesn't .join() work with function arguments?
Why does this work (returns "one, two, three"):
var words = ['one', 'two', 'three'];
$("#main").append('<p>' + words.join(", ") + '</p>');
and this work (returns "the list: 111"):
var displayIt = function() {
return 'the list: ' + arguments[0];
}
$("#main").append('<p>' + displayIt('111', '222', '333') + '</p>');
but not this (returns blank):
var displayIt = function() {
return 'the list: ' + arguments.join(",");
}
$("#main").append('<p>' + displayIt('111', '222', '333') + '</p>');
What do I have to do to my "arguments" variable to be to use .join() on it?
It doesn't work because the arguments
object is not an array, although it looks like it. It has no join
method:
>>> var d = function() { return '[' + arguments.join(",") + ']'; }
>>> d("a", "b", "c")
TypeError: arguments.join is not a function
To convert arguments
to an array, you can do:
var args = Array.prototype.slice.call(arguments);
Now join
will work:
>>> var d = function() {
var args = Array.prototype.slice.call(arguments);
return '[' + args.join(",") + ']';
}
>>> d("a", "b", "c");
"[a,b,c]"
Alternatively, you can use jQuery's makeArray
, which will try to turn "almost-arrays" like arguments
into arrays:
var args = $.makeArray(arguments);
Here's what the Mozilla reference (my favorite resource for this sort of thing) has to say about it:
The
arguments
object is not an array. It is similar to an array, but does not have any array properties exceptlength
. For example, it does not have the pop method. ...The
arguments
object is available only within a function body. Attempting to access the arguments object outside a function declaration results in an error.
If you are not interested on other Array.prototype
methods, and you want simply to use join
, you can invoke it directly, without converting it to an array:
var displayIt = function() {
return 'the list: ' + Array.prototype.join.call(arguments, ',');
};
Also you might find useful to know that the comma is the default separator, if you don't define a separator, by spec the comma will be used.
You could use this jQuery .joinObj Extension/Plugin I made.
As you'll see in that fiddle, you can use it as follows:
$.joinObj(args, ",");
or
$.(args).joinObj(",");
Plugin Code:
(function(c){c.joinObj||(c.extend({joinObj:function(a,d){var b="";if("string"===typeof d)for(x in a)switch(typeof a[x]){case "function":break;case "object":var e=c.joinObj(a[x],d);e!=__proto__&&(b+=""!=b?d+e:e);break;default:"selector"!=x&&"context"!=x&&"length"!=x&&"jquery"!=x&&(b+=""!=b?d+a[x]:a[x])}return b}}),c.fn.extend({joinObj:function(a){return"object"===typeof this&&"string"===typeof a?c.joinObj(this,a):c(this)}}))})(jQuery);
Just use the jQuery utility function makeArray
arguments
is not an Array, it is an object. But, since it so "array-like", you can call the jQuery utility function makeArray
to make it work:
var displayIt = function() {
return 'the list: ' + $.makeArray(arguments).join(",");
}
$("#main").append('<p>' + displayIt('111', '222', '333') + '</p>');
Which will output:
<p>the list: 111,222,333</p>
At the moment you can't join array arguments, because they aren't an array, shown here
so you have to either first turn them into an array like this,
function f() {
var args = Array.prototype.slice.call(arguments, f.length);
return 'the list: ' + args.join(',');
}
or like this, a bit shorter
function displayIt() {
return 'the list: ' + [].join.call(arguments, ',');
}
if you are using something like babel or a compatible browser to use es6 features, you can also do this using rest arguments.
function displayIt(...args) {
return 'the list: ' + args.join(',');
}
displayIt('111', '222', '333');
which would let you do even cooler stuff like
function displayIt(start, glue, ...args) {
return start + args.join(glue);
}
displayIt('the start: ', '111', '222', '333', ',');