// "Глубокое" сравнение объектов
// т.е. сравнение по всем полям и значениям
// включая вложенные
function deepEqual(a, b) {
// Если переданы ссылки на один объект, то они равны
// Или если переданы равные скалярные значения
if (a === b) return true;
// Если хотя бы один пуст или не является объектом
if (a == null || typeof a != "object" ||
b == null || typeof b != "object") return false;
// Получаем все ключи объектов
let keysA = Object.keys(a), keysB = Object.keys(b);
// Если длина разная, значит ключей разное кол-во, объекты не равны
if (keysA.length != keysB.length) return false;
// Проверка каждого ключа.
// Если хотя бы один отсутствует во втором, - не равны
// Плюс запускается рекурсия по вложенным значениям
for (let key of keysA) {
if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false;
}
// Если все проверки пройдены, значит объекты равны
return true;
}
Почему на скриншоте ниже под синей чертой мы не указываем 'format', а в остальных контейнерах указываем?
reduce принимает два параметра - функцию и начальное значение
.reduce(myFunc, initialValue);
в данном случае initialValue = []
функция должна принимать два параметра, аккумулятор (или по другому, результат с предыдущей итерации). На самой первой итерации он как раз пример значение initialValue. Вторым параметром в нее будет передаваться элемент перебираемого массива. На основе этих данных вы внутри функции можете что делать с массивом.
Здесь каждый член массива объединяется с предыдущими, получая таким обьразом "плоскую" структуру массива.
Итого, по полочкам
Тут главное понять, что reduce перебирает массив (по сути цикл), на каждом элементе вызывает функцию, функция что-то делает, возвращает результат и этот результат опять используется в этой функции на следующем элементе.