През последната година се опитвах да подобря уменията си в JavaScript. Може би най-полезното нещо, което научих, е композицията. Да можеш да пишеш код, който се чете добре, е страхотно както за нас, така и за бедния човек, който може да поддържа кода веднъж в бъдеще.
Аз ❤️ ES6. Синтаксисът е много по-добър от стария стил на JavaScript. И дори лошата репутация, която JavaScript имаше навремето, е на път да изчезне. Методи като картиране, филтриране, намаляване са не само непроменливи методи, но и се четат добре. Но все още можете да сбъркате. И е доста лесно да се обърка с JavaScript. Така че изборът на стил на код и качването на функционалния JS хипстърски вагонможе да е добра идея!
Така че да продължим. Да кажем, че имаме тази част в стар стил JavaScript:
function completedTodos(todos) { var completedTodos = []; for (var i = 0; i < todos.length; i++) { if (todos[i].completed) { if (completedTodos.length < 10) { todos[i].image = './path/image.jpg'; completedTodos.push(todos[i]); } } } return completedTodos; };
Освен стария синтаксис, функцията може да изглежда доста добре на пръв поглед. Не е толкова дълго и изглежда доста чисто. Но не е така. Първо мутира два пъти: Присвояването на свойства директно върху масива todos и методът push също се променят. Но този път няма да се концентрираме върху мутирането, запазваме го за по-късно. Ще се концентрираме върху разлагането.
И така, нека да видим какво всъщност прави функцията:Тя връща последните десет завършени задачи и добавя изображение към тях. Първо, името на функцията completedTasks не описва много какво всъщност прави и по-важното е доста трудно да се прочете от кода какво всъщност прави. А наличието на четим самообясняващ се код е доста ценно. Функционалното програмиране е много за това. Разказване на история, една функция в даден момент.
За да разложим тази функция, нека започнем с обмисляне на стъпките, от които се нуждаем, за да постигнем това, което искаме:
• Намерете всички завършени задачи
• Филтрирайте последните десет
• Добавете изображение към всяка задача
И така, ще напиша три нови функции със синтаксиса на ES6:
const completedTodos = todos => todos.filter( todo => todo.completed ); const firstTenTodos = todos => todos.slice(0, 10); const addImageToTodos = todos => todos.map(todo => { return {...todo, image: './path/image.jpg'} });
Това е много по-хубаво. Имената на функциите са специфични за това, което функцията прави, и дори ако не сте запознати със синтаксиса, е доста ясно какво правят и методите. Първо филтрираме, за да получим завършените задачи, отрязваме последните 10 и след това картографираме всеки обект и добавяме изображение. Освен това няма мутиране, само красиви чисти функции, които връщат нови обекти. Страхотно! 🎉
Така че сега ще съставим нашите функции заедно. Можем да направим във vanilla JS така:
cont addImageToFirstTenCompletedTodos = addImageToTodos(firstTenTodos(completedTodos(todos)));
Но това не ми харесва. Трябва да прочетем функцията отвътре навън или отдясно наляво, за да я получим. Това не е много четивно! Вместо това ще използвам малък помощник, наречен Lodash Flow. Ще направи абсолютно същото, но отляво надясно и синтаксисът е много по-хубав.
import flow from 'lodash/flow'; const addImageToFirstTenCompletedTodos = flow( completedTodos, firstTenTodos, addImageToTodos, )(todos);
Ще видиш? Това е само списъкът, който имахме в началото 👌
Бонус: Вече можем да пишем тестове!
Когато правим нещата по този начин, също е много по-лесно да пишем тестове. Единичните тестове може да са плашещи, ако сте нов в JavaScript, но всъщност са доста страхотни! Ще използвам „Jest“ за пример, но има и няколко други страхотни тестове.
Така че ще напишем тест за нашата функция completedTodos. Вече сме направили функцията, така че просто я импортираме, самият тест е само няколко реда код. Но трябва да напишем някои тестови данни:
import 'completedTodos' from '../functions/completedTodos'; var todos = [{ name: 'One', completed: true, }, { name: 'Two', completed: false, }, { name: 'Three', completed: true, } ]; var result = [{ name: 'One', completed: true, }, { name: 'Three', completed: true, } ]; describe('firstTenTodos', () => { it('Takes and array of todos and returns the completed', () => { expect(completedTodos(todos)).toEqual(result); }); });
Единственото нещо, което трябва да направим, е да опишем как изглеждат нашите данни и какъв искаме да бъде резултатът. След това поставяме нашата функция в expect и нашия очакван резултат в toEqual. След това трябва да дадем на нашата тестова колекция и име на теста и сме готови да започнем npm run test. Лесно грах 🙌
Ако тестът ви е неуспешен, той ще изведе разликата между това, което функцията ви връща, и желания резултат. Така че, ако работим със сложни структури от данни, добра идея е първо да напишем теста и да стартираме теста, докато се развивате, докато функцията ви върне това, което искате.
–
Така че аз самият съм далеч от функционален герой на JavaScript. Но наистина ми харесва да уча и виждам как кодът ми се подобрява. И докато светът на интерфейса се движи доста бързо в наши дни, усещането е доста приятно да научите и използвате тези „стари доказани принципи на компютърната наука“ на функционалното програмиране.