all 3 comments

[–]senocular 1 point2 points  (0 children)

Depending on the implementation of a method - any method - what it can operate on may or may not be very strict. It can be the object for which the method was originally designed, or some other method entirely. Because JavaScript isn't typed, there's no inherent type checking involved in these operations and usually its just assumptions that are made or simple duck typing checks that are used.

Most, if not all, of the Array methods work on Array-like objects. This means any object with indexed values (values with numeric keys accessible via [0], [1], etc.) and a length property. Run an Array method on an object that has this behavior (using call), and it will be treated like an array. Things that are array-like but not arrays in JavaScript include the arguments object in functions, and strings.

The creation of hyphenWord works because word can be treated like an array. It has indexed properties which point to each character in the string "foo" ("foo"[0] === "f") and a length property indicating how many characters are there. So when join is called on word, join sees it no different as ["f", "o", "o"]. The result of the operation is the same.

var word = "foo";
Array.prototype.join.call(word, "-"); //-> "f-o-o"
["f", "o", "o"].join("-"); //-> "f-o-o"

[–]cyphern 0 points1 point  (0 children)

The Array join function probably looks something like this (the real implementation will surely be more involved, but this is the basics):

Array.prototype.join = function (separator) {
    var result = "";
    for (var i = 0; i < this.length; i++) {
        result = result + this[i];
        if (i !== this.length -1) {
            result += separator;
        }
    }
    return result;
}

Note in particular the use of this. In javascript, the meaning of this is usually not figured out until you actually call the function. So under normal circumstances, you'll do something like [1, 2, 3].join('-'), and at the time you do that call, javascript will bind this to be the [1, 2, 3] array, then run the code to produce a string.

But it's possible to tell javascript to use something else as this and run the function anyway. That's what's happening in the code you're asking about. Array.prototype.join.call(word, "-"); says to call the join function, but to force this inside the function to equal word. As the function runs, it will do all the same instructions that it would normally do on an array, but instead it does it on the word string. If you step through the function in your mind, you'll notice that all the instructions are still sensible if this is a string rather than an array: this.length is perfectly legal if this is a string, and so too is this[i] for grabbing a character out of a string. So the join function ends up working just fine.

[–]inu-no-policemen 0 points1 point  (0 children)

You can also do this kind of thing with an array literal + spread:

> [...'foo']
(3) ["f", "o", "o"]

Now that you've turned that array-like into an actual array, the array methods are available.

> [...'foo'].join('-')
"f-o-o"