Функціональне програмування.
Фронтенд розробка JavaScript. -> Сортування об'єктів.
Сортування об’єктів.
Припустимо, у нас є масив.
var fruits = ['cherries', 'apples', 'bananas']
Функція сортування має вигляд.
arr.sort([функция-сравниватель])
Її можна спричинити без аргументів.
console.log(fruits.sort())
Загальний вигляд функції-порівняча
function cmp(a,b) {
if ( a > b ) return 1;
if ( a < b ) return -1;
return 0;
}
console.log(fruits.sort(cmp))
Припустимо, у нас є складний об’єкт.
var people = [
{firstname: 'Dima', lastname: 'Ivanov'},
{firstname: 'Vova', lastname: 'Putin'},
{firstname: 'Anna', lastname: 'Karenina'}
]
Ми хочемо відсортувати його по полю firstname.
І тому визначимо таку функцію.
function cmp(a,b) {
return ( a.firstеname > b.firstname )? 1: ( a.firstname < b.firstname )? -1: 0;
}
Удосконалимо функцію, передавши параметром значення поля, за яким хочемо відсортувати.
function sortBy(field) {
return function(a,b) {
return ( a[field] > b[field] )? 1: ( a[field] < b[field] )? -1: 0;
}
}
Перевірка.
console.log(people.sort(sortBy('lastname')))
Фронтенд розробка JavaScript. -> Домашнє завдання. Чисті функції.
Домашнє завдання. Чисті функції.
Створити функцію вищого порядку forEachObject, яка має таку сигнатуру
forEachObject(object,function(property,object[property]))
Ця функція проходить за всіма властивостями об’єкта та застосовує функцію до кожної з властивостей згідно з сигнатурою вище.
При цьому необхідно брати властивості тільки цього об’єкта, не торкаючись успадкованих через prototype.
Фронтенд розробка JavaScript. -> Чисті функції.
Чисті функції.
Чистими називають ті функції які працюють виключно з параметрами, що передаються в них.
Якщо ф-ция працює зі змінними, визначеними її межами, вона є чистої і має побічний ефект.
Припустимо, у нас є список.
var fruits = ['cherries', 'apples', 'bananas']
Визначимо функцію перебору елементів масиву.
function forEach(arr,fn){
for(let i=0; i<=arr.length-1; i++){
fn(arr[i]);
}
}
Застосуємо її для виведення елементів у консоль.
forEach(fruits,(el)=> console.log(el))
Зробимо функцію, яка змінює елементи масиву.
function map(arr,fn){
for(let i=0; i<=arr.length-1; i++){
arr[i] = fn(arr[i]);
}
}
map(fruits,(el)=> el.toUpperCase())
console.log(fruits);
Функція every.
Припустимо, є два масиви.
var myarr1 = [NaN,2,NaN,NaN];
var myarr2 = [NaN,NaN,NaN,NaN];
Необхідно перевірити чи є в масиві хоч один елемент, що не відповідає умові, яка укладена в функцію, і повернути true якщо всі відповідають або false якщо хоча б один немає.
const every = (arr,fn) => {
let result = true;
for(let i=0;i<arr.length;i++){
result = result && fn(arr[i]);
}
return result;
};
У js є вбудована функція isNaN, яка перевіряє чи є значення числом.
console.log(every(myarr1,isNaN)); false
console.log(every(myarr2,isNaN)); true
Функція деяка.
Робить навпаки, повертає true якщо хоча б один відповідає і повертає true, інакше повертається false.
const some = (arr,fn) => {
let result = false;
for(let i=0;i<arr.length;i++){
result = result || fn(arr[i]);
}
return result;
};
Необхідно відзначити неоптимальну роботу функції, коли вона у будь-якому разі пройде весь масив цілком, навіть якщо перший елемент поверне true і необхідності йти масивом далі немає.
За допомогою таких функцій можна писати програми у функціональному стилі, не використовуючи операторів умов (if else) та циклів (for).
Наприклад, щоб визначити чи присутня в масиві
var myarr1 = [NaN,2,NaN,'Dima'];
хоч одне значення ‘Dima’ можна так
console.log(some(myarr1,(e) => e === 'Dima')));
Сортування об’єктів.
Припустимо, у нас є масив.
var fruits = ['cherries', 'apples', 'bananas']
Функція сортування має вигляд.
arr.sort([функція-порівняльник])
Її можна спричинити без аргументів.
console.log(fruits.sort())
Загальний вигляд функції-порівняча.
function cmp(a,b) {
if ( a > b ) return 1;
if ( a < b ) return -1;
return 0;
}
console.log(fruits.sort(cmp))
Припустимо, у нас є складний об’єкт.
var people = [
{firstname: 'Dima', lastname: 'Ivanov'},
{firstname: 'Vova', lastname: 'Putin'},
{firstname: 'Anna', lastname: 'Karenina'}
]
Ми хочемо відсортувати його по полю firstname.
І тому визначимо таку функцію.
function cmp(a,b) {
return ( a.firstеname > b.firstname )? 1: ( a.firstname < b.firstname )? -1: 0;
}
Удосконалимо функцію, передавши параметром значення поля, за яким хочемо відсортувати.
function sortBy(field) {
return function(a,b) {
return ( a[field] > b[field] )? 1: ( a[field] < b[field] )? -1: 0;
}
}
Перевірка.
console.log(people.sort(sortBy('lastname'))))
Замикання.
Із замиканням пов’язана область пам’яті, в яку розміщуються змінні в момент повернення однієї функції з іншої.
Простіше кажучи замикання - це внутрішня функція зі змінними, які потрапляють до неї із зовнішньої.
function outer() {
function inner() {
}
}
Функція inner називається функцією - замиканням.
Уся сила цих функцій полягає у механізмі доступу до області видимості змінних усередині поточної функції.
Усього їх 3.
-
Змінні, оголошені у власній області поточної функції.
-
Змінні, оголошені у глобальному просторі (за межами функцій)
-
Змінні, оголошені у зовнішній функції щодо поточної.
Варіант 1.
function outer() {
function inner(){
let a = 1;
console.log(a);
}
inner();
}
Варіант 2.
var global = 3;
function outer() {
function inner(){
let a = 1;
console.log(global);
}
inner();
}
Варіант 3.
function outer() {
let outer = 'Outer';
function inner(){
let a = 1;
console.log(outer);
}
inner();
}
При цьому зовнішня функція як би замикає простір видимості для внутрішньої функції-замикання та робить доступним змінні з неї.
Спробуємо повернути внутрішню функцію із зовнішньої, якій ще й передамо параметр.
var fn = (arg) => {
let outer = 'Visible';
let innerFn = () => {
console.log(outer);
console.log(arg);
}
return innerFn;
}
Виклик буде наступним.
var closureFn = fn(5);
closureFn();
Спочатку ми присвоюємо змінній результат виконання fn, яка приймає аргумент і повертає функцію-замикання.
І ця функція-замикання матиме доступ як до аргументу arg, так і до outer.
Функція unary.
Допустимо ми хочемо перетворити рядки масиву на числа.
console.log(['1','2','3'].map((parseInt)))
висновок
[1, NaN, NaN]
Проблема в тому, що функція map має наступну сигнатуру
array.map(callback(item, index, array))
А функция parseInt имеет сигнатуру
parseInt(string, radix);
де radix ця основа числа в математиці і коли map туди заштовхує порядковий номер елемента index - це змінює її роботу і не бажано
Тому створимо функцію unary, яка відсіє всі зайві параметри, що передаються map.
const unary = function(func) {
if (func.length === 1){
return func
} else {
return function(el) {
return func(el);
}
}
}
Або більш який варіант зі стрілочними функціями та тернарним оператором.
const unary = (func) => (func.length === 1)? func: (el) => func(el);
І тепер скористаємось.
console.log(['1','2','3'].map((unary(parseInt))));
Работа с массивами.
Функция map
Смысл - изменить массив функцией.
const map = (array, fn) => {
let results = [];
for(const value in array) {
results.push(fn(value));
}
return results;
}
Застосування.
console.log(map(['1','2','3'],(el) => parseInt(el)));
Функція Filter.
Функція filter
Сенс - відсіяти елементи масиву, що не задовольняють умовам переданої функції (колбеку).
const filter = (arr,func) => {
let result = [];
for(const value of arr) {
(func(value)) ? result.push(value): undefined;
}
return result;
}
Відбираємо парні числа.
console.log(filter([1,2,3,4,5,6],(el) => el%2 === 0));