Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling method of objects in array using map()

I'm trying to figure out a one-liner code using map.

Here is a simple set up.

function Cat(name) {
    this.name = name;
    // FYI: using __proto__ is discouraged. thanks @KarelG
    this.__proto__.mew = function () {
        console.log(this.name + " mews");
    };
}

var cats = [
    new Cat('MB'),
    new Cat('503')
];

Then, I can use map() to call mew method in cats.

cats.map(function (cat) {
    cat.mew();
});
// MB mews
// 503 mews

call() on prototype also works.

cats.map(function (cat) {
    Cat.prototype.mew.call(cat);
});
// MB mews
// 503 mews

And here is my final one-liner, but it emits error and I could't understand why:

cats.map(Cat.prototype.mew.call);

// Uncaught TypeError: undefined is not a function
// at Array.map (<anonymous>)

Checking typeof Cat.prototype.mew.call says it's a function and map()'s parameter should be a function.

Could anyone explain why it doesn't work? What did I miss and where to correct?

like image 413
Kita Avatar asked Dec 22 '17 06:12

Kita


People also ask

What does the array method map () do?

The Array. map() method allows you to iterate over an array and modify its elements using a callback function. The callback function will then be executed on each of the array's elements.

How do you map an array to an array of objects?

To convert a Map to an array of objects: Call the Array. from() method, passing it the Map as the first parameter and a function as the second. On each iteration of the function, return an object containing the current key-value pair.

Can we use map on objects?

A Map 's keys can be any value (including functions, objects, or any primitive). The keys of an Object must be either a String or a Symbol . The keys in Map are ordered in a simple, straightforward way: A Map object iterates entries, keys, and values in the order of entry insertion.

Can we use map on array?

map() can be used to iterate through objects in an array and, in a similar fashion to traditional arrays, modify the content of each individual object and return a new array. This modification is done based on what is returned in the callback function.


1 Answers

Could anyone explain why it doesn't work? What did I miss and where to correct?

Error message says

VM1100:15 Uncaught TypeError: undefined is not a function

This means that it is looking to call the mew method on a context which is undefined.

You need to bind the context as

cats.map( Cat.prototype.mew.call.bind( new Cat().mew ) );

Demo

function Cat(name) {
    this.name = name;
    this.__proto__.mew = function () {
        console.log(this.name + " mews");
    };
}

var cats = [
    new Cat('MB'),
    new Cat('503')
];
cats.map( Cat.prototype.mew.call.bind( new Cat().mew ) );

Or as @PatrickRoberts has suggested, you can use

cats.map(Function.call.bind(Cat.prototype.mew))

to avoid needlessly creating an instance of Cat

In cats.map(function (cat) { Cat.prototype.mew.call(cat); }); expression, why Cat.prototype.mew.call has a correct context?

As per spec

If a thisArg parameter is provided, it will be used as the this value for each invocation of callbackfn. If it is not provided, undefined is used instead.

So, unless you pass a context like

cats.map( Cat.prototype.mew.call,  new Cat().mew );

It will be undefined.

like image 194
gurvinder372 Avatar answered Oct 24 '22 19:10

gurvinder372