JavaScript精解练习:深度比较

3
我正在学习JavaScript,并尝试完成以下练习:
编写一个名为deepEqual的函数,它接受两个值作为参数,仅当它们是相同的值或具有相同属性的对象且属性值通过对deepEqual的递归调用进行比较时相等时,才返回true
要确定应该直接比较值(使用===操作符),还是比较它们的属性,您可以使用typeof操作符。如果它对于两个值都产生“object”,那么您应该进行深度比较。但是您必须考虑一个愚蠢的例外:由于历史原因,typeof null也会产生“object”。
在需要遍历对象属性进行比较时,Object.keys函数会很有用。
以下是我的解决方案,但它给我返回了truefalsefalse,这是不正确的。
function deepEqual (a,b) {
    if (a===b) return true;
    if (typeof a=="object" && typeof b=="object") {         
        let x=Object.keys(a), y=Object.keys(b);
        if (x.lenght==y.lenght) {
            for (key of x){
                if (y.includes(key)){
                    if (a[key]===b[key]) return true;
                    else return false;
                }
            }
        }
        return true;
    } 
}

let obj = {here: {is: "an"}, object: 2};
console.log(deepEqual(obj, obj));    
console.log(deepEqual(obj, {here: 1, object: 2}));
console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));

这是正确的解决方案:
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;
}


let obj = {here: {is: "an"}, object: 2};
console.log(deepEqual(obj, obj));
// → true
console.log(deepEqual(obj, {here: 1, object: 2}));
// → false
console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));
// → true

我真的不明白我写的有什么问题,该怎么修复它。
非常感谢您帮助一个新手 :)

2
你没有深入嵌套对象; 这是一个经典的递归问题。 length 拼错了。 - Dave Newton
我尝试了:function deepEqual(a, b) { if (a === b) return true; if (typeof a == "object" && typeof b == "object") { let x = Object.keys(a), y = Object.keys(b); if (x.length == y.length) { for (key of x) { if (y.includes(key)) { if (a[key] === b[key]) return true; else return false; } } } return true; } else return false; } let obj = {here: {is: "an"}, object: 2}; console.log(deepEqual(obj, obj));但仍然无法正常工作... - Lorenzo Case Del Rosario
2
这作为注释是无法阅读的。length 仍然拼错了,而且它仍然没有深入嵌套对象。 - Dave Newton
将解决方案分解并映射到您编写的内容。您很容易看到您的解决方案在哪些点上做得不对。 - aksappy
1个回答

2
以下是您代码中的问题: 1)对象测试:
if (typeof a=="object" && typeof b=="object") {

这很好,但如果这个条件不成立呢?你没有处理这种情况的代码,所以函数将返回 undefined。它应该返回 false
其次,在JavaScript中有一件奇怪的事情,问题已经警告过你了 - 你应该考虑到它:
由于历史原因,null 的类型也是 "object"。所以你需要有一个单独的测试来判断,因为 null 不是真正的对象,当你把它当作对象处理时,代码会产生错误。
在你的代码中,一个 null 值会通过这个 if 测试,然后执行 Object.keys(null),这会触发一个异常。一个 null 值不应该允许出现在那里。
2) 比较属性的数量
    if (x.lenght==y.lenght) {

有一个拼写错误。不是 lenght,而是 length(2x)。 再次提醒,如果这个条件不成立怎么办?除了在那个 if 块之后的 return true 之外,没有任何代码处理这种情况,但你的函数应该返回 false

3) 检查两个对象是否都存在某个属性

            if (y.includes(key)){

这个测试可以工作,但不是最优的。使用includes比仅检查key in b要慢(遗憾的是参考解决方案也使用了includes)。
并且,如果这个条件不成立呢?函数应该立即退出循环并返回false,但这并没有发生...
4) 检查相同属性的值是否深度相等。
                if (a[key]===b[key]) return true;

这个条件没有进行深度比较。问题已经告诉你该怎么做了:
“...其中属性的值通过递归调用deepEqual进行比较相等。”
所以这里应该执行递归调用,以便任何嵌套对象都可以以相同的方式进行比较。只有a[key]===b[key]时,才会返回false,当这两个值是不同的对象时。但是,当这些对象具有相同的属性和相同的属性值时,条件应该是真的......这正是您的函数能够做到的:因此,在这里“调用”它。
其次,这不是“返回true”的时候,因为这会在未检查其他键的情况下退出循环,那里的结果可能是负面的......一个“否定”就足以使整体结果变为false。所以,当一切顺利时,你应该“继续”循环。
第5点:当值不同时
                else return false;

现在是使用return false的正确时间。

6) 当所有测试都成功时

    return true;

这是唯一一个正确的地方,可以使用return true,但是你应该解决我答案中的第二个备注,以便在长度不同时不执行此语句。

正确的代码

由于您已经有了正确的比较代码,因此在这里重复该代码有点过度。


你帮了我很多,非常感谢!我改成了这样但还是不起作用:codefunction deepEqual (a,b){ if (a===b) return true; if (typeof a==null || typeof b==null)return false; else { if (typeof a=="object" && typeof b=="object") { let x=Object.keys(a), y=Object.keys(b); if (x.length==y.length) { for (key of x){ if (y.includes(key)){ if (deepEqual(a[key], b[key])); else return false; } else return false; } return true; } else return false; } return true; } return false; }code - Lorenzo Case Del Rosario
它在第二个“else return false”处出现错误,错误是“意外的标记'else'”。抱歉,如果我没有发布格式良好的代码,但我是新手,不知道如何在评论中插入代码。 - Lorenzo Case Del Rosario
几件事情:typeof a == null 永远不会成立。请阅读我引用的问题中的关键短语?当 a === null 时,typeof a === "object"。您应该只测试 a===null - trincot
你在一些没有对应的 if 来抵消的地方使用了 else 关键字。正确缩进你的代码以检测哪些 else 是没有对应的 if 而悬挂的。 - trincot
我已经检查了多次,对我来说似乎每个条件都有其自己的作用...也许有一些基础知识我没有理解。 - Lorenzo Case Del Rosario
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接