Общее программирование
Универсальное программирование основано на идее абстрагирования от конкретных эффективных алгоритмов для получения универсальных алгоритмов, которые можно комбинировать с различными представлениями данных для создания широкого спектра полезного программного обеспечения.
— Мюссер, Дэвид Р.; Степанов, Александр А., Общее программирование
Цель
- Чтобы заставить алгоритм/метод/решение работать в общем, инкапсулируя детали о структурах данных и операциях.
- Чтобы позволить разработчикам сосредоточиться на решении, а не различать структуры данных в реализации.
Не болтай, покажи пример
Вычислить сумму массива
function sum(arr) { let total = 0; for(let i = 0; i < arr.length; i++) { total += arr[i]; } return total; }
console.log(sum([1,2,3])); //6
Мы перебираем массив и складываем каждый элемент, чтобы получить сумму массива. Но что, если нам нужна другая операция, например, поиск максимального числа:
Найдите максимальное число в массиве
function max(arr) { let result = arr[0]; for(let i = 1; i < arr.length; i++) { if(arr[i] > result) { result = arr[i] } } return max; }
console.log(max([1,2,3])); //3
Как мы можем сделать лучше?
Может быть много случаев, когда нам нужно пройтись по массиву и что-то сделать с его элементами. Это должно быть хорошим вариантом для инкапсуляции операции и предоставления вызывающей стороне возможности определить, что делать с каждым элементом. Вот для чего предназначено reduce. Давайте реализуем наш собственный _reduce.
function _reduce(op, initialValue) {
return (arr) => {
let result;
let index = 0;
if(initialValue != null) {
result = initialValue;
} else {
result = arr[0];
index = 1;
}
for(let i = index; i < arr.length; i++) {
result = op(result, arr[i])
}
return result;
}
}
Итак, теперь мы можем переписать sum и max как:
let sumWithReduce = _reduce((sum, item) => sum + item) let maxWithReduce = _reduce((max, item) => max > item ? max : item)
console.log(sumWithReduce([1,2,3])); //6 console.log(maxWithReduce([1,2,3])); //3
Как мы можем сделать еще лучше?
В приведенной выше реализации _reduce мы абстрагировались от деталей операции и оставили в реализации только логику цикла. Однако реализация по-прежнему зависит от for и индекса массива, поэтому она работает только для массивов. Мы делаем его более общим с помощью Итераторов.
function _genericReduce(op, initialValue) { return (iterables) => { let inited, result; if(initialValue != null) { result = initialValue; inited = true; } for(let item of iterables) { if(!inited) { result = item; inited = true; } else { result = op(result, item) } } return result; } }
let sumWithGenericReduce = _genericReduce((sum, item) => sum + item) let maxWithGenericReduce = _genericReduce((max, item) => max > item ? max : item)
console.log(sumWithGenericReduce([1,2,3])); //6 console.log(maxWithGenericReduce([1,2,3])); //3
Теперь он работает для всех структур данных, которые являются итерируемыми. Вот заметка, которую я написал об итераторе, если вам интересно.
class Group { constructor(id) { this.id = id; this.members = []; }
addMember(person) { this.members.push(person); }
[Symbol.iterator]() { let index = 0; return { next: () => ({ value: this.members[index++], done: index > this.members.length }) }; } }
class Member { constructor(name, salary) { this.name = name; this.salary = salary; } }
## try to find the lowest salary in the group
let group = new Group('007'); group.addMember(new Member('mike', 1000)) group.addMember(new Member('john', 2000)) group.addMember(new Member('alfred', 3000)) let lowestSalary = _genericReduce((result, member) => { if(member.salary < result) { return member.salary } return result; }, Number.MAX_SAFE_INTEGER)(group) console.log(lowestSalary);
Ресурс
Уведомление
- Если вы хотите следить за последними новостями/статьями из серии моих блогов, пожалуйста, 「Watch」 для подписки.