3
var a = "foo";
var c = Array.prototype.join.call( a, "-" ); // 'f-o-o'

How does the second line of code work? I don't see any conversion of the string to an array and then converting back again, is this happening in the background? I've encountered this kind of code and it's very weird, an array method accepting a string.

Tony_Henrich
  • 42,411
  • 75
  • 239
  • 374
daremkd
  • 8,244
  • 6
  • 40
  • 66
  • NB: Array methods like splice(),reverse(),sort() etc. which modify the array in place will NOT work for strings because strings are immutable – Danield Nov 29 '15 at 13:25

3 Answers3

5

See the specification for Array.prototype.join (below). It doesn't require that the this it's operating on be an array, merely that it have a length and properties with names like 0, 1, and so on. Strings do, and so join can work on a string.

From the spec:

NOTE 2 The join function is intentionally generic; it does not require that its this value be an Array object. Therefore, it can be transferred to other kinds of objects for use as a method.

Here's the full algorithm from the spec:

  1. Let O be ToObject(this value).
  2. ReturnIfAbrupt(O).
  3. Let len be ToLength(Get(O, "length")).
  4. ReturnIfAbrupt(len).
  5. If separator is undefined, let separator be the single-element String ",".
  6. Let sep be ToString(separator).
  7. ReturnIfAbrupt(sep).
  8. If len is zero, return the empty String.
  9. Let element0 be Get(O, "0").
  10. If element0 is undefined or null, let R be the empty String; otherwise, let R be ToString(element0).
  11. ReturnIfAbrupt(R).
  12. Let k be 1.
  13. Repeat, while k < len
    1. Let S be the String value produced by concatenating R and sep.
    2. Let element be Get(O, ToString(k)).
    3. If element is undefined or null, let next be the empty String; otherwise, let next be ToString(element).
    4. ReturnIfAbrupt(next).
    5. Let R be a String value produced by concatenating S and next.
    6. Increase k by 1.
  14. Return R.
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Is this for all non-destructive array methods? For example: https://gist.github.com/dare05/1feabb110d24676167b3 also can work with a string. It seems that at the beginning, it does an internal .split('') before applying the function to each string. – daremkd Nov 29 '15 at 10:46
  • @daremkd: Most of the array methods are intentionally generic. Many methods on other built-in prototypes are as well. If you search the spec for "intentionally generic" (they're very consistent with their phrasing on this :-) ) you'll find a *bunch* (including `Array.prototype.map`). – T.J. Crowder Nov 29 '15 at 10:47
  • @daremkd: See also the "array-like objects" part of [this answer](http://stackoverflow.com/questions/9329446/for-each-over-an-array-in-javascript/9329476#9329476). – T.J. Crowder Nov 29 '15 at 10:53
4

A string is an Array like object, because it has the property length and you can access its elements (chars) using [] as of that you can apply most of the array manipulation operations on it.

The Function.prototype.call() calls the function given function with using the first parameter as this and the flowing one as normal parameters.

As of that Array.prototype.join.call(a, "-") will call the function join on the object a in you case the string.

Tony_Henrich
  • 42,411
  • 75
  • 239
  • 374
t.niese
  • 39,256
  • 9
  • 74
  • 101
3

String is array-like object. An array-like object provides indexed access to elements and the property length. You can read more here

  • Yes but a string does not behave like an array in a sense that strings are non-mutable and arrays are. Thus, is it possible to use all nonmutable array methods on a string? – daremkd Nov 29 '15 at 10:48
  • You can use mutable methods(push, sort, reverse...), but string will not change its value. And, of course, you can use any nonmutable methods – Ruslan Abelharisov Nov 29 '15 at 10:53
  • @daremkd: ...because `str = "123"; str[0] = 'x'; console.log(str);` shows `123`, not `x23`. Even `str = new String("123"); str[0] = 'x'; console.log(str);` does. Assigning to a string's index-style properties is a no-op, those properties aren't writable. – T.J. Crowder Nov 29 '15 at 10:54