Javascript 返回对象中每个深度属性的字符串路径数组

Javascript 返回对象中每个深度属性的字符串路径数组,javascript,node.js,javascript-objects,Javascript,Node.js,Javascript Objects,我有一个丑陋的1MB+JSON对象,它有许多深层属性,包括包含嵌套对象的嵌套数组等 我正在寻找一个函数,它可以为给定对象中的每个属性返回字符串“路径”数组 ['obj.propA.first', 'obj.propA.second', 'obj.propB'] 到目前为止,我所有的搜索都找到了相反方向的解决方案。例如:获取路径字符串并获取属性值 我的直觉告诉我必须有一个比重新发明轮子更好的方法 提前谢谢 示例行为: var ugly = { a: 'a', b: ['b1', 'b2'

我有一个丑陋的1MB+JSON对象,它有许多深层属性,包括包含嵌套对象的嵌套数组等

我正在寻找一个函数,它可以为给定对象中的每个属性返回字符串“路径”数组

['obj.propA.first', 'obj.propA.second', 'obj.propB']
到目前为止,我所有的搜索都找到了相反方向的解决方案。例如:获取路径字符串并获取属性值

我的直觉告诉我必须有一个比重新发明轮子更好的方法

提前谢谢

示例行为:

var ugly = {
  a: 'a',
  b: ['b1', 'b2'],
  c: {
    c1: 'c1',
    c2: ['c2a', 'c2b'],
    c3: {
      c3a: 'c3a',
      c3b: [['c3b']],
    },
    c4: [{c4a: 'c4a'}],
  }
};

getPaths = function(obj) {
      ???
};    

getPaths(ugly) = [
      'a',
      'b[0]',
      'b[1]',
      'c.c1',
      'c.c2[0]',
      'c.c2[1]',
      'c.c3.c3a',
      'c.c3.c3b[0][0]',
      'c.c4[0].c4a',
    ];

这种情况有点奇怪,可能暗示在体系结构级别存在问题,但要理解这些问题有时是继承的和/或不可避免的

node 4.2版本es2015中的一个非常糟糕的可变递归实现:

function isPlainishObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

function propinator (obj, _paths, _currentPath) {
  _paths = _paths || [];

  if (typeof obj !== 'object') {
    _paths.push(_currentPath);
  } else {
    for (let prop in obj) {
      let path;
      if (isPlainishObject(obj)) {
        path = _currentPath && `${_currentPath}.${prop}` || prop;
      } else {
        path = _currentPath && `${_currentPath}[${prop}]` || prop;
      }

      propinator(
        obj[prop],
        _paths,
        path
      );
    }
  }

  return _paths;
}
测试:

let assert = require('assert');
assert.deepEqual(propinator(ugly), [
  'a',
  'b[0]',
  'b[1]',
  'c.c1',
  'c.c2[0]',
  'c.c2[1]',
  'c.c3.c3a',
  'c.c3.c3b[0][0]',
  'c.c4[0].c4a',
]);    


这只是简单的测试(虽然可能很差),所以意见/改进是非常受欢迎的。

这种情况有点奇怪,可能暗示在体系结构级别上存在问题,但请理解这些东西有时是继承的和/或不可避免的

node 4.2版本es2015中的一个非常糟糕的可变递归实现:

function isPlainishObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

function propinator (obj, _paths, _currentPath) {
  _paths = _paths || [];

  if (typeof obj !== 'object') {
    _paths.push(_currentPath);
  } else {
    for (let prop in obj) {
      let path;
      if (isPlainishObject(obj)) {
        path = _currentPath && `${_currentPath}.${prop}` || prop;
      } else {
        path = _currentPath && `${_currentPath}[${prop}]` || prop;
      }

      propinator(
        obj[prop],
        _paths,
        path
      );
    }
  }

  return _paths;
}
测试:

let assert = require('assert');
assert.deepEqual(propinator(ugly), [
  'a',
  'b[0]',
  'b[1]',
  'c.c1',
  'c.c2[0]',
  'c.c2[1]',
  'c.c3.c3a',
  'c.c3.c3b[0][0]',
  'c.c4[0].c4a',
]);    


这只是简单的测试(虽然可能很差),所以意见/改进是非常受欢迎的。

这种情况有点奇怪,可能暗示在体系结构级别上存在问题,但请理解这些东西有时是继承的和/或不可避免的

node 4.2版本es2015中的一个非常糟糕的可变递归实现:

function isPlainishObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

function propinator (obj, _paths, _currentPath) {
  _paths = _paths || [];

  if (typeof obj !== 'object') {
    _paths.push(_currentPath);
  } else {
    for (let prop in obj) {
      let path;
      if (isPlainishObject(obj)) {
        path = _currentPath && `${_currentPath}.${prop}` || prop;
      } else {
        path = _currentPath && `${_currentPath}[${prop}]` || prop;
      }

      propinator(
        obj[prop],
        _paths,
        path
      );
    }
  }

  return _paths;
}
测试:

let assert = require('assert');
assert.deepEqual(propinator(ugly), [
  'a',
  'b[0]',
  'b[1]',
  'c.c1',
  'c.c2[0]',
  'c.c2[1]',
  'c.c3.c3a',
  'c.c3.c3b[0][0]',
  'c.c4[0].c4a',
]);    


这只是简单的测试(虽然可能很差),所以意见/改进是非常受欢迎的。

这种情况有点奇怪,可能暗示在体系结构级别上存在问题,但请理解这些东西有时是继承的和/或不可避免的

node 4.2版本es2015中的一个非常糟糕的可变递归实现:

function isPlainishObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

function propinator (obj, _paths, _currentPath) {
  _paths = _paths || [];

  if (typeof obj !== 'object') {
    _paths.push(_currentPath);
  } else {
    for (let prop in obj) {
      let path;
      if (isPlainishObject(obj)) {
        path = _currentPath && `${_currentPath}.${prop}` || prop;
      } else {
        path = _currentPath && `${_currentPath}[${prop}]` || prop;
      }

      propinator(
        obj[prop],
        _paths,
        path
      );
    }
  }

  return _paths;
}
测试:

let assert = require('assert');
assert.deepEqual(propinator(ugly), [
  'a',
  'b[0]',
  'b[1]',
  'c.c1',
  'c.c2[0]',
  'c.c2[1]',
  'c.c3.c3a',
  'c.c3.c3b[0][0]',
  'c.c4[0].c4a',
]);    



这只是一个简单的测试(虽然可能很差),所以非常欢迎意见/改进。

为什么需要这些路径?这似乎是一个奇怪的需要(不是说它一定是错的,只是需要一些上下文)
。在
中,在对象的实例上递归(或者对数组进行一些更具体的类型检查/etc)@NickTomlin-我有一个数据库,其中包含一些使用路径索引的属性的元数据。@PaulS.-我只是真的很惊讶,没有人为此制作lodash或下划线混音。@Peterhaneman不想打消您的用例,但我认为没有人这样做,因为这是一个非常罕见的场景。我在这个行业还相对年轻,但我从未遇到或听说过这样的存储/用例。如何解析重复路径?是否只需要每个对象的“terminal”属性?我认为提供一个示例源和结果会很有帮助。为什么需要这些路径?这似乎是一个奇怪的需要(不是说它一定是错的,只是需要一些上下文)
。在
中,在对象的实例上递归(或者对数组进行一些更具体的类型检查/etc)@NickTomlin-我有一个数据库,其中包含一些使用路径索引的属性的元数据。@PaulS.-我只是真的很惊讶,没有人为此制作lodash或下划线混音。@Peterhaneman不想打消您的用例,但我认为没有人这样做,因为这是一个非常罕见的场景。我在这个行业还相对年轻,但我从未遇到或听说过这样的存储/用例。如何解析重复路径?是否只需要每个对象的“terminal”属性?我认为提供一个示例源和结果会很有帮助。为什么需要这些路径?这似乎是一个奇怪的需要(不是说它一定是错的,只是需要一些上下文)
。在
中,在对象的实例上递归(或者对数组进行一些更具体的类型检查/etc)@NickTomlin-我有一个数据库,其中包含一些使用路径索引的属性的元数据。@PaulS.-我只是真的很惊讶,没有人为此制作lodash或下划线混音。@Peterhaneman不想打消您的用例,但我认为没有人这样做,因为这是一个非常罕见的场景。我在这个行业还相对年轻,但我从未遇到或听说过这样的存储/用例。如何解析重复路径?是否只需要每个对象的“terminal”属性?我认为提供一个示例源和结果会很有帮助。为什么需要这些路径?这似乎是一个奇怪的需要(不是说它一定是错的,只是需要一些上下文)
。在
中,在对象的实例上递归(或者对数组进行一些更具体的类型检查/etc)@NickTomlin-我有一个数据库,其中包含一些使用路径索引的属性的元数据。@PaulS.-我只是真的很惊讶,没有人为此制作lodash或下划线混音。@Peterhaneman不想打消您的用例,但我认为没有人这样做,因为这是一个非常罕见的场景。我在这个行业还相对年轻,但我从未遇到或听说过这样的存储/用例。如何解析重复路径?是否只需要每个对象的“terminal”属性?我认为提供一个示例源和一个结果会很有帮助。我的i7 Haswell 2.3Ghz上的Node v5能够在9.792ms内完成385KB和8704条路径。在一个有90756条路径的6.5MB文件上,平均耗时115.749ms。有点慢,但幸运的是我有机会进行预处理和缓存。再次感谢。这当然是一个奇怪的用例,但是生成json文件的数据源无法访问元数据。唉,我被困住了。@Peterhaneman抓住你了,我明白了。如果您有任何性能调整,请告诉我。很高兴它成功了;)供参考