如何使用递归函数正确确定多维javascript对象中是否存在键
我试图创建一个递归函数,该函数将在多维对象中循环,并测试键是否存在于单独的对象中。如果键不存在,我想中断循环并返回false;如果所有键都存在,我想返回true 我遇到的问题是,函数似乎总是返回true。以下是我正在使用的代码:如何使用递归函数正确确定多维javascript对象中是否存在键,javascript,recursion,Javascript,Recursion,我试图创建一个递归函数,该函数将在多维对象中循环,并测试键是否存在于单独的对象中。如果键不存在,我想中断循环并返回false;如果所有键都存在,我想返回true 我遇到的问题是,函数似乎总是返回true。以下是我正在使用的代码: var properties = {'global': {'structure' : {'body': {}}}}; var testExists = {'global': {'structure': {'test': 'value'}}}; if( ! this.
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”的值时,我看到两行,第一行为false,第二行为true,因此我创建的递归肯定存在错误您的问题似乎是没有使用递归调用函数的结果 此外,您不应该使用
参数.callee
,而应该使用函数名,并在枚举其属性之前检查参数是否为对象。您可能还想检查目的地的属性是否不在枚举源中
试试这个:
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;
}
你让事情变得比需要的更复杂:
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
,true
,true
-您期望什么?我想在出现false时立即中断循环/函数并返回false。因此,当到达testExists对象中的键“test”时,因为它不存在于properties对象中,我希望函数返回false对于该对象,您的函数确实返回了false
,但是该返回值并不会阻止调用函数返回true
。请注意,您可以命名函数并将其分配给对象属性或变量。如果同时执行这两种操作,函数名将仅在函数内部可见,这意味着您仍然可以递归调用它,而不会污染名称空间。这是两全其美的。如果其中任何一个参数都是“真实对象”,那么就不需要进行那种笨拙的检查,因为..in将愉快地对数字或字符串进行操作。另一方面,hasOwnProperty很重要。@Kiyura:for in
将愉快地在Number
/String
.prototype
上循环任何可枚举属性。它也将在普通对象上循环任何可枚举属性。正如我在回答中所指出的,重要的是要包含一个hasOwnProperty检查,或者干脆用它完全取代falsy检查。这不一定是想要的,也不符合实际情况。只要检查一下当使用exists({proof:“someString”},{proof:{toString:{oops:true}}}})调用函数时,函数会做什么。
函数不会检查对象的所有属性,您应该提及或修复它。这不是我的论点-您的函数无法处理具有多个属性的对象。此函数要么总是返回false,要么我收到“超过最大调用堆栈大小”错误听起来像是在对大型对象调用此函数。递归函数总是有超过调用堆栈大小的风险。如果希望它在任意大小的对象上工作,则需要迭代地重新实现。您能用一个较小的示例(在JSFIDLE中)演示它在不希望返回false时是如何返回false的吗?你明白这个函数在做什么吗?这会为我生成一个“超过最大调用堆栈大小”错误-