我正在构建一个实用程序函数,该函数应该搜索属性名称并在找到后返回其值。它应该递归地执行此操作:
// 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')
然而,控制台日志永远存在,浏览器崩溃。我做错了什么?
修改
这就是我调用该函数的方式:
// Input
item: {
photo: {
file: {},
progress: 20
}
}
this.findProgress(item)
methods: {
findProgress (item) {
return util.findVal(item, this.propName)
}
}
答案 0 :(得分:17)
您可以使用Object.keys
并使用Array#some
进行迭代。
function findVal(object, key) {
var value;
Object.keys(object).some(function(k) {
if (k === key) {
value = object[k];
return true;
}
if (object[k] && typeof object[k] === 'object') {
value = findVal(object[k], key);
return value !== undefined;
}
});
return value;
}
var object = { photo: { progress: 20 }};
console.log(findVal(object, 'progress'));
答案 1 :(得分:4)
您的代码有一些错误
您递归调用util.findVal
但未返回通话结果。代码应为return util.findVal(...)
您未将属性名称key
传递给递归调用
您没有处理参考循环的可能性
如果一个对象包含一个键,并且一个子对象包含返回值的键是随机的(取决于分析键的顺序)
第三个问题是什么可以导致无限递归,例如:
var obj1 = {}, obj2 = {};
obj1.x = obj2; obj2.y = obj1;
如果你只是继续在obj1
或obj2
中进行递归搜索,可能会导致无限递归。
不幸的是,由于我在Javascript中不清楚的原因是不可能知道对象"身份" ...(Python id(x)
做什么)你只能将一个对象与另一个对象进行比较。这意味着要知道过去是否已经看过某个物体,您需要使用已知物体进行线性扫描。
ES6增加了使用
Set
和Map
检查对象标识的可能性,其中对象可用作键。这允许更快(亚线性)搜索时间。
以深度顺序运行的搜索解决方案可以是例如
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;
}
给定一个对象和一个属性名称,返回在找到它们的第一个深度处找到的所有值(可以有多个值:例如,在搜索{x:{z:1}, y:{z:2}}
键时{{1}两个值处于相同的深度。)
该函数还可以正确处理自引用结构,避免无限搜索。
答案 2 :(得分:2)
尝试更改像这样的其他语句
return util.findVal(object[key],propName)
答案 3 :(得分:1)
如果找不到钥匙,请考虑一下。
我认为你可以做这样的事情而不是搜索
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
}
}
}
}
答案 4 :(得分:1)
我想你是说你想在属性和子属性的对象树中递归地查找属性名称。如果是这样,我将采用以下方式:
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);
答案 5 :(得分:1)
如果可以避免,请不要编写自己的实用程序。
使用类似jsonpath
一些受支持的语法示例:
JSONPath Description
$.store.book[*].author The authors of all books in the store
$..author All authors
$.store.* All things in store, which are some books and a red bicycle
$.store..price The price of everything in the store
$..book[2] The third book
$..book[(@.length-1)] The last book via script subscript
$..book[-1:] The last book via slice
$..book[0,1] The first two books via subscript union
$..book[:2] The first two books via subscript array slice
$..book[?(@.isbn)] Filter all books with isbn number
答案 6 :(得分:0)
答案取决于你想要的复杂程度。例如,JSON解析数组不包含函数 - 我相当肯定它不会包含设置为对象树中父节点的属性值。
此版本返回搜索对象树时找到的第一个属性名称的属性值。如果未找到命名属性或值为undefined
,则返回undefined
。需要进行一些修改来区分。它不会重新搜索已经搜索过的父节点,也不会尝试扫描空对象!
let util = {};
util.findVal = (object, propName, searched=[]) => {
searched.push( object)
for (let key in object) {
if (key === propName) {
return object[key]
}
else {
let obj = object[ key]
if( obj && (typeof obj == "object" || typeof obj == "function")) {
if( searched.indexOf(obj) >=0) {
continue
}
let found = util.findVal(obj, propName, searched)
if( found != searched) {
return found
}
}
}
}
searched.pop();
// not in object:
return searched.length ? searched : undefined
}
答案 7 :(得分:0)
我知道这是一篇很老的帖子,但我发现通过递归找到一个值来解决我遇到的问题很有帮助。我进一步提出了Nina Scholz给出的答案,并得出以下结论。它应该更快,因为每次递归调用时都不会创建所有键的数组。此外,如果找不到密钥,这将显式返回false。
function findVal(obj, keyToFind) {
if (obj[keyToFind]) return obj[keyToFind];
for (let key in obj) {
if (typeof obj[key] === 'object') {
const value = findVal(obj[key], keyToFind);
if (value) return value;
}
}
return false;
}
var object = { photo: { progress: 20 }};
console.log(findVal(object, 'progress'));
&#13;
答案 8 :(得分:0)
旧问题,但要检查对象层次结构中属性是否存在,请尝试使用此简单选项
var obj = {
firstOperand: {
firstOperand: {
firstOperand: {
sweptArea: 5
}
}
}
};
function doesPropertyExists ( inputObj, prop )
{
return JSON.stringify(obj).indexOf( "\""+ prop +"\":" ) != -1;
};
console.log( doesPropertyExists( obj, "sweptArea" ) );
console.log( doesPropertyExists( obj, "firstOperand" ) );
console.log( doesPropertyExists( obj, "firstOperand22" ) );
&#13;
答案 9 :(得分:0)
我最后写了这个函数。 它是这里找到的函数的重构:Recursively looping through an object to build a property list
添加了一个深度参数,以避免chrome devtools中的堆栈溢出。
function iterate(obj, context, search, depth) {
for (var property in obj) {
if (Object.prototype.hasOwnProperty.call(obj, property)) {
if(typeof obj[property] == 'function') continue;
if( property == search ){
console.log(context+property);
return;
}
if (typeof obj[property] == "object" && depth < 7) {
//console.log('--- going in: ' + context+property);
iterate(obj[property], context+property+'.', search, depth+1);
}
/*else {
console.log(context+property);
}*/
}
}
}
答案 10 :(得分:0)
在需要一个通用解决方案的领域中发现了这个问题,即检查对象是否在其层次结构中的任何位置(无论键如何)都包含特定值,而该值当然可以包括数组。因此,以下内容不能直接回答OP的问题或改进其他解决方案,但可能会帮助其他人寻找我所做的相同事情并找到这篇文章:
function hasValue(object, value) {
return Object.values(object).some(function(val) {
if (val === value) {
return true;
}
if (val && typeof val === 'object') {
return hasValue(val, value);
}
if (val && typeof val === 'array') {
return val.some((obj) => {
return hasValue(obj, value);
})
}
});
}
当然是受到@Nina Scholz解决方案的启发!
答案 11 :(得分:0)
返回具有指定名称的字段的值。
data
是根节点/对象。
keyName
是字段/成员的字符串名称。
如果keyName
指定的字段本身就是对象,则返回该对象。
function find (data, keyName) {
for (const key in data) {
const entry = data[key]
if (key === keyName)
return entry
if (typeof entry === 'object') {
const found = find(entry, keyName)
if (found)
return found
}
}
}
for
循环遍历每个字段,如果该字段是一个对象,则它将递归到该对象中。
答案 12 :(得分:0)
这是一段代码,可以在rootObj树中找到您要寻找的key
。并将其添加到根对象。因此,到最后,您将可以访问像rootObj[key]
这样的密钥。
findKeyVal(object, key, rootObj) {
if(object instanceof Object) {
let keys = Object.keys(object);
if(keys.includes(key) && !isNullOrUndefined(object[key])) {
rootObj[key] = object[key];
return;
}
else {
keys.filter(k => object[k] instanceof Object).forEach( k => {
this.findKeyVal(object[k], key, rootObj);
})
}
}
}