递归遍历javascript对象并按键替换值

时间:2016-10-10 09:54:38

标签: javascript json node.js recursion

由于JSON无法执行函数,因此我需要通过JSON对象中的键标志来评估JSON字符串。我想以对象形式改变JSON数据。

我无法在线找到一个功能/方法,可以根据已知的密钥模式为我提供密钥的完整路径。

鉴于此数据:

  {
    "js:bindto": "#chart-1", // note the key here 'js:'
    "point": {
        "r": 5
    },
    "data": {
        "x": "x",
        "xFormat": "%Y",
        "columns": [
            ...
        ],
        "colors": {
            "company": "#ed1b34",
            "trendline": "#ffffff"
        }
    },
    "legend": {
        "show": false
    },
    "axis": {
        "x": {
            "padding": {
                "left": 0
            },
            "type": "timeseries",
            "tick": {
                "format": "%Y",
                "outer": false
            }
        },
        "y": {
            "tick": {
                "outer": false,
                "js:format": "d3.format(\"$\")" // note the key here 'js:'
            }
        }
    },
    "grid": {
        "lines": {
            "front": false
        },
        "y": {
            "lines": [...]
        }
    }
}

标志是以js:开头的键。

如果我查找js:format,我希望它的路径类似于:/js:bindto/axis/y/tick/js:format。接受建议。

在上下文中:

mutateGraphData<T>(data:T):T {
   // data here is a parsed JSON string. ( an object as shown above )

    let jsonKeys = this.findKeysInJSON(JSON.stringify(data), "js:");

    // jsonKeys = ["js:bindto","js:format"]
        jsonKeys.map((key:string) => {
          // find the key in data, then modify the value. (stuck here)
         // i need the full path to the key so i can change the data property that has the key in question
        });
    });
    return data;
}

findKeysInJSON<T>(jsonString:string, key:string):Array<T> {
        let keys = [];
        if (Boolean(~(jsonString.indexOf(`"${key}`)))) {
            let regEx = new RegExp(key + "(\\w|\\-)+", "g");
            keys = jsonString.match(regEx);
        }
        return keys;
}

我已经参加了几个npm套餐:

我看了

我看到的任何内容都无法返回相关密钥的完整路径,因此我可以对其进行修改,也不会直接在对象本身上工作,因此我可以更改其属性。

3 个答案:

答案 0 :(得分:1)

你可以选择Ramda。它内置了函数,允许您以完全不可变的方式映射对象并修改对象的各个部分。

Ramda提供R.lensPath,允许您深入挖掘对象,并根据需要进行修改。它不遵循您想要的模式,但我们可以使用lensify函数快速修补它。

正在使用R.set函数将节点设置为传入的值,并创建一个将在传入的对象上运行所有操作的管道。

你可以用ramda和镜头做一些非常酷的东西。在livecoding.tv上查看evilsoft以获得非常好的概述。

const obj={"js:bindto":"#chart-1",point:{r:5},data:{x:"x",xFormat:"%Y",columns:[],colors:{company:"#ed1b34",trendline:"#ffffff"}},legend:{show:!1},axis:{x:{padding:{left:0},type:"timeseries",tick:{format:"%Y",outer:!1}},y:{tick:{outer:!1,"js:format":'d3.format("$")'}}},grid:{lines:{front:!1},y:{lines:[]}}}

const lensify = path => R.lensPath(path.split('/'))
// create the property accessors split by /
const bindToLens = lensify('js:bindto')
const formatLens = lensify('axis/y/tick/js:format')

const modifyObj = R.pipe(
  R.set(bindToLens, 'dis be bind'),
  R.set(formatLens, 'I been here')
)

console.log(modifyObj(obj))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>

答案 1 :(得分:0)

在浏览一下后,我修改了Javascript/JSON get path to given subnode? @ adam-rackis

的答案
function search(obj, target, path = "") {
    for (var k in obj) {
        if (obj.hasOwnProperty(k))
            if (k === target)
                return path + "." + k;
            else if (typeof obj[k] === "object") {
                var result = search( obj[k], target, path + "." + k );
                if (result){
                     return result;
                }
            }
    }
    return false;
}

search(data,"js:format").slice(1); // returns: axis.y.tick.js:format
search(data,"js:bindto").slice(1); // returns: js:bindto

现在,我可以使用dottyobject-resolve-path或简单split('.')来解析对象的路径。

答案 2 :(得分:0)

对于object-scan,这应该是一个衬里。我们已经在数据处理中大量使用了它,一旦您将其放在头上,它就会很强大。这是您可以使用它的方式

const objectScan = require('object-scan');

const find = (data) => objectScan(['**.js:*'], { joined: true })(data);

const data = {"js:bindto":"#chart-1","point":{"r":5},"data":{"x":"x","xFormat":"%Y","columns":[],"colors":{"company":"#ed1b34","trendline":"#ffffff"}},"legend":{"show":false},"axis":{"x":{"padding":{"left":0},"type":"timeseries","tick":{"format":"%Y","outer":false}},"y":{"tick":{"outer":false,"js:format":"d3.format(\"$\")"}}},"grid":{"lines":{"front":false},"y":{"lines":[]}}};

console.log(find(data));
// => [ 'axis.y.tick.js:format', 'js:bindto' ]