javascript - 无法理解此展平对象上的 ` recursion and closure scope`

标签 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"} 

但是我无法理解我得到的结果。我知道,这是面向递归闭包范围 - 但是搜索谷歌我没有得到任何明确的教程或文章。

有人可以帮助我一步一步地理解这一点吗?

Here is the live demo

提前致谢!

最佳答案

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]
}

然后对象包含对象作为字段。因此,您可以使用 function 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;
}

关于javascript - 无法理解此展平对象上的 ` recursion and closure scope`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24880182/

相关文章:

javascript - 两种类型的输入由选项卡分隔,我只能传递选项卡被选中的输入

javascript - RingCentral 调用管理

iphone - 隐藏在其他类中声明的TableView

Python:如何检查一个对象是否是一个模块?

javascript - 网站可以在 Firefox 和 Chrome 中运行,但不能在 Internet Explorer 中运行

recursion - Elixir map_reduce 引用最后一个元素

javascript - onBeforeUnload 突然无法按预期工作

javascript - 可调整大小的 div 中的 Bootstrap 网格系统响应实用程序

c - 语言 : C; Compute a series recursive and iterative

database - Prolog - 坚持作业 - 使用数据库并输入 2 个值以从数据库中获取第三个值