【问题标题】:How to correctly determine if key exists in multidimensional javascript object using a recursive function如何使用递归函数正确确定多维javascript对象中是否存在键
【发布时间】:2012-10-01 19:30:54
【问题描述】:

我正在尝试创建一个递归函数,该函数将遍历多维对象并测试键是否存在于单独的对象中。如果键不存在我想打破循环并返回false,如果所有键都存在我想返回true。

我遇到的问题是该函数似乎总是返回 true。这是我正在使用的代码:

var properties = {'global': {'structure' : {'body': {}}}};

var testExists = {'global': {'structure': {'test': 'value'}}};

if( ! this.exists(properties, testExists)) {
   console.log("DOESNT EXIST");
}


exists: function(destination, source) {
    var exists = true;

    check:
    for (var property in source) {

        if(destination[property]) {
            arguments.callee(destination[property], source[property]);
        }
        else
        {
            exists = false;
            break check;
        }
    }

    console.log(exists);

    return exists;
},

当我查看控制台以查看 'exists' 的值时,我看到两行第一行为假,第二行为真,因此我正在创建的递归一定有错误

【问题讨论】:

  • 在执行你的代码时,我看到falsetruetrue - 你期待什么?
  • 我想一有错误就中断循环/函数并返回错误。因此,在到达 testExists 对象中的关键“测试”时,因为它在属性对象中不存在,我希望函数返回 false
  • 您的函数确实为该对象返回false - 但该返回值不会阻止调用函数返回true

标签: javascript recursion


【解决方案1】:

您的问题似乎是您没有使用递归调用函数的结果。

此外,您不应该使用arguments.callee,而是使用函数名,并可能在枚举其属性之前检查参数是否为对象。您可能还想检查不在枚举source 中的destination 的属性。

试试这个:

function equal(destination, source) {
    if (Object(destination)!==destination || Object(source)!==source)
        // at least one of them is a primitive value
        return destination == source; // maybe use strict equality === ?
    for (var prop in source)
        if (!(prop in destination) || !equal(source[prop], destination[prop]))
            return false;
    return true;
}

【讨论】:

  • 请注意,您可以命名一个函数并将其分配给对象属性或变量。如果两者都做,则函数的名称将仅在函数内部可见,这意味着您仍然可以递归调用它而不会污染命名空间。这是两全其美的。
  • 如果任一参数是“真实对象”,则无需进行那种尴尬的检查,因为..in 会很高兴地对数字或字符串进行操作。另一方面,hasOwnProperty 很重要。
  • @Kiyura:for in 将愉快地循环遍历Number/String.prototype 上的任何可枚举属性。
  • 它也会遍历普通对象上的任何可枚举属性。正如我在回答中所展示的,重要的是包含一个 hasOwnProperty 检查,或者完全用它替换虚假检查。
  • 这不一定是想要的,也与案例不匹配。只需检查您的函数在使用 exists({proof:"someString"}, {proof:{toString:{oops:true}}}) 调用时的作用
【解决方案2】:

你让它变得比它需要的更复杂:

function exists(destination, source) {
    for (var property in source) {
        if(destination.hasOwnProperty(property)) {
            if (!exists(destination[property], source[property])) {
                return false;
            }
        } else {
            return false;
        }
    }

    return true;
}​

请注意,.hasOwnProperty 意味着这只会比较对象的直接属性,而不是从原型继承的属性。我以为这就是你要找的东西。

另请注意:它实际上使用递归调用的结果,它正确递归,它使用 .hasOwnProperty 而不是仅检查虚假性,并且它不使用中间变量来存储结果(这在无论如何,以您使用它们的方式递归)。

还有一件事:这只会“单向”,即不会检查目标中不在源中的任何属性。要同时检查这两种方式,您必须调用它两次或将其扩展为在两者上循环。

【讨论】:

  • 您的函数不会检查对象的所有属性,您应该提及或修复它。
  • 这不是我的论点——你的函数不能处理具有多个属性的对象。
  • 这个函数要么总是返回 false,要么我得到一个“超出最大调用堆栈大小”错误
  • 听起来你在一个巨大的物体上调用它。递归函数总是会带来超出调用堆栈大小的风险。如果您希望它适用于任意大小的对象,则需要迭代地重新实现它。你能用一个更小的例子(在一个 jsfiddle 中)演示它是如何在你不期望的时候返回 false 的吗?你明白这个函数在做什么吗?
  • 这会为我生成一个“超出最大调用堆栈大小”错误 - jsfiddle.net/9g72p/1
猜你喜欢
  • 1970-01-01
  • 2015-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-11
  • 2010-11-13
  • 2021-04-06
  • 2019-12-16
相关资源
最近更新 更多