如何在Javascript中获取嵌套数组长度?

Tru*_*246 1 javascript arrays function infinite-loop multidimensional-array

我有一个嵌套数组的例子:

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];
Run Code Online (Sandbox Code Playgroud)

这是我获取嵌套数组长度的函数:

Array.prototype.getLength = function() {
  var sum = 0;
  function getMultiLength(array) {
    for (count = 0; count < array.length; count ++) {
      sum ++;
      if (!array[count].length) {
        getMultiLength(array[count]);
      }
    }
  }
  getMultiLength(this.valueOf());
  return sum;
};
Run Code Online (Sandbox Code Playgroud)

我对结果的期望是12,但我得到的是无限循环:

testArray.getLength(); //infinite loop
Run Code Online (Sandbox Code Playgroud)

任何人都知道为什么以及如何获得嵌套数组长度?

小智 8

你的代码有问题

您的现有代码失败,因为检查重复是向后的.如果长度不为零,您想要递归.所以它应该是

  if (array[count].length) getMultiLength(array[count]);
  else sum++;
Run Code Online (Sandbox Code Playgroud)

当你的代码表示,getMultiLength将即使被称为array[count]不是一个数组(因为如果array[count]不是数组,length将不确定).所以它会永远地继续递归.只需在调试器中单步执行代码,就可以轻松搞清楚.

顺便说一句,你不需要this.valueOf().这与this这种情况相同.

调整你的代码

但实际上,您可以通过消除不必要的内部函数并使用递归调用的返回值来简化代码:

Array.prototype.getLength = function() {
  let sum = 0;
  for (let count = 0; count < this.length; count ++) {
    sum += this[count].length ? this[count].getLength() : 1;
  }
  return sum;
};
Run Code Online (Sandbox Code Playgroud)

有些人可能更愿意使用reduce以下方法编写:

Array.prototype.getLength = function() {
  return this.reduce((sum, elt) => 
    sum + (elt.length ? elt.getLength() : 1), 0);
};
Run Code Online (Sandbox Code Playgroud)

使用展平的另一种解决方案

另一种解决方案是展平阵列,然后找到展平阵列的长度.在这里,我们使用生成器创建一个易于阅读和理解的平整(ES6功能):

function *flatten(array) {
  for (elt of array) 
    if (Array.isArray(elt)) yield *flatten(elt);
    else yield elt;
}

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];

console.log(Array.from(flatten(testArray)).length);
Run Code Online (Sandbox Code Playgroud)

替代实施 flatten

或者,使用您自己喜欢的实现flatten,例如这个递归版本:

function flatten(value) {
  return Array.isArray(value) ? [].concat(...value.map(flatten)) ? value;
}
Run Code Online (Sandbox Code Playgroud)

或者在ES5中

function flatten(value) {
  return Object.prototype.toString.call(value) === '[object Array]' ?
    [].concat.apply([], value.map(flatten)) :
    value;
}
Run Code Online (Sandbox Code Playgroud)

把它放在Array原型上

如果你坚持把它放在原型上,那么

Object.defineProperty(Array.prototype, 'getLength', {
  value() { return flatten(this).length; }
});
Run Code Online (Sandbox Code Playgroud)

使用defineProperty使该属性不可枚举,不可配置等.