# Map

## Objectives

1. Implement a `map()` function from scratch.

## Introduction

In the previous lesson, we learned about `.filter()`, a built-in array method that searches through a collection, passes each element to a provided callback function, and returns an entirely new array comprised of elements for which the callback returned a truthy value.

Another very common built-in array method is `.map()`, which transforms every element in an array to another value. For example, it can be used to square every value in an array of numbers: `[1, 2, 3]` -> `[1, 4, 9]`. Map also accepts a callback function, and it passes each element successively to the callback:

```
[1, 2, 3].map(function(num) {
	return num * num;
});
// => [1, 4, 9]
```

Let's quickly run through how we could create our own version of the `.map()` method.

## Abstracting the iteration

Right off the bat, we know that our function needs to accept the array from which we'd like to *map* values as an argument:

```
function map(array) {
	// Map magic to follow shortly
}
```

Inside the function, we need to iterate over each element in the passed-in array, so let's fall back on our trusty `for...of` statement:

```
function map(array) {
	for (const element of array) {
		// Do something to each element
	}
}
```

## Callback city

We want to transform values from the array, but for code organization and re-usability it's best to keep that logic decoupled from the `map()` function. `map()` should really only be concerned with iterating over the collection and passing each element to a callback that will handle the transformations. Let's accept that callback function as the second argument to `map()`:

```
function map(array, callback) {
	for (const element of array) {
		// Do something to each element
	}
}
```

And inside our iteration, we'll want to invoke the callback, passing in the elements from `array`:

```
function map(array, callback) {
	for (const element of array) {
		callback(element);
	}
}
```

Let's make sure this is working so far:

```
map([1, 2, 3], function(num) {
	console.log(num * num);
});
// LOG: 1
// LOG: 4
// LOG: 9
```

## Returning a brand new collection

Logging each squared number out to the console is fun, but `map()` should really be returning an entirely new array containing all of the squared values. Show off that new collection!

[![NY Fashion Week](https://camo.githubusercontent.com/b3ee116284289c1efe0ba4183903c162bb553a10/68747470733a2f2f637572726963756c756d2d636f6e74656e742e73332e616d617a6f6e6177732e636f6d2f7765622d646576656c6f706d656e742f6a732f6c6f6f70696e672d616e642d697465726174696f6e2f6d61702d726561646d652f6e7966772e676966)](https://camo.githubusercontent.com/b3ee116284289c1efe0ba4183903c162bb553a10/68747470733a2f2f637572726963756c756d2d636f6e74656e742e73332e616d617a6f6e6177732e636f6d2f7765622d646576656c6f706d656e742f6a732f6c6f6f70696e672d616e642d697465726174696f6e2f6d61702d726561646d652f6e7966772e676966)

Fierce.

First, let's create that new array:

```
function map(array, callback) {
	const newArr = [];

	for (const element of array) {
		callback(element);
	}
}
```

Inside the `for...of` statement, let's `.push()` the return value of each callback invocation into `newArr`:

```
function map(array, callback) {
	const newArr = [];

	for (const element of array) {
		newArr.push(callback(element));
	}
}
```

And at the end of our `map()` function we're going to want to return the new array:

```
function map(array, callback) {
	const newArr = [];

	for (const element of array) {
		newArr.push(callback(element));
	}

	return newArr;
}
```

Let's test it out!

```
const originalNumbers = [1, 2, 3, 4, 5];

const squaredNumbers = map(originalNumbers, function(num) {
	return num * num;
});

originalNumbers;
// => [1, 2, 3, 4, 5]

squaredNumbers;
// => [1, 4, 9, 16, 25]
```

## Flatbook's expanding engineering team

Let's use our `map()` function on a trickier data structure — a list of recently onboarded engineers. First off, we need to flip each new engineer's account from a normal user to an admin:

```
const oldAccounts = [
	{ userID: 15, title: 'Developer Apprentice', accessLevel: 'user' },
	{ userID: 63, title: 'Developer Apprentice', accessLevel: 'user' },
	{ userID: 97, title: 'Developer Apprentice', accessLevel: 'user' },
	{ userID: 12, title: 'Developer Apprentice', accessLevel: 'user' },
	{ userID: 44, title: 'Developer Apprentice', accessLevel: 'user' }
];

const newEngineers = map(oldAccounts, function(account) {
	return Object.assign({}, account, { accessLevel: 'admin' });
});

oldAccounts;
// => [
//      { userID: 15, title: "Developer Apprentice", accessLevel: "user" },
//      { userID: 63, title: "Developer Apprentice", accessLevel: "user" },
//      { userID: 97, title: "Developer Apprentice", accessLevel: "user" },
//      { userID: 12, title: "Developer Apprentice", accessLevel: "user" },
//      { userID: 44, title: "Developer Apprentice", accessLevel: "user" }
//    ]

newEngineers;
// => [
//      { userID: 15, title: "Developer Apprentice", accessLevel: "admin" },
//      { userID: 63, title: "Developer Apprentice", accessLevel: "admin" },
//      { userID: 97, title: "Developer Apprentice", accessLevel: "admin" },
//      { userID: 12, title: "Developer Apprentice", accessLevel: "admin" },
//      { userID: 44, title: "Developer Apprentice", accessLevel: "admin" }
//    ]
```

Notice that we're using `Object.assign()` to create a **new** object with updated values instead of mutating the original object's `accessLevel` property. Nondestructive updating is an important concept to practice — destructively modifying objects at multiple points within a code base is one of the biggest sources of bugs.

Next, we just need a simple array of the new engineers' `userID`s that we can shoot over to the system administrator:

```
const userIDs = map(newEngineers, function(eng) {
	return eng.userID;
});

userIDs;
// => [15, 63, 97, 12, 44]
```

Finally, let's use the built-in `Array.prototype.map()` method to indicate that all the new engineers have been provided a new work laptop:

```
const equippedEngineers = newEngineers.map(function(eng) {
	return Object.assign({}, eng, { equipment: 'Laptop' });
});

equippedEngineers;
// => [
//      { userID: 15, title: "Developer Apprentice", accessLevel: "admin", equipment: "Laptop" },
//      { userID: 63, title: "Developer Apprentice", accessLevel: "admin", equipment: "Laptop" },
//      { userID: 97, title: "Developer Apprentice", accessLevel: "admin", equipment: "Laptop" },
//      { userID: 12, title: "Developer Apprentice", accessLevel: "admin", equipment: "Laptop" },
//      { userID: 44, title: "Developer Apprentice", accessLevel: "admin", equipment: "Laptop" }
//    ]
```

Now that we understand how the built-in `.map()` array method is implemented, we can stick to the native method and get rid of our copycat `map()` function.

[![Office Space](https://camo.githubusercontent.com/388b1471aca33285bc45e25159d87cd82bf53597/68747470733a2f2f637572726963756c756d2d636f6e74656e742e73332e616d617a6f6e6177732e636f6d2f7765622d646576656c6f706d656e742f6a732f6c6f6f70696e672d616e642d697465726174696f6e2f6d61702d726561646d652f6f66666963655f73706163652e676966)](https://camo.githubusercontent.com/388b1471aca33285bc45e25159d87cd82bf53597/68747470733a2f2f637572726963756c756d2d636f6e74656e742e73332e616d617a6f6e6177732e636f6d2f7765622d646576656c6f706d656e742f6a732f6c6f6f70696e672d616e642d697465726174696f6e2f6d61702d726561646d652f6f66666963655f73706163652e676966)

## Resources

* [MDN — `Array.prototype.map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)

View [Map](https://learn.co/lessons/js-looping-and-iteration-map-readme) on Learn.co and start learning to code for free.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://certil-remy.gitbook.io/learn/javascript/untitled-6/untitled-13.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
