JSON.stringify replacer - how to get full path

后端 未结 5 2071
太阳男子
太阳男子 2021-01-07 07:35

Replacer in below code write on console current processed field name

5条回答
  •  盖世英雄少女心
    2021-01-07 08:14

    Decorator

    replacerWithPath in snippet determine path using this (thanks @Andreas for this tip ), field and value and some historical data stored during execution (and this solution support arrays)

    JSON.stringify(c, replacerWithPath(function(field,value,path) {
      console.log(path,'=',value); 
      return value;
    }));
    

    function replacerWithPath(replacer) {
      let m = new Map();
    
      return function(field, value) {
        let path= m.get(this) + (Array.isArray(this) ? `[${field}]` : '.' + field); 
        if (value===Object(value)) m.set(value, path);  
        return replacer.call(this, field, value, path.replace(/undefined\.\.?/,''))
      }
    }
    
    
    // Explanation fo replacerWithPath decorator:
    // > 'this' inside 'return function' point to field parent object
    //   (JSON.stringify execute replacer like that)
    // > 'path' contains path to current field based on parent ('this') path
    //   previously saved in Map
    // > during path generation we check is parent ('this') array or object
    //   and chose: "[field]" or ".field"
    // > in Map we store current 'path' for given 'field' only if it 
    //   is obj or arr in this way path to each parent is stored in Map. 
    //   We don't need to store path to simple types (number, bool, str,...)
    //   because they never will have children
    // > value===Object(value) -> is true if value is object or array
    //   (more: https://stackoverflow.com/a/22482737/860099)
    // > path for main object parent is set as 'undefined.' so we cut out that
    //   prefix at the end ad call replacer with that path
    
    
    // ----------------
    // TEST
    // ----------------
    
    let a = { a1: 1, a2: 1 };
    let b = { b1: 2, b2: [1, a] };
    let c = { c1: 3, c2: b };
    
    let s = JSON.stringify(c, replacerWithPath(function(field, value, path) {
      // "this" has same value as in replacer without decoration
      console.log(path);
      return value;
    }));

    BONUS: I use this approach to stringify objects with circular references here

提交回复
热议问题