遍历所有节点并生成 Javascript 中的键和值

Traverse all nodes and yield keys and value in Javascript

给定一个 JSON 结构

var json = {
  'a': {
    'a1': ['a1a', 'a1b', 'a1c'],
    'a2': ['a2a', 'a2b'],
    'a3': []
  },
  'b': {
    'b1': ['b1a', 'b1b', 'b1c', 'b1d'],
    'b2': ['b2a', 'b2b'],
  },
  'c': ['c1', 'c2'],
  'd': {
    'd1': ['d1a', 'd1b', 'd1c'],
    'd2': []
  },
  'e': ['e1', 'e2'],
  'f': [
    'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10'
  ]
};

使用 Javascript 我如何遍历它以 产生 所有键和值的数组?换句话说,如果不简单地保留一个外部存储并在我遍历时附加到它,我怎么能 return 整个节点键和值集的数组?

例如,在 Python 中,我可能会使用生成器。所以也许我应该问,如何在 Javascript 中使用生成器?

Javascript 示例 jQuery:

function traverse(jsonObj) {
  if( typeof jsonObj == "object" ) {
    $.each(jsonObj, function(k,v) {
      traverse(v);
    });
  }
  else {
    // how can I yield this value instead?
    console.log(jsonObj)
  }
}

我的预期输出是所有键和值的数组:

['a', 'a1', 'a1a', 'a1b', 'a1c', 'a2', 'a2a', 'a2b'] // ... and so on

标准的javascript模式是传入一个处理函数:

function traverse(jsonObj, receive) {
    if (typeof jsonObj == "object") {
        if (Array.isArray(jsonObj)) {
            // Don't want to output the keys for arrays
            $.each(jsonObj, function (k, v) {
                traverse(v, receive);
            });

        } else {
            $.each(jsonObj, function (k, v) {
                traverse(k, receive);
                traverse(v, receive);
            });
        }
    } else {
        receive(jsonObj);
    }
}

然后是一些示例代码,它选择将每个生成的对象添加到数组中。

var myArray = [];
traverse(myObject, function(jsonObj) { 
                      myArray.push(jsonObj); 
                });

这是一个工作示例,它不推送到数组,而是显示 HTML 中的每个项目:http://jsfiddle.net/9u3zrjes/1/

ECMAScript 6 有 generators。所以你可以把函数写成

function *traverse(value) {
  if (typeof value === "object") {
    var isArray = Array.isArray(value);
    for (var prop in value) {
        if (!isArray) yield prop;
        yield* traverse(value[prop]);
    }
  }
  else {
    yield value;
  }
}

并将其用作:

var obj = {
  'a': {
    'a1': ['a1a', 'a1b', 'a1c'],
    'a2': ['a2a', 'a2b'],
    'a3': []
  }
};

console.log(Array.from(traverse(obj)));

DEMO via 6to5


但是没有原生生成器也没什么不同:

function traverse(value, result) {
  result = result || [];
  if (typeof value === "object") {
    var isArray = Array.isArray(value);
    for (var prop in value) {
      if (!isArray) result.push(prop);
      traverse(value[prop], result);
    }
  }
  else {
    result.push(value);
  }
  return result;
}

console.log(traverse(obj));