Why doesn't .join() work with function arguments?
Asked Answered
K

9

74

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?

Knighthood answered 19/1, 2010 at 4:46 Comment(2)
See: #1425210Lelia
I've amended my answer to take into account your updated question -- specifically, the "what do I have to do to make this work?" part.Goodnight
G
95

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 except length. 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.

Goodnight answered 19/1, 2010 at 4:51 Comment(4)
or Array.join(arguments, ",") (like Array.forEach(arguments, func);)Fagen
what happens when one of your arguments is an object?Communistic
@Fagen TypeError: Object function Array() { [native code] } has no method 'join'Killie
Array.prototype.join.call(arguments, ', ')Balliol
S
23

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.

Stupefaction answered 19/1, 2010 at 5:2 Comment(1)
+1 This is the fastest and safest answer IF all you want is to call join instead of creating a new array. Calling slice just to join will allocate memory when join works on array-like objects as well.Brehm
P
3

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);
Photostat answered 30/3, 2012 at 13:43 Comment(2)
and ... why the -1? this is a working plug that does exactly as asked?Photostat
i hate it too, when people -1 my post without explanatian.. +1 for you.. T^TThorlay
Z
2

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>
Zoometry answered 19/1, 2010 at 4:55 Comment(0)
V
2

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', ',');
Valletta answered 29/9, 2015 at 19:28 Comment(0)
P
1

You can use typeof to see what's happening here:

>>> typeof(['one', 'two', 'three'])
"object"
>>> typeof(['one', 'two', 'three'].join)
"function"
>>> typeof(arguments)
"object"
>>> typeof(arguments.join)
"undefined"

Here you can see that typeof returns "object" in both cases but only one of the objects has a join function defined.

Piotr answered 19/1, 2010 at 5:0 Comment(0)
B
1

I don't know if there's a simple way to convert arguments into an array, but you can try this:

var toreturn = "the list:";
for(i = 0; i < arguments.length; i++)
{
   if(i != 0) { toreturn += ", "; }
   toreturn += arguments[i];
}
Broida answered 19/1, 2010 at 5:4 Comment(0)
N
1

You can also use Array.from and then join() with whatever token you'd like:

function joinArgs() {
  return Array.from(arguments).join(' ');
}

joinArgs('one', 'two', 'three'); // returns 'one two three'
Niello answered 9/5, 2023 at 3:57 Comment(0)
H
0

arguments is not a jQuery object, just a regular JavaScript object. Extend it before you try to call .join(). I think you would write:

return 'the list:' + $(arguments)[0];

(I'm not too familiar with jQuery, only Prototype, so I hope this is not completely bogus.)

Edit: It's wrong! But in his response, Doug Neiner describes what I'm trying to accomplish.

Hannie answered 19/1, 2010 at 4:50 Comment(5)
This isn't quite right; arguments is not an array. Instead, it's an "array-like object".Goodnight
A normal JS Array supports join.Zoometry
if arguments is not an array, how come arguments[0] and arguments[1] give me the correct values passed to the function?Knighthood
Edward: JavaScript objects can respond to [x] like they respond to .foo, it's not something that only array objects can do like in other languages. I think. I have been wrong before ;)Hannie
@Edward Tanguay: Here's a javascript object that is not an array but looks like one: {1:'hello',2:'world',length:2}. Notice that that object only has 3 properties: 1,2 and length. It does not have any methods attached to it. The arguments object is similar, the result of getElementsByTagName is another one.Josh

© 2022 - 2024 — McMap. All rights reserved.