Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a constructor to Array.map?

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.

like image 989
set Avatar asked Jun 28 '11 07:06

set


People also ask

Can a constructor be an array?

Array constructor with a single parameterArrays can be created using a constructor with a single number parameter. An array with its length property set to that number and the array elements are empty slots.

Can constructors return an array?

Hello.. you can't return an array in a constructor. The return type of a constructor is void.

How do you assign an array to a map?

To convert an array of objects to a Map , call the map() method on the array and on each iteration return an array containing the key and value. Then pass the array of key-value pairs to the Map() constructor to create the Map object.

Is constructor a property of array?

The JavaScript Array constructor property is used to return the constructor function for an array object. It only returns the reference of the function and not returns the name of the function. So, In JavaScript arrays, it returns the function Array() { [native code] }.


1 Answers

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.

like image 63
Tom Avatar answered Oct 04 '22 14:10

Tom