Javascript: получить ссылку из объекта JSON с помощью traverse - PullRequest
2 голосов
/ 05 сентября 2010

Мне нужно получить ссылку из объекта JSON, код следующий:

var Tree = {
    data: {
        0: {
            pk: 1,
        },
        1: {
            pk: 2,
        },
        2: {
            pk: 3,
            children: {
                0: {
                    pk: 11,
                },
                1: {
                    pk: 22,
                },
                2: {
                    pk: 33,
                },
            },
        },
    },

    traverse: function(data, pk) {
        for (i in data) {
            // console.log(data[i]);
            if(data[i].pk && data[i].pk == pk)
                return data[i];

            if (typeof(data[i].children) == 'object')
                this.traverse(data[i].children, pk);
        };
    },
}

Код работает очень хорошо при прохождении элементов верхнего уровня:

>>> Tree.traverse(Tree.data, 1);
Object {pk=1}

Но не работаеткогда получаем дочерний элемент:

>>> Tree.traverse(Tree.data, 22);
undefined

Мне очень странно, почему именно такое поведение, когда вы раскомментируете '// console.log (data [i]);'Строка, в которой вы увидите, что объект получен, но не возвращен.

Есть идеи?

Ответы [ 2 ]

6 голосов
/ 05 сентября 2010

Вы не поставили return до this.traverse(data[i].children, pk);.


EDIT:

var Tree = {
    data: {
        0: {
            pk: 1,
        },
        1: {
            pk: 2,
        },
        2: {
            pk: 3,
            children: {
                0: {
                    pk: 11,
                },
                1: {
                    pk: 22,
                },
                2: {
                    pk: 33,
                },
            },
        },
    },

    traverse: function(data, pk) {
        for (var i in data) {
            // console.log(data[i]);
            if(data[i].pk && data[i].pk == pk)
                return data[i];

            if (typeof(data[i].children) == 'object') {
                var retVal = this.traverse(data[i].children, pk);
                if (typeof retVal!='undefined') {//here was the logical problem,there might be more than one
                                                 //object, we can't return the result of traversing first one.
                                                 //So we will check, if no return, we go on searching
                    return retVal;
                }
            }

        };
    },
};

alert(Tree.traverse(Tree.data, 1).pk);
alert(Tree.traverse(Tree.data, 22).pk);

проверить в прямом эфире здесь: http://jsfiddle.net/rq4LK/

0 голосов
/ 05 сентября 2010

Это длинный выстрел, но вы создаете глобальную переменную в цикле for.Попробуйте вместо этого for(var i in data), а затем сообщите, пожалуйста.

Если это не весь объект и у вас есть свойство с ключом (например, 3: ...) в родительском литерале Object, которого нет в дочернем свойстве children, оно, очевидно, будетвернуть undefined, поскольку у этого ключа такого свойства нет.

Редактировать: Согласно вашему комментарию, это также может быть проблемой с областью действия функции, так как вы используете хвостовая рекурсия для перебора объекта с несколькими слоями.Таким образом, попытайтесь поместить текущую ссылку на объект вне области действия функции, как это было бы в любой конструкции языка JavaScript, которая требует динамической ссылки:

var current = null , match = null ;

function traverse() {

    var data = arguments[0] ;
    var pk = arguments[1] ;

        for(var i in data) {

                current = data[i] ; /* DEBUG */console.log( current.toSource() ) ; //!! Object.prototype.toSource() requires a W3 compatible browser (like FF)

                if(current.pk !== undefined && current.pk === pk) return current ;
                else if( typeof current.children === "object") traverse(current.children, pk);

         }
}

match = traverse(data,pk) ;

Редактировать 2: Ошибка логики на моемчасть.Попробуйте вместо этого:

var match = null ;

function traverse() {

    var data = arguments[0] ;
    var pk = arguments[1] ;

    var current = null ;

        for(var i in data) {

                current = data[i] ; /* DEBUG */console.log( current.toSource() ) ; //!! Object.prototype.toSource() requires a W3 compatible browser (like FF)

                if(current.pk !== undefined && current.pk === pk) match = current ; //!! if there is a match set the variable match to the current object
                else if( typeof current.children === "object") traverse(current.children, pk); //!! else use recursion to test a child property if present

         }

}

Используя это, если ваш объект содержит указанное свойство, match не будет null и будет содержать соответствующий объект или дочерний объект.

...