21

How can i do something like this:

var a = [1,2,3,4];
a.map(Date.constructor);

This code throws an Error on Google V8:

SyntaxError: Unexpected number

I'am also tried:

a.map(Date.constructor, Date.prototype)

with the same result.

3
  • That code should not result in a SyntaxError. (Even though the operation is questionable otherwise: if new is not used during the invocation then the constructor function is ... just a normal function.) Is that all the code? Can you create a minimal jsfiddle test-case? Does it have a SyntaxError in FF/IE? Commented Jun 28, 2011 at 7:58
  • There is a mistake in my code. The Date.constructor is the Function object constructor. The Date object constructor is Date.prototype.constructor or just Date. Commented Jun 28, 2011 at 11:52
  • Found an answer. I will post it in a few hours. Commented Jun 28, 2011 at 12:07

4 Answers 4

8

I think what the OP was looking for is strictly analogous to this:

var nums = [1, 2, 3];
var strs = nums.map(String);
//=> ['1', '2', '3']; // array of strings

I assume the reason is that this is really elegant, both in simple type-casting operations like above, and in more interesting tasks like converting one representation of something into a different representation, like so:

function MyCoolObject(oldObject) {
    // generates new object by consuming old one
    // maybe attach some cool class methods via prototype
    return this;
}

var newList = oldList.map(MyCoolObj);
//=> array of MyCoolObj based on oldObject

The problem with this appears to be that the new object, when created by passing the constructor to Array.map, is an extended version of the window; that is, this within the constructor refers to the global scope, which sucks because (1) it wasn't your goal to hang props on window, and (2) the objects you create this way are not unique instances.

For what it's worth, the original type-casting example isn't all it's cracked-up to be, either, because:

strs[0] instanceof String
//=> false // UGH!

The only solution I've come up with so far requires writing the constructor differently -- which you obviously can't do for native types like Date:

function Human(animal) {
    var h = new Object();
    h.species = 'human';
    h.name = animal.name;
    return h;
}

var humans = animals.map(Human);

By defining the return value as a new object, we sever the connection between the global scope and this; at least, that's what I assume is going on here. (You could also return a JSON literal instead of invoking Object.)

If I want these objects to have an interesting prototype, I have to define it separately and then attach it explicitly:

// this object will be used as the prototype for new Human instances
var HumanProto = {
    species: 'human',
    speak: function() { console.log('My name is ' + this.name); },
    canDrink: function() { return this.age >= 21; }
}

// then, in Human, make this change
var h = new Object(HumanProto);

In this case, it's not just as good to return JSON, because there don't appear to be any effective ways to set the prototype of an object-literal; and even if you could, you never want this to be true:

myObject.hasOwnProperty('prototype');
//=> true // only if myObject = { prototype: HumanProto }

I think the best way to ensure the new object has the desired prototype is to pass the would-be prototype as the argument to new Object().

Is this pattern ideal? I don't know. It seems a little weird, since there are now two symbols associated with creating humans: Human the constructor function, and HumanProto the explicit prototype. More importantly, this seems like a real barrier if you've already got an ecosystem of fun custom classes that weren't written to be compatible with this pattern.

There is probably a better way out there. Maybe someone will post it.

Sign up to request clarification or add additional context in comments.

1 Comment

Another problem with my solution is that you can't say myHuman instanceof Human -- you have to compare it to HumanProto, which is counter-intuitive and exposes the smoke-and-mirrors implementation. GROSS.
3

Is this what you're trying to do?

var a = [1, 2, 3, 4];
a.map(function(obj) { return new Date(obj); });

3 Comments

Yes, but without anonymous function.
Why? It's a straightforward, working solution and doesn't create any significant overhead.
Because if I have an anonymous function which calls the constructor of object with its argument and returns a result, it is reasonable to call the constructor directly. In any case this is not possible in this case (see my answer)
0

The map method just iterates an array using the callback function provided (https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map). So:

var a = [1,2,3,4];
a.map(function(b) { return b+10; }); // [11, 12, 13, 14]

What are you trying to get from this:

Date.constructor(1);
Date.constructor(2);
Date.constructor(3);

Update from comment:

The problem here is to create an array of Date objects with time values from array a by passing the Date object constructor to a map function. Anyway there is a mistake in the code(see comment to pst) – set

I see, so something like:

var a = [1,2,3,4];
a.map(Date.prototype.constructor);

1 Comment

The problem here is to create an array of Date objects with time values from array a by passing the Date object constructor to a map function. Anyway there is a mistake in the code(see comment to pst)
-4

The Date is a function, so the Date.constructor is a constructor of a function. Proper call of the Date object constructor looks like this:

Date.prototype.constructor();

Or just:

Date();

The problem here is to create an array of Date objects with time values from array a, but it is impossible to call the Date object constructor and pass an arguments to it without a new operator (ECMA-262 15.9.2).

But it is possible for any object constructors that can be called as a functions with the same result as if i use the new operator (for instance the Error object constructor (ECMA-262 15.11.1)).

$ var a = ['foo','bar','baz'];
$ a.map(Error);
> [ { stack: [Getter/Setter], arguments: undefined, type: undefined, message: 'foo' },
    { stack: [Getter/Setter], arguments: undefined, type: undefined, message: 'bar' },
    { stack: [Getter/Setter], arguments: undefined, type: undefined, message: 'baz' } ]

3 Comments

that’s wrong, those are just objects, not instances of Error. and if you map .prototype.constructor instead, suddenly this isn’t defined when calling functions added to the prototype.
@Antoniossss because the author accepted their own answer.
Right its authors answser.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.