Javascript 按属性名递归搜索对象中的值

Javascript 按属性名递归搜索对象中的值,javascript,recursion,Javascript,Recursion,我正在构建一个实用函数,它应该搜索属性名,并在找到属性名后返回其值。它应该递归地执行此操作: // Function util.findVal = (object, propName) => { for (let key in object) { if (key === propName) { console.log(propName) console.log(object[key]) return object[key] } els

我正在构建一个实用函数,它应该搜索属性名,并在找到属性名后返回其值。它应该递归地执行此操作:

// Function
util.findVal = (object, propName) => {
  for (let key in object) {
    if (key === propName) {
      console.log(propName)
      console.log(object[key])
      return object[key]
    } else {
      util.findVal(object[key], propName)
    }
  }
}

// Input
object: {
  photo: {
    progress: 20
  }
}

// Usage
util.findVal(object, 'progress')
但是,控制台日志将永远消失,浏览器将崩溃。我做错了什么

编辑:

util.findVal = (object, propName) =>{
 if(!!object[propName]){
   return object[propName]
 }else{
   for (let key in object) {
     if(typeof object[key]=="object"){
      return util.findVal(object[key], propName)
     }else{
      return null
     }
  }
 }
}
这就是我调用函数的方式:

// Input

item: {
  photo: {
    file: {},
    progress: 20
  }
}

this.findProgress(item)

methods: {
  findProgress (item) {
    return util.findVal(item, this.propName)
  }
}

如果找不到钥匙,请考虑一下

我想你可以这样做,而不是搜索

return object[propName] || null 
在您的代码中缺少断点,我猜您正在尝试在整个对象中搜索,而不仅仅是直接相关的属性,因此这里是对您的代码的编辑

编辑:

util.findVal = (object, propName) =>{
 if(!!object[propName]){
   return object[propName]
 }else{
   for (let key in object) {
     if(typeof object[key]=="object"){
      return util.findVal(object[key], propName)
     }else{
      return null
     }
  }
 }
}

如果找不到钥匙,请考虑一下

我想你可以这样做,而不是搜索

return object[propName] || null 
在您的代码中缺少断点,我猜您正在尝试在整个对象中搜索,而不仅仅是直接相关的属性,因此这里是对您的代码的编辑

编辑:

util.findVal = (object, propName) =>{
 if(!!object[propName]){
   return object[propName]
 }else{
   for (let key in object) {
     if(typeof object[key]=="object"){
      return util.findVal(object[key], propName)
     }else{
      return null
     }
  }
 }
}

尝试像这样更改else语句


返回util.findVal(object[key],propName)
尝试这样更改else语句


return util.findVal(object[key],propName)

我想您是说您希望在属性和子属性的对象树中的任意位置递归查找属性名称。如果是这样的话,我会这样做:

var object1 = _getInstance(); // somehow we get an object
var pname = 'PropNameA';

var findPropertyAnywhere = function (obj, name) {
    var value = obj[name];
    if (typeof value != 'undefined') {
        return value;
    }
    foreach(var key in obj) {
        var v2 = findPropertyAnywhere(obj[key], name);
        if (typeof v2 != 'undefined') {
            return v2;
        }
    }
    return null;
}
findPropertyAnywhere(object1, pname);

我认为您的意思是希望在属性和子属性的对象树中的任意位置递归查找属性名称。如果是这样的话,我会这样做:

var object1 = _getInstance(); // somehow we get an object
var pname = 'PropNameA';

var findPropertyAnywhere = function (obj, name) {
    var value = obj[name];
    if (typeof value != 'undefined') {
        return value;
    }
    foreach(var key in obj) {
        var v2 = findPropertyAnywhere(obj[key], name);
        if (typeof v2 != 'undefined') {
            return v2;
        }
    }
    return null;
}
findPropertyAnywhere(object1, pname);

您的代码有几个错误:

  • 您正在递归调用
    util.findVal
    ,但不返回调用结果。代码应该是return util.findVal(…)
  • 您没有将属性名
    传递给递归调用
  • 您没有处理引用循环的可能性
  • 如果一个对象包含一个键以及包含该键的子对象,则返回的值是随机的(取决于分析键的顺序)
第三个问题是什么会导致无限递归,例如:

var obj1 = {}, obj2 = {};
obj1.x = obj2; obj2.y = obj1;
function findVal(obj, key) {
    var seen = new Set, active = [obj];
    while (active.length) {
        var new_active = [], found = [];
        for (var i=0; i<active.length; i++) {
            Object.keys(active[i]).forEach(function(k){
                var x = active[i][k];
                if (k === key) {
                    found.push(x);
                } else if (x && typeof x === "object" &&
                           !seen.has(x)) {
                    seen.add(x);
                    new_active.push(x);
                }
            });
        }
        if (found.length) return found;
        active = new_active;
    }
    return null;
}
如果您只是在
obj1
obj2
中递归搜索,可能会导致无限递归

不幸的是,由于Javascript中我不清楚的原因,不可能知道对象“身份”。。。(Python
id(x)
所做的)您只能将一个对象与另一个对象进行比较。这意味着要知道过去是否已经看到过某个对象,需要对已知对象进行线性扫描

ES6增加了使用对象可用作键的
Set
Map
检查对象标识的可能性。这允许更快的(次线性)搜索时间

按深度顺序运行的搜索解决方案可以是,例如:

var obj1 = {}, obj2 = {};
obj1.x = obj2; obj2.y = obj1;
function findVal(obj, key) {
    var seen = new Set, active = [obj];
    while (active.length) {
        var new_active = [], found = [];
        for (var i=0; i<active.length; i++) {
            Object.keys(active[i]).forEach(function(k){
                var x = active[i][k];
                if (k === key) {
                    found.push(x);
                } else if (x && typeof x === "object" &&
                           !seen.has(x)) {
                    seen.add(x);
                    new_active.push(x);
                }
            });
        }
        if (found.length) return found;
        active = new_active;
    }
    return null;
}
函数findVal(obj,键){
var seen=新集合,活动=[obj];
while(活动长度){
var new_active=[],found=[];

对于(var i=0;i您的代码有一些错误:

  • 您正在递归调用
    util.findVal
    ,但没有返回调用结果。代码应该是
    return util.findVal(…)
  • 您没有将属性名
    传递给递归调用
  • 您没有处理引用循环的可能性
  • 如果一个对象包含一个键以及包含该键的子对象,则返回的值是随机的(取决于分析键的顺序)
第三个问题是什么会导致无限递归,例如:

var obj1 = {}, obj2 = {};
obj1.x = obj2; obj2.y = obj1;
function findVal(obj, key) {
    var seen = new Set, active = [obj];
    while (active.length) {
        var new_active = [], found = [];
        for (var i=0; i<active.length; i++) {
            Object.keys(active[i]).forEach(function(k){
                var x = active[i][k];
                if (k === key) {
                    found.push(x);
                } else if (x && typeof x === "object" &&
                           !seen.has(x)) {
                    seen.add(x);
                    new_active.push(x);
                }
            });
        }
        if (found.length) return found;
        active = new_active;
    }
    return null;
}
如果您只是在
obj1
obj2
中递归搜索,可能会导致无限递归

不幸的是,由于Javascript中我不清楚的原因,不可能知道对象的“标识”…(Python
id(x)
所做的),您只能将一个对象与另一个对象进行比较。这意味着要知道一个对象过去是否已经被看到,您需要对已知对象进行线性扫描

ES6增加了使用对象可用作键的
Set
Map
检查对象标识的可能性。这允许更快的(次线性)搜索时间

按深度顺序运行的搜索解决方案可以是,例如:

var obj1 = {}, obj2 = {};
obj1.x = obj2; obj2.y = obj1;
function findVal(obj, key) {
    var seen = new Set, active = [obj];
    while (active.length) {
        var new_active = [], found = [];
        for (var i=0; i<active.length; i++) {
            Object.keys(active[i]).forEach(function(k){
                var x = active[i][k];
                if (k === key) {
                    found.push(x);
                } else if (x && typeof x === "object" &&
                           !seen.has(x)) {
                    seen.add(x);
                    new_active.push(x);
                }
            });
        }
        if (found.length) return found;
        active = new_active;
    }
    return null;
}
函数findVal(obj,键){
var seen=新集合,活动=[obj];
while(活动长度){
var new_active=[],found=[];
对于(var i=0;i,您可以使用

函数findVal(对象,键){
var值;
对象。键(对象)。一些(函数(k){
如果(k==键){
值=对象[k];
返回true;
}
if(对象[k]&&typeof对象[k]='object'){
value=findVal(对象[k],键);
返回值!==未定义;
}
});
返回值;
}
var object={photo:{progress:20}};
log(findVal(object,'progress'));
您可以使用它进行迭代

函数findVal(对象,键){
var值;
对象。键(对象)。一些(函数(k){
如果(k==键){
值=对象[k];
返回true;
}
if(对象[k]&&typeof对象[k]='object'){
value=findVal(对象[k],键);
返回值!==未定义;
}
});
返回值;
}
var object={photo:{progress:20}};

console.log(findVal(object,'progress'));
答案取决于您想要得到的复杂程度。例如,JSON解析的数组不包含函数,我相当确定它不会包含设置为对象树中父节点的属性值

此版本返回搜索对象树时找到的第一个属性名的属性值。
undefined
如果未找到指定属性或其值为
undefined,则返回