Нехорошо давать готовый ответ, так как ты лишаешься удовольствия решить эту задачу самостоятельно. И получается не научишься сама решать эти задачи без помощи. Но я считаю, что иногда на первых порах пока только начинаешь разбираться в JS, то можно подсказывать прямо, чтобы человек не загруз с решением задачи и не остановился в ее решении.
Вижу, что мое решение не идеальное, надо добавлять тесты и проверки и дополнять код. Это каркас, так сказать.
function isObject(obj) {
// определение типа переменной
// Object.prototype.toString.call([]) вернет '[object Array]'
// Object.prototype.toString.call({}) вернет '[object Object]'
return Object.prototype.toString.call(obj) === '[object Object]';
}
function isNumber(num) {
// определение типа переменной
// Object.prototype.toString.call(1) вернет '[object Number]'
// Object.prototype.toString.call(NaN) вернет '[object Number]'
return Object.prototype.toString.call(num) === '[object Number]';
}
// Здесь все очевидно - сравнение двух массивов
function isArraysEqual(arrFirst, arrSecond) {
if (arrFirst.length !== arrSecond.length) {
return false;
}
for (let i = 0; i < arrFirst.length; i++) {
if (arrFirst[i] !== arrSecond[i]) {
return false;
}
}
return true;
}
function objEqual(a, b) {
const keysA = Object.keys(a);
const keysB = Object.keys(b);
// Ставим все условия и проверки вначале
// если объекты не проходят проверки - то функция возвращает false
// если после прохождения всех проверок ни одна проверка не завершилась успешно
// то в конце функции objEqual() возвращаем true
if (keysA.length !== keysB.length) {
return false;
}
for (var i = 0; i < keysA.length; i++) {
const currentKey = keysA[i];
const currentAValue = a[currentKey];
const currentBValue = b[currentKey];
// 'k' in g - это для объектов, а не для массивов, проверяет входит ли ключ 'k' в объект g
// Object.keys(a) и Object.keys(b) вернет массивы, поэтому для проверки
// входит ли элемент в массив надо использовать метод массива includes()
if (!keysB.includes(currentKey)) {
return false;
}
if (Array.isArray(currentAValue)) {
// Если currentAValue имеет тип массив, а currentBValue не типа массив, то возвращаем false
// Если массивы не равны - тоже возвращаем false
if (!Array.isArray(currentBValue) || !isArraysEqual(currentAValue, currentBValue)) {
return false;
}
} else if (isObject(currentAValue)) {
// Если currentAValue имеет тип объект, а currentBValue не типа объект, то возвращаем false
// Если объекты не равны - тоже возвращаем false
// Здесь идеи рекурсия: !objEqual(currentAValue, currentBValue)
if (!isObject(currentBValue) || !objEqual(currentAValue, currentBValue)) {
return false;
}
} else if (isNumber(currentAValue) || isNumber(currentBValue)) {
// если одна из переменных имеет тип number а другая нет - значит
// эти переменные не равны
if (!isNumber(currentAValue) || !isNumber(currentBValue)) {
return false;
}
// если currentAValue равен NaN, а currentBValue не равен NaN, или наоборот, то возвращаем false
if (isNaN(currentAValue) && !isNaN(currentBValue) || !isNaN(currentAValue) && isNaN(currentBValue) ) {
return false;
}
// Если обе переменные currentAValue и currentBValue равны NaN, переходим к следующей итерации цикла
if (isNaN(currentAValue) && isNaN(currentBValue)) {
continue;
}
// если добрались до сюда, то currentAValue и currentBValue - это числа и их можно сравнивать обычным сравнением
if (currentAValue !== currentBValue) {
return false;
}
} else {
// Если дошли сюда, значит currentAValue и currentBValue - это простые типы, не объекты и не массивы и не равны NaN
// Проверяем простые типы обычным сравнением
if (currentAValue !== currentBValue) {
return false;
}
}
}
// Все проверки пройдены и ни одна не вернула false
// значит объекты равны - возвращаем true
return true;
}
const H1 = { a:5, b: { b1:6, b2:7 } };
const H2 = { b: { b1:6, b2:7 }, a:5 };
const H3 = { a:5, b: { b1:6 } };
const H4 = { a:5, b: { b1:66, b2:7 } };
const H5 = { a:5, b: { b1:6, b2:7, b3:8 } };
const H6 = { a:null, b:undefined, c:Number.NaN };
const H7 = { c:Number.NaN, b:undefined, a:null };
console.log( objEqual(H1, H2) ? 'пройден' : 'НЕ ПРОЙДЕН!' ); // => true
console.log( objEqual(H1, H3) ? 'пройден' : 'НЕ ПРОЙДЕН!' ); // => false
console.log( objEqual(H1, H4) ? 'пройден' : 'НЕ ПРОЙДЕН!' ); // => false
console.log( objEqual(H1, H5) ? 'пройден' : 'НЕ ПРОЙДЕН!' ); // => false
console.log( objEqual(H6, H7) ? 'пройден' : 'НЕ ПРОЙДЕН!' ); // => true