Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

The list processing routine map on an array object is very convenient at times. Here's one of the handy ways to use it:

var numarr = [1,2,3,4];
console.log(numarr.map(String))

>>> ["1", "2", "3", "4"]

I took this for granted thus far. Today I was however puzzled by it. What the map function is returning above is an array of strings. We typically pass a function to map as argument. In above case we pass String object. String is implemented inside the Javascript implementation, so I don't know what kind of specialities it has. The above code works as if a new instance of String is created for each item in array.

If it's not clear, consider this. If I decide to implement an object in Javascript say MyString and pass it to map, I won't get the above behavior.

function MyString(x) { this.val = x; }

MyString.prototype.toString = function () { return String(this.val); };

var ms = new MyString(4)

console.log(String(ms));
>>> "4"

var arr = [1,2,3];
arr.map(MyString)
>>> [undefined, undefined, undefined]

Does anyone know why then arr.map(String) works the way it does?

share|improve this question
4  
Did you see what typeof String returns? "If I decide to implement an object in Javascript say MyString [...]": MyString is a function too! But it shows undefined because you are not returning anything form it. – Felix Kling 25 mins ago

3 Answers

Array.map returns an array whose elements are the value returned by applying the specified function to each value in the this array. String is a function; it returns a string. That's all there is to it.

share|improve this answer
Functions are always first-class Javascript objects: a function is a function object. You can also run the same trick on the other javascript "types": Array, Date, Number, Boolean, Object. – thefrontender 27 mins ago
@thefrontender: What's your point? (as comment to this answer) – Felix Kling 22 mins ago
@FelixKling This was the best answer when I commented. Questioner is obviously confused about relationship between objects and functions in JS. Do you think this comment belongs elsewhere or is unhelpful? – thefrontender 17 mins ago
@thefrontender: I thought you were criticizing this answer somehow, but couldn't see why. Now I understand that it is just additional information. It might have been better as comment to the question, but it's not a big deal, I was just confused. – Felix Kling 13 mins ago

At the end of the 2nd snippet, try console.log(val). You'll notice you've leaked a global:

var arr = [1,2,3];
arr.map(MyString);
console.log(val); // "3"

When using arr.map(MyString), you're calling that constructor as a function, without the new to create instances. And, since MyString doesn't return anything, you get undefined in the results. But, you've still set this.val, while this isn't an instance but is rather the global object.

String doesn't return undefined because it has a return when called without new:

When String is called as a function rather than as a constructor, it performs a type conversion.

Returns a String value (not a String object) computed by ToString(value). If value is not supplied, the empty String "" is returned.

You can imitate this with MyString by checking if this is an instance first:

function MyString(x) {
    if (this instanceof MyString) {
        this.val = x;
    } else {
        return String(x);
    }
}

var arr = [1, 2, 3];
arr.map(MyString); // [ "1", "2", "3" ]
share|improve this answer

Thats is because String is a function. It returns a string constructed from what is passed to it. For example, if you call String(100), it will return "100".

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.