JS Object嵌套函数有效,但不知道为什么

时间:2017-03-04 05:27:46

标签: javascript loops ecmascript-6

所以我和一位同事一起工作,他向我展示了如何解决一个特定的问题:如何将扁平物体变成嵌套物体。对象属性以这样的方式命名,即可以将它们切片到其命名的相关键中,然后嵌套。他的解决方案效果很好,但是当我自己编写代码时,我无法理解它是如何工作的。

我实际上是从一个excel工作表并从中创建json但是为了论证,我将删除excel部分并添加excel解析器出来的示例结构:

//Example data
var result = {
    frame1.title: "heading",
    frame1.division: "first",
    frame1.data[0].month: "Jan",
    frame1.data[0].value: "54",
}


function deepInsert (o, path, value) {
let next, cur = o
path.forEach((p,i) => {
    next = cur[p]
    if (i == path.length -1) {
        cur[p] = value
    } else {
        if (!next) {
            next = cur[p] = {}
        }
        cur = next
    }
})
}
function processWorkbook () {

const result = json.map(item => {
    var o = {foo: "bar"}
    Object.keys(item).forEach(prop => {
        deepInsert(o, prop.split('.'), item[prop])
        console.log(JSON.stringify(o, 0, '  '));

    })
    return o
})

console.log(JSON.stringify(result, 0, '  '))
}

从我可以看出它看起来像是传递'o',这是一个空白对象,然后deepInsert函数中的循环将数据分配给param,而不是调用函数中的对象,因为每次通过循环,我的控制台日志显示更多被添加到对象。

我也不明白这一部分:next = cur[p] = {}。出于某种原因,三重分配会在chrome repl中引发错误,但在该函数中却没有?我很困惑,任何帮助都会很棒!

1 个答案:

答案 0 :(得分:1)

函数deepInsert包含以下参数:

  • 一个对象(将被修改)
  • 值的路径数组('foo.bar.x'需要成为['foo','bar', 'x']
  • 要插入的值

并且这样做:

  1. 迭代路径数组
  2. 如果当前路径迭代不是最后一个,它将初始化一个
    新的对象就可以了。
  3. 如果当前路径是最后一个路径,则将传递的值设置为它。
  4. 函数processWorkbook只是迭代对象键以将参数发送到deepInsert函数。这可以直接在deepInsert上完成。

    就是这样。问题是函数有未使用的变量和复杂的代码。一个更简单和记录的功能:

    function unnestObject(obj = {}) {
    
        let newObject = {}, //The object to return
    
            current; // the object position holder
    
        for (var key in obj) { // iterate on recived object keys
    
            current = newObject // Makes the current object the new Object root
    
            let path = key.split('.') // Split the current key
    
            path.forEach((p, i) => { // iterate on the key paths
    
                if ((path.length - 1) !== i) //if the path isn't the last one
    
                    current[p] = current[p] || {} // initialize a new object on that path (if a object was previously initialized, it is preserved)
    
                else //if the path is the last one
    
                    current[p] = obj[key] // sets the value of the initial object key
    
                current = current[p] // Updates the current to the next node
    
            })
        }
        return newObject; //returns the new object
    }
    
    //Example data [DOESNT WORK WITH ARRAYS]
    var data = {
        "frame1.title": "heading",
        "frame1.division": "first",
        "frame1.data.month": "Jan",
        "frame1.data.value": "54",
    }
    
    console.log(unnestObject(data))
    // Prints
    // {
    //   "frame1": {
    //     "title": "heading",
    //     "division": "first",
    //     "data": {
    //       "month": "Jan",
    //       "value": "54"
    //     }
    //   }
    // }
    

    注意:这两个函数都不支持数组,如果传递{"foo.bar[0].value": 42}之类的内容,foo.bar将是一个对象。您可以检测数组[]键并使其初始化数组而不是迭代中的对象

    关于next = cur[p] = {},您可以一次为多个变量分配一个值。你可以做foo = bar = 42,两人都有42。 您也可以foo = bar = {}。两者都有指向同一个对象的指针,如果你在一个上更改一个值,另一个就会有更改。

    这对于获取和初始化实例

    的全局值非常有用
    var foo = window.foo = window.foo || {bar: 42};
    

    这一行会让foowindow.foowindow.foo上收回对象。如果window.foo尚未初始化,它将重新获得新对象。