Пошук шляху за допомогою .Map ()

Багатослівність та елегантність рішення зумовлені інструментами, якими ми маємо вирішити певну проблему. Хоча метою вирішення проблеми є вирішення проблеми , її методи повинні рухатися до найбільш елегантного способу. Проте подорож до такого рішення, схоже, лежить на асимптотичній кривій. Досконалість стає все ближче і ближче, але назавжди залишається недосяжною.

Проблема

Уявіть, що у вас є масив і вам потрібно змінити кожен елемент масиву. Можливо, наприклад, взяти масив висот у дюймах і потрібно перетворити їх у сантиметри. Або, можливо, перетворення масиву температур за Цельсієм у Фаренгейт. Якщо ви новачок у програмуванні, ваш розум може негайно перейти до певної форми циклу. І, вгадайте що? Я впевнений, ти міг би це змусити працювати.

Тим НЕ менше, я тут , щоб дати вам ще один інструмент - що - то , щоб ви просто трохи ближче до елегантний Array.prototype.map().

mapМетод дозволяє перетворити кожен елемент масиву, не зачіпаючи вихідний масив. Це вважається функцією вищого порядку та технікою функціонального програмування, оскільки вона бере функцію як аргумент, і ми виконуємо обчислення, не змінюючи стан нашого додатку.

Map- це властивість, яка успадковується від прототипу масиву. Прототипи забезпечують вбудовані методи, з якими об’єкти поставляються (масиви - це особливі типи об’єктів в очах JavaScript). Хоча mapможе бути трохи більше іноземним, цей прототип нічим не відрізняється від, наприклад, Array.lengthпрототипу. Це просто методи, які вписуються в JavaScript. Прототипи масивів можна додавати і мутувати за допомогою: Array.prototype.= ...

Наприкінці цього уроку ми з’ясуємо, як це mapпрацює, і напишемо власний метод прототипу масиву.

То що робить .map ()?

Скажімо, у вас є безліч температур за Цельсієм, які ви хочете перевести у Фаренгейт.

Існує ряд способів вирішення цієї проблеми. Одним із способів може бути написання forциклу для створення масиву температур за Фаренгейтом із заданих температур за Цельсієм.

За допомогою forциклу ми можемо написати:

const celciusTemps = [22, 36, 71, 54]; const getFahrenheitTemps = (function(temp) { const fahrenheitTemps = []; for (let i = 0; i < celciusTemps.length; i += 1) { temp = celciusTemps[i] * (9/5) + 32 fahrenheitTemps.push(temp); } console.log(fahrenheitTemps); [71.6, 96.8, 159.8, 129.2 })();

Зазначимо пару речей:

  1. Це працює.
  2. Ми використовуємо вираз функції з негайним викликом (IIFE), щоб уникнути також необхідності викликати функцію.
  3. Це трохи багатослівно і не дуже елегантно.

Map дозволяє нам взяти наведений вище код і переформатувати його до наступного:

const fahrenheitTemps = celciusTemps.map(e => e * (9/5) + 32); console.log(fahrenheitTemps); // [71.6, 96.8, 159.8, 129.2]

То як працює карта?

Mapприймає функцію і застосовує цю функцію до кожного елемента масиву. Ми могли б написати mapтрохи детальніше з ES5, щоб побачити це трохи чіткіше.

const fahrenheitTemps = celciusTemps .map(function(elementOfArray) { return elementOfArray * (9/5) + 32; }); console.log(fahrenheitTemps); // [71.6, 96.8, 159.8, 129.2]

Якби наша функція карти могла сказати, що робить, вона сказала б:

"Для кожного елемента масиву я помножую його на (9/5), а потім додаю 32. Коли це буде зроблено, я повертаю результат як елемент у новому масиві, який називається fahrenheitTemps."

Давайте розглянемо більш поширений випадок використання. Припустимо, у нас є масив peopleоб’єктів. Кожен об'єкт має пару nameі ageключ-значення. Ми хочемо створити змінну, яка являє собою лише імена всіх у масиві. За допомогою нашого forметоду циклу ми можемо написати:

const people = [ {name: Steve, age: 32}, {name: Mary, age: 28}, {name: Bill, age: 41}, ]; const getNames = (function(person) { const names = []; for (let i = 0; i < people.length; i += 1) { name = people[i].name; names.push(name); } console.log(names); // [Steve, Mary, Bill]; })();

З map:

const names = people.map(e => e.name); console.log(names) // [Steve, Mary, Bill];

Зверніть увагу, що ми нічого не трансформуємо, ми просто повертаємо пару ключ-значення name.

Знову forпетлі працюють. Але це багатослівно, і нам доводиться створювати нову спеціальну функцію кожного разу, коли ми хочемо зробити інше перетворення. Основною частиною програмування є написання сухого коду (не повторюйся). Ці функції вищого порядку, такі як map, дозволяють нам робити більш складне програмування з меншою кількістю рядків коду, ніж ми могли б без них.

Знову винахід колеса:

Для кращого розуміння того, що відбувається під капотом, ми створимо власну функцію карти, яку ми приєднаємо до прототипу масиву.

Спочатку, щоб приєднати метод-прототип до масиву, ми напишемо:

Array.prototype.

так для нас:

Array.prototype.myMap =

Але яким буде наш код?

Ми вже маємо логіку, яка нам потрібна, з наведених forвище петель. Все, що нам потрібно зробити, - це трохи переформатувати. Давайте рефакторингуємо останню написану нами функцію getNames().

Пам’ятайте, ця функція взяла людину (іншими словами, елемент нашого масиву), виконала власну трансформацію до цього елемента (з forциклом та деякою логікою) і повернула масив імен (або новий масив).

const getNames = (function(person) { const names = []; for (let i = 0; i < people.length; i += 1) { name = people[i].name; names.push(name); } console.log(names); // [Steve, Mary, Bill]; })();

По-перше, давайте змінимо назву нашої функції. Зрештою, цей новий метод не передбачає знання, на який масив він діятиме:

const myMap = (function(person) { //Changed name const names = []; for (let i = 0; i < people.length; i += 1) { name = people[i].name; names.push(name); } console.log(names); // [Steve, Mary, Bill]; })();

По-друге, ми створюємо власну версію .map(). Ми знаємо, що це прийме функцію, яку надає користувач. Давайте змінимо параметр, який приймає наша функція:

// It is a bit verbose, but a very clear parameter name const myMap = (function(userProvidedFunction) { const names = []; for (let i = 0; i < people.length; i += 1) { name = people[i].name; names.push(name); } console.log(names); // [Steve, Mary, Bill]; })();

Нарешті, ми не уявляємо, на який масив діятиме цей метод. Отже, ми не можемо посилатися, people.lengthале можемо посилатися на this.length. this, поверне масив, на який діє метод. Крім того, давайте очистимо деякі інші імена змінних:

const myMap = (function(userProvidedFunction) { // change variable name const newArr = []; // use "this.length" for (let i = 0; i < this.length; i += 1) { // use "this[i]", and change variable name const newElement = this[i]; // update the array we push into newArr.push(newElement); } // Return the newly created array return newArr; })();

Ми майже готові, але є одне, про що ми забуваємо. Ми не перетворили масив! Все, що ми зробили вище, - повернути старий масив. Ми повинні застосувати надану користувачем функцію до кожного елементу масиву:

const myMap = (function(userProvidedFunction) { const newArr = []; for (let i = 0; i < this.length; i += 1) { /* Transform the element by passing it into the * user-provided function */ const newElement = userProvidedFunction(this[i]); newArr.push(newElement); } return newArr; })();

Нарешті, ми можемо приєднати нашу нову функцію до Array.prototype.

Array.prototype.myMap = myMap;

Остаточна перевірка осудності:

const myArray = [1, 2, 3]; // Multiply each element x 2 const myMappedArray = myArray.myMap(e => e * 2) console.log(myMappedArray) // [2, 4, 6];

Резюме

Map is a prototype method offered by arrays. Behind the scenes, it iterates through the array, applying a user-provided function to each element. Ultimately, it returns a new array with the transformed values. It does this without mutating the original array. Because the parameter it takes is a function, it is considered a higher-order function. In addition, its use falls into the functional programming paradigm.

Thanks for reading!

woz