2

示例:目前我们可以在地址名称属性中引用名称属性值,如下所示

{
        person: { 
            name: "a",
            address: {
                name: { "$ref":"#/person/name"},
                zip:"123"
            }
        }
  }

有什么方法可以参考下面的相对路径。

{
        person: { 
            name: "a",
            address: {
                name: { "$ref":"#/../name"},
                zip:"123"
            }
        }
  }

对于上面的问题,我正在查看的是一种简单的方法来引用当前 json 中的任何值,其中存在复杂和多个层次结构,如下面的第一个代码片段中给出的。为了从同级引用“名称”属性,我必须提到从根开始的完整路径,尽管可以维护。如果层次结构发生微小变化,则引用将不再有效。

{
  "one": {
    "two": {
      "three": {
        "four": {
          "five": {
            "fiveLevel1": {
              "name": "foo"
            },
            "fiveLevel2": {
              "name": {
                "$ref": "#/one/two/three/four/five/fiveLevel1/name"
              }
            }
          }
        }
      }
    }
  }
}

如果我们能够引用第二个片段中给出的相同属性,那么上层层次结构的变化不会对引用产生任何影响,只有当“FiveLevel1”和“FiveLevel2”的兄弟有直接变化时才会发生变化</ p>

{
  "one": {
    "two": {
      "three": {
        "four": {
          "five": {
            "fiveLevel1": {
              "name": "foo"
            },
            "fiveLevel2": {
              "name": {
                "$ref": "#../fiveLevel1/name"
              }
            }
          }
        }
      }
    }
  }
} 
4

2 回答 2

0

有一个相对 JSON 指针草案不幸于 2021 年 8 月到期,我不确定以后是否有任何扩展。

尽管如此,它应该是一个好的开始,因为它是已经提到的RFC6901 - JavaScript Object Notation (JSON) Pointer的扩展

于 2022-01-18T14:37:06.253 回答
0

这个功能在 vanilla JavaScript 中不存在,正如评论中所述。

但是,没有什么能阻止您向对象添加循环引用,这样您就可以实现与您正在寻找的东西相近的东西。您甚至可以将其封装在一个类中:

class RelPathObj {
  constructor(obj) {
    function build (parent, parentKey, obj) {
      if (typeof obj === "object") {
        for (let key in obj) {
          if (typeof obj[key] === "object") {
            parent[key] = { "..": parent, ...obj[key] };
            build(parent[key], key, obj[key]);
          } else {
            if (key === "$ref") {
              const path = obj[key].split("/");
              Object.defineProperty(parent[".."],
                                    parentKey,
                                    {
                                      get: function() {
                                        let value = parent[".."];
                                        path.forEach(p => { value = value[p] });
                                        return value;
                                      },
                                      set: function(value) {
                                        let ref = parent[".."];
                                        path.forEach(p => { 
                                          if (typeof ref[p] === "object")
                                            ref = ref[p] 
                                          else
                                            ref[p] = value
                                        });
                                      }
                                    });
            } else {
              parent[key] = obj[key];
            }
          }
        }
      } else {
        parent = obj;
      }
    }
    this.root = {};
    build(this.root, "root", obj);
  } 
}

const relativePathObject = new RelPathObj({
  "one": {
    "two": {
      "three": {
        "four": {
          "five": {
            "fiveLevel1": {
              "name": "foo"
            },
            "fiveLevel2": {
              "name": {
                "$ref": "../fiveLevel1/name"
              }
            }
          }
        }
      }
    }
  }
});

let fiveLevel1 = relativePathObject["root"]["one"]["two"]["three"]["four"]["five"]["fiveLevel1"];
console.log(fiveLevel1.name);
  
let fiveLevel2 = fiveLevel1[".."]["fiveLevel2"];
console.log(fiveLevel2.name);
  
fiveLevel1.name = "bar";
console.log(fiveLevel2.name);
  
fiveLevel2.name = "baz"
console.log(fiveLevel1.name);

它远非完美,但这里的主要思想是循环遍历对象的属性,在每个子对象中添加对父对象的引用,然后递归地重复此操作。当它找到 时$ref,它会解析路径并将其转换为它的值。

当然,如果对象层次结构发生变化,您就必须修复父引用(这是您可以在自定义类中实现的东西)。

请记住:这只是一个简单的代码片段,向您展示您可以做什么,我并没有花太多心思。不要在生产中使用它

于 2019-04-15T15:13:44.000 回答