简体   繁体   English

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

[英]Traverse a javascript object recursively and replace a value by key

Since JSON can not perfom functions i need to eval a JSON string by a key flag in the JSON object.由于 JSON 不能执行函数,我需要通过 JSON 对象中的键标志来评估 JSON 字符串。 I want to mutate the JSON data when it's in Object form.我想在对象形式时改变 JSON 数据。

I can't find a function/method online that can give me the full path to key based on a known key pattern.我在网上找不到可以根据已知密钥模式为我提供完整密钥路径的函数/方法。

Given this data:鉴于此数据:

  {
    "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": [...]
        }
    }
}

The flags are keys beginning with js: .标志是以js:开头的键。

If I look up js:format , I'd expect it's path to be something like: /js:bindto and /axis/y/tick/js:format .如果我查找js:format ,我希望它的路径类似于: /js:bindto/axis/y/tick/js:format Open to suggestions.对建议持开放态度。

In context:在上下文中:

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

I have been around a few npm packages:我接触过几个 npm 包:

I have looked at我看过

Nothing have I seen can return the full path to the key in question so I can modify it, nor work directly on the object itself so I can change its properties.我没有看到任何东西可以返回有问题的键的完整路径,以便我可以修改它,也没有直接在对象本身上工作,以便我可以更改其属性。

You could go with Ramda .你可以和Ramda一起去。 It has built in functions that will allow you to map over an object and modify parts of the object in a completely immutable way.它具有内置函数,允许您映射对象并以完全不可变的方式修改对象的某些部分。

Ramda offers R.lensPath that will allow you to dig into the object, and modify it as needed. R.lensPath提供了R.lensPath允许你深入研究对象,并根据需要修改它。 It doesn't follow the pattern you want, but we can quickly patch it with the lensify function.它不遵循您想要的模式,但我们可以使用lensify功能快速修补它。

It is using the R.set function to set the node to the passed in value, and creating a pipeline that will run all the operations on the passed in object.它使用R.set函数将节点设置为传入的值,并创建一个管道,将对传入的对象运行所有操作。

You can do some really cool stuff with ramda and lenses.你可以用 ramda 和镜头做一些非常酷的事情。 Checkout evilsoft on livecoding.tv for a really good overview.在 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>

After doing a look around I modified the answer from Javascript/JSON get path to given subnode?环顾四周后,我修改了从Javascript/JSON get path 到给定子节点的答案 @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

Now I can use dotty or object-resolve-path or plain ole split('.') to resolve the path to the object.现在我可以使用dottyobject-resolve-path或普通的 ole split('.')来解析对象的路径。

With object-scan this should be a one liner.使用对象扫描,这应该是单衬。 We've been using it a lot for data processing and it's powerful once you wrap your head around it.我们一直在大量使用它进行数据处理,一旦您了解它,它就会变得非常强大。 Here is how you could use it这是你可以如何使用它

 // 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' ]
 .as-console-wrapper {max-height: 100% !important; top: 0}
 <script src="https://bundle.run/object-scan@13.8.0"></script>

Disclaimer : I'm the author of object-scan免责声明:我是对象扫描的作者

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM