Расшифруйте, пожалуйста, функцию. Комментарии будут очень полезны
Изучал сортировку таблицы и вот попался такой код. Код этот я уже скомпилировал через babel (до этого он был еще менее читаемым). Эта функция позволяет отсортировать <table> при клике <th> конкретной колонки (банальный addEventListener).
function getCellValue(tr, index) {
return tr.children[index].innerText;
};
function comparer(index, asc) {
return function (rowA, rowB) {
return (function (prevTd, nextTd) {
return prevTd.toString().localeCompare(nextTd);
})(
getCellValue(asc ? rowA : rowB, index),
getCellValue(asc ? rowB : rowA, index)
);
};
};
Array.from(table.querySelectorAll("tr:nth-child(n+2)"))
.sort(
comparer(
Array.from(target.parentNode.children).indexOf(target),
(this.asc = !this.asc)
)
)
.forEach(function (tr) {
return table.appendChild(tr);
});
Загвоздка больше всего в comparer. Можно ли ее сделать проще без высшего порядка? В частности непонятен этот блок:
return (function (prevTd, nextTd) {
return prevTd.toString().localeCompare(nextTd);
})(
getCellValue(asc ? rowA : rowB, index),
getCellValue(asc ? rowB : rowA, index)
);
Выше после первого return стоит скобка, затем getCellValue (2 шт) тоже помещены в скобки. Что это значит? Зачем вообще использованы return в return, который тоже находится в return? Почему getCellValue(asc ?...) используется дважды? В общем, вопросов больше чем ответов. Прокомментируйте, пожалуйста?
Ответы (1 шт):
Есть функции, результатом выполнения которых являются другие функции и очень часто используются. Самый простой пример дается через возведение в степень.
function expFabric (exp) {
return function(value){
return value ** exp;
}
}
// Получаем другую функцию, в который уже фиксированный exp
let square = expFabric(2);
console.log(square(10));
console.log(square(20));
// Получаем другую функцию, в который уже фиксированный exp
let cube = expFabric(3);
console.log(cube(10));
console.log(cube(20));
Функции можно вызывать сразу после объявления, код аналогичен вышеприведенному.
let square = (function expFabric (exp) {
return function(value){
return value ** exp;
}
})(2); // сразу передаем два и получаем функцию внутри
console.log(square(10));
console.log(square(20));
Ваш compare генерирует другую функцию:
let array = Array.from(table.querySelectorAll("tr:nth-child(n+2)"));
let anotherFunction = comparer(
Array.from(target.parentNode.children).indexOf(target),
(this.asc = !this.asc)
);
array.sort(anotherFunction)
.forEach(function (tr) {
return table.appendChild(tr);
});
Получается в anotherFunction у нас лежит функция.
function (rowA, rowB) {
return (function (prevTd, nextTd) {
return prevTd.toString().localeCompare(nextTd);
})(
getCellValue(asc ? rowA : rowB, index),
getCellValue(asc ? rowB : rowA, index)
);
};
Аргументы в эту функцию передает сама sort, когда мы ей передаем anotherFunction; Эта функция как раз вызывается сразу с аргументами. Можно переписать в более понятный код.
Итерация 1:
function compareString (prevTd, nextTd) {
return prevTd.toString().localeCompare(nextTd);
};
function (rowA, rowB) {
return compareString (
getCellValue(asc ? rowA : rowB, index),
getCellValue(asc ? rowB : rowA, index)
);
};
Или итерация 2:
function compareString (prevTd, nextTd) {
return prevTd.toString().localeCompare(nextTd);
};
function (rowA, rowB) {
let left = getCellValue(asc ? rowA : rowB, index);
let right = getCellValue(asc ? rowB : rowA, index);
return compareString (left, right);
};
Ну и полная картина на более понятных вещах:
function getCellValue(tr, index) {
return tr.children[index].innerText;
};
function compareString (prevTd, nextTd) {
return prevTd.toString().localeCompare(nextTd);
};
function comparer(index, asc) {
return function (rowA, rowB) {
let left = getCellValue(asc ? rowA : rowB, index);
let right = getCellValue(asc ? rowB : rowA, index);
return compareString (left, right);
};
};
let index = Array.from(target.parentNode.children).indexOf(target);
let asc = (this.asc = !this.asc);
let currentComparer = comparer(index, asc);
Array.from(table.querySelectorAll("tr:nth-child(n+2)"))
.sort(currentComparer)
.forEach(function (tr) {
return table.appendChild(tr);
});
P.S.> поскольку это абстрактый код без примера, то возможны ошибки, но думаю общая логика понятная.