DEV Community

Steve
Steve

Posted on • Updated on • Originally published at stvbyr.tech

Get Mapped Object Inside a Callback Function

Sometimes when using array map you maybe want to access the referenced object that is mapped over.

If you use a closure you can just reference the mapped object by its name as the closure has access to the outer scope.

const names = ["Olive", "Ty", "Hugo", "Ginger"];

const status = names.map(
  (name) => `Took ${name} from names(${names.length} entries)`
);

console.log(status);

// Array(4) [ 
//     0: "Took Olive from names(4 entries)"
//     1: "Took Ty from names(4 entries)"
//     2: "Took Hugo from names(4 entries)"
//     3: "Took Ginger from names(4 entries)"
// ​]
Enter fullscreen mode Exit fullscreen mode

But if you wanna use a generic callback you can't do that.

const firstNames = ["Olive", "Ty", "Hugo", "Ginger"];
const lastNames = ["Yew", "Ayelloribbin", "First", "Plant"];

const logStatusForNames = (name) => `Took ${name} from names(${names.length} entries)`;

const firstNamesStatus = firstNames.map(logStatusForNames);
const lastNamesStatus = lastNames.map(logStatusForNames);

console.log(firstNamesStatus, lastNamesStatus);

// will not work because "names" is not specified anymore and I can't use any variable either
Enter fullscreen mode Exit fullscreen mode

Unfortunately, but there is hope.

Method 1: Using the third argument of the callback

Luckily there is a super easy fix for that.

The callback function actually can take three parameters as its arguments.

The first one is the value of a single array element.

The second one is the index of that element.

And finally the third parameter is a reference to the object that is mapped over.

const firstNames = ["Olive", "Ty", "Hugo", "Ginger"];
const lastNames = ["Yew", "Ayelloribbin", "First", "Plant"];

const logStatusForNames = (name, index, names) => `Took ${name} from names(${names.length} entries)`;

const firstNamesStatus = firstNames.map(logStatusForNames);
const lastNamesStatus = lastNames.map(logStatusForNames);

console.log(firstNamesStatus, lastNamesStatus);

// Array(4) [ 
//     0: "Took Olive from names(4 entries)"
//     1: "Took Ty from names(4 entries)"
//     2: "Took Hugo from names(4 entries)"
//     3: "Took Ginger from names(4 entries)"
// ​]
// Array(4) [ 
//     0: "Took Yew from names(4 entries)"
//     1: "Took Ayelloribbin from names(4 entries)"
//     2: "Took First from names(4 entries)"
//     3: "Took Plant from names(4 entries)"
// ​]
Enter fullscreen mode Exit fullscreen mode

That's it! Easy right?

Method 2: Setting the thisArg

Technically there is another approach to this.

You can give the map function a second argument. It will determine what this refers to inside the callback function.

But I do not recommend that as the use of this should be used in small doses. Or avoided if possible.

There is another caveat though. You can't use arrow functions when using that method. This relates to how arrow functions are implemented in javascript.

const firstNames = ["Olive", "Ty", "Hugo", "Ginger"];
const lastNames = ["Yew", "Ayelloribbin", "First", "Plant"];

const logStatusForNamesFunction = function (name) {
    return `Took ${name} from names(${this.length} entries)`
};
const logStatusForNamesArrow = (name) => `Took ${name} from names(${this.length} entries)`;

const firstNamesStatus = firstNames.map(logStatusForNamesFunction, firstNames); // works as in the previous example
const lastNamesStatus = lastNames.map(logStatusForNamesArrow, lastNames); // doesn't work. "this" refers to the window object if called in a browser

console.log(firstNamesStatus, lastNamesStatus);
Enter fullscreen mode Exit fullscreen mode

Conclusion

As you can see it is very easy to reference the mapped object inside a array map callback.

By the way the first method that I showed you also works with reduce. The callback can take up to four arguments. The fourth one would be the reduced array.

Top comments (0)