无法理解此展平对象上的“递归和闭包范围”

时间:2014-07-22 06:17:07

标签: javascript object recursion

我应该想要展平一个对象,为此我使用这个函数:

var flatter = function(ob){
    var f = {};
    for(var i in ob) {
        if(typeof ob[i] == 'object') {
            var newOb = flatter(ob[i]);
            for(var x in newOb) {
                f[i+'.'+x] = newOb[x];
            }
        }else{
            f[i] = ob[i];
        }
    }
    return f;
}

工作正常。我得到了适当的结果来应用这个对象:

var ob = {
    "address" : {
        "details" : {
            "first" : "siva",
            "last" : "sankara",
            "mam":["mam1","mam2"]
        }
    }
};

结果是:

reslut : Object {address.details.first: "siva", address.details.last: "sankara", address.details.mam.0: "mam1", address.details.mam.1: "mam2"} 

但是我无法理解我得到的结果。我理解,这是以recursionclosure scope为导向的 - 但是搜索谷歌我没有得到任何明确的教程或文章。

有人帮我逐步理解这一点吗?

Here is the live demo

提前致谢!

2 个答案:

答案 0 :(得分:1)

function flatter(ob){
    'use strict';
    var f = {}, //return this
        key;
    for(key in ob) { //for each key
        if (ob.hasOwnProperty(key)) {
            if(typeof ob[key] === 'object') {   //if value is object
                //flatten this object again. Assign result to newOb
                var newOb = flatter(ob[key]);   
                for(var x in newOb) {
                    f[key + '.' + x] = newOb[x];
                }
            } else {
                f[key] = ob[key];
            }
        }
    }
    return f;
}

你可以用这样的代码翻译这段代码

function flatter(ob){
    'use strict';
    var f = {}, //return this object
        key;
    for(key in ob) { //for each key
        if (ob.hasOwnProperty(key)) {
            if(typeof ob[key] === 'object') {   //if value is object
                var newOb = (function (ob) {
                    'use strict';
                    var f = {}, //return this object
                        key;
                    for(key in ob) { //for each key
                        if (ob.hasOwnProperty(key)) {
                            if(typeof ob[key] === 'object') {   //if value is object
                                var newOb = flatter(ob[key]);
                                for(var x in newOb) {
                                    f[key + '.' + x] = newOb[x];
                                }
                            } else {
                                f[key] = ob[key];
                            }
                        }
                    }
                    return f;
                }(ob[key]));
                for(var x in newOb) {
                    f[key + '.' + x] = newOb[x];
                }
            } else {
                f[key] = ob[key];
            }
        }
    }
    return f;
}

主要思想是每个函数调用都可以被这个函数的主体代替 对象本身是一个递归结构,因为它可以是内容对象。如果给出

{
    id: 12345,
    name: 'John',
    friends: [12346, 75645, 96768]
}

不需要递归。对象不包含任何对象,因此它可以在没有附加函数调用的情况下被绑定(顺便说一下它是平的)。如果给出

{
    id: 12345,
    name: {
        first: 'John',
        last: 'Doe'
    },
    friends: [12346, 75645, 96768]
}

然后对象包含对象作为字段。所以你可以使用函数flatter,其中函数调用被函数体代替。如果给出

{
    id: 12345,
    name: {
        first: 'Helen',
        last: {
            beforeMarriage: 'Dobsky',
            afterMarriage: 'Bobsky'
        }
    },
    friends: [12346, 75645, 96768]
}

然后一个人离不开3个函数调用。所以你可以复制三次函数体。但是,对象可以具有[无限]非常深的结构。所以函数的嵌套体的数量是未知的。因此,不是将函数体嵌套到函数中,而是使用递归调用 递归函数应至少有一个退出点以避免无限递归

return f;

在我们的案例中。可以到达此出口点,因为对象中的字段数是有限的。这不是解决任务的唯一方法。对象看起来像树(一种)递归可以用栈代替,它保留了复杂的字段,在处理完简单字段后返回到对象堆栈并在循环中处理它们。

堆栈实现。不漂亮,但有效)

function iflatter(input) {
    'use strict';
    var f = {}, //return this object
        key,
        stack = [],
        ob,
        prefix,
        name;
    stack.push(["", input]);
    while (stack.length != 0) {
        [prefix, ob] = stack.pop();
        for(key in ob) { //for each key
            if (ob.hasOwnProperty(key)) {
                if (prefix !== "") {
                    name = prefix + "." + key;
                } else {
                    name = key;
                }
                if(typeof ob[key] === 'object') {
                    stack.push([name, ob[key]]);
                } else {
                    f[name] = ob[key];
                }
            }
        }
    }
    return f;
}

答案 1 :(得分:0)

您正在将对象传递给flatter()。当Object具有一个具有Object本身值的属性时,它会再次将该Object传递给flatter(),或者递归传递。见if(typeof ob[i] == 'object')?这意味着如果ob具有属性i并且其值(得到ob[i])是一个对象。注意var flatter = function(){}相当于function flatter(){}