从深层对象获取属性值

时间:2014-10-10 19:01:03

标签: javascript

我的目标:创建一种从多级javascript对象获取属性值的方法。

例如,这是一个我想要从以下位置获取属性值的对象:

var originalCookieObject = {
        User: "notmyemail@gmail.com",
        GridStates: {
            gridName : {
                "page": 1,
                "pageSize": 50,
                "sort": [
                            {
                                field: "CommonName",
                                dir: "desc"
                            }
                        ]
            }
        },
        ProtectionState: {
            SelectedRow: "string",
            PanelsOpen: ['string', 'string']
        }
    }

以下是我如何检索该属性的值:

getProperty(originalCookieObject, 'gridName');

到目前为止,我尝试过以下递归函数:

function traverse(toTraverse, findKey) {
    if( typeof toTraverse == "object" ) {
        var foundValue = toTraverse[findKey];
        if (foundValue){ return foundValue; }

        $.each(toTraverse, function(k,v) {
            // k is either an array index or object key
            traverse(v, findKey);
        });
    }
}
var objectValue = traverse(originalCookieObject, 'gridName');
console.log(objectValue);

我的问题是,当我尝试深入多个级别时,当前traverse()调用仅将属性值返回到父级traverse()调用。

我的问题:

  1. 如何让孩子traverse()调用将属性值返回到父traverse()函数?
  2. 有更好的方法吗?

3 个答案:

答案 0 :(得分:1)

var originalCookieObject = {
    User: "notmyemail@gmail.com",
    GridStates: {
        gridName : {
            "page": 1,
            "pageSize": 50,
            "sort": [
                {
                    field: "CommonName",
                    dir: "desc"
                }
            ]
        }
    },
    ProtectionState: {
        SelectedRow: "string",
        PanelsOpen: ['string', 'string']
    }
}

function traverse(toTraverse, findKey) {
    if( typeof toTraverse == "object" ) {
        var foundValue = toTraverse[findKey];
        if (foundValue){ return foundValue; }

        $.each(toTraverse, function(k,v) {
            // k is either an array index or object key
            foundValue = traverse(v, findKey) || foundValue;
        });
        return foundValue;
    }
}

var objectValue = traverse(originalCookieObject, 'SelectedRow');
console.log(objectValue);

你几乎就在那里,只需要将嵌套遍历调用的结果赋给var,然后在函数末尾返回它

updated jsfiddle

答案 1 :(得分:1)

您需要检查是否有返回值,然后将其存储在变量中:

function traverse(toTraverse, findKey) {
    if( typeof toTraverse == "object" ) {
        var foundValue = toTraverse[findKey];
        if (foundValue){ return foundValue; }
        var returnVal;
        $.each(toTraverse, function(k,v) {
            // k is either an array index or object key
           returnVal = traverse(v, findKey) || returnVal; //set/overwrite the returnVal if there is one
        });
        return returnVal; //return the value to parent, parent will return it further
    }
}
var objectValue = traverse(originalCookieObject, 'gridName');
console.log(objectValue);

因此,如果找到了值,则始终返回值undefined或值本身。这将一直持续到它返回顶部。实际值将始终用于undefined

答案 2 :(得分:1)

  

如何让子traverse()调用将属性值返回到父traverse()函数?

通过将“child”调用的返回值存储在变量中并返回它。

  

有更好的方法吗?

你必须以递归方式遍历结构。使用for...in会使它更容易一些,因为你可以直接从循环体返回而不必使用中间变量。

但是,您实施的两个问题是:

  1. 如果搜索到的密钥具有虚假值(因为if (foundValue){ ... }),则会失败;
  2. 即使你找到了价值,你仍然会继续寻找(好吧,在你的情况下,你甚至不知道什么时候你找到了价值,但其他答案都有这个问题)。
  3. 如果数据结构包含多个具有相同名称的键,则只能获得第一个键。这是否是一个问题取决于您正在使用的数据。
  4. 以下解决方案负责1.和2.:

    function traverse(toTraverse, findKey) {
        if( typeof toTraverse == "object" ) {
            if (toTraverse.hasOwnPropert(findKey)) { // does object have this property?
                return toTraverse[findKey];
            }
            var foundValue;
    
            $.each(toTraverse, function(k,v) {
                var value = traverse(v, findKey);
                if (typeof value !== 'undefined') {
                    foundValue = value;
                    return false; // stop looking
                }
            });
    
            return foundValue;
        }
    }
    

    有关详细信息,请参阅jQuery.each

    警告:此解决方案仍然无法正确处理值为undefined的属性(例如{foo: undefined}),但在大多数情况下都可以。