【问题标题】:Traverse a javascript object recursively and replace a value by key递归遍历一个javascript对象并按键替换一个值
【发布时间】:2017-02-18 17:20:27
【问题描述】:

由于 JSON 无法执行功能,我需要通过 JSON 对象中的键标志来评估 JSON 字符串。我想在 JSON 数据为 Object 形式时对其进行变异。

我在网上找不到可以根据已知键模式为我提供键的完整路径的函数/方法。

鉴于此数据:

  {
    "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 包:

看过

我没有看到任何东西可以返回相关键的完整路径以便我可以修改它,也不能直接处理对象本身以便我可以更改它的属性。

【问题讨论】:

  • mutateGraphData&lt;T&gt;(data:T):T 是什么语言?
  • @NinaScholz:打字稿。

标签: javascript json node.js recursion


【解决方案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))
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"&gt;&lt;/script&gt;

【讨论】:

【解决方案2】:

环顾四周后,我修改了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 或plain ole split('.') 来解析对象的路径。

【讨论】:

    【解决方案3】:

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

    免责声明:我是object-scan的作者

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 2013-03-02
      • 1970-01-01
      相关资源
      最近更新 更多