将javascript点符号对象转换为嵌套对象

IT技术 javascript
2021-01-24 01:53:36

我正在尝试构建一个可以扩展对象的函数,例如:

{
    'ab.cd.e' : 'foo',
    'ab.cd.f' : 'bar',
    'ab.g' : 'foo2'
}

进入嵌套对象:

{ab: {cd: {e:'foo', f:'bar'}, g:'foo2'}}

像这个 php 函数:Set::expand()

当然不使用 eval 。

6个回答

我相信这就是你所追求的:

function deepen(obj) {
  const result = {};

  // For each object path (property key) in the object
  for (const objectPath in obj) {
    // Split path into component parts
    const parts = objectPath.split('.');

    // Create sub-objects along path as needed
    let target = result;
    while (parts.length > 1) {
      const part = parts.shift();
      target = target[part] = target[part] || {};
    }

    // Set value at end of path
    target[parts[0]] = obj[objectPath]
  }

  return result;
}

// For example ...
console.log(deepen({
  'ab.cd.e': 'foo',
  'ab.cd.f': 'bar',
  'ab.g': 'foo2'
}));

@brandonscript 我相信这适用于多个顶级属性。我与测试pizza/ this.other/this.thing.that在你的答案例子,并得到相同的结果你。
2021-03-20 01:53:36
如果您有一个同名的顶级属性,这是有风险的。从包装t=oo;t[key] = o[k]if (k.indexOf('.') !== -1)...
2021-04-01 01:53:36
如果您有多个顶级密钥,它也不起作用。
2021-04-08 01:53:36
我只是在下面提供了一个更全面的解决方案:github.com/Gigzolo/dataobject-parser
2021-04-10 01:53:36

如果您使用的是 Node.js(例如 - 如果没有从我们的module中剪切和粘贴),请尝试这个包:https : //www.npmjs.org/package/dataobject-parser

构建了一个执行正向/反向操作的module:

https://github.com/Gigzolo/dataobject-parser

它现在被设计为一个自我管理的对象。通过实例化 DataObjectParser 的实例使用。

var structured = DataObjectParser.transpose({
    'ab.cd.e' : 'foo',
    'ab.cd.f' : 'bar',
    'ab.g' : 'foo2'
});                                                                                                                                                                                                                                                                                                                                                                                                                                                   

structured.data() 返回您的嵌套对象:

{ab: {cd: {e:'foo', f:'bar'}, g:'foo2'}}

所以这是 JSFiddle 中的一个工作示例:

http://jsfiddle.net/H8Cqx/

函数名称很糟糕,代码很快就完成了,但它应该可以工作。请注意,这会修改原始对象,我不确定您是否要创建一个旧对象的扩展版本的新对象。

(function(){

    function parseDotNotation( str, val, obj ){
    var currentObj = obj,
        keys = str.split("."), i, l = keys.length - 1, key;

        for( i = 0; i < l; ++i ) {
        key = keys[i];
        currentObj[key] = currentObj[key] || {};
        currentObj = currentObj[key];
        }

    currentObj[keys[i]] = val;
    delete obj[str];
    }

    Object.expand = function( obj ) {

        for( var key in obj ) {
        parseDotNotation( key, obj[key], obj );
        }
    return obj;
    };

})();



var expanded = Object.expand({
    'ab.cd.e' : 'foo',
        'ab.cd.f' : 'bar',
    'ab.g' : 'foo2'
});



JSON.stringify( expanded );  


//"{"ab":{"cd":{"e":"foo","f":"bar"},"g":"foo2"}}"
这很好,但只有在只有一个顶级密钥时才有效。如果你有{"foo":"bar", "foo.baz":"bar", "baz":"bar"}它会放下“baz”键。
2021-04-02 01:53:36

源自Esailija 的答案,修复了支持多个顶级键的问题。

(function () {
    function parseDotNotation(str, val, obj) {
        var currentObj = obj,
            keys = str.split("."),
            i, l = Math.max(1, keys.length - 1),
            key;

        for (i = 0; i < l; ++i) {
            key = keys[i];
            currentObj[key] = currentObj[key] || {};
            currentObj = currentObj[key];
        }

        currentObj[keys[i]] = val;
        delete obj[str];
    }

    Object.expand = function (obj) {
        for (var key in obj) {
            if (key.indexOf(".") !== -1)
            {
                parseDotNotation(key, obj[key], obj);
            }            
        }
        return obj;
    };

})();

var obj = {
    "pizza": "that",
    "this.other": "that",
    "alphabets": [1, 2, 3, 4],
    "this.thing.that": "this"
}

输出:

{
    "pizza": "that",
    "alphabets": [
        1,
        2,
        3,
        4
    ],
    "this": {
        "other": "that",
        "thing": {
            "that": "this"
        }
    }
}

Fiddle

您可以将键字符串拆分为路径,并通过使用未访问级别的默认对象来减少它以分配值。

function setValue(object, path, value) {
    var keys = path.split('.'),
        last = keys.pop();

    keys.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
    return object;
}

var source = { 'ab.cd.e': 'foo', 'ab.cd.f': 'bar', 'ab.g': 'foo2' },
    target = Object
        .entries(source)
        .reduce((o, [k, v]) => setValue(o, k, v), {});

console.log(target);

如果我们有一个键重复两次怎么办?看起来它只保留最后一个值......
2021-03-19 01:53:36
@ user3174311,对。你想得到什么?
2021-04-02 01:53:36
如果一个键重复,我想得到一个数组或对象。谢谢。
2021-04-03 01:53:36
@ user3174311,在这种特殊情况下,您可以检查该属性是否具有值并将类型更改为具有第一个值的数组。但这也需要检查是否已经给出了值。也许您针对这个问题提出了一个新问题,并添加了您尝试过的内容。
2021-04-08 01:53:36
我在这里问过:stackoverflow.com/questions/58482952/…… 我要添加一些我试过的。谢谢你。
2021-04-08 01:53:36