您的代码有问题
您现有的代码失败,因为递归检查是向后的。如果长度为非零,您希望递归。所以应该是
if (array[count].length) getMultiLength(array[count]);
else sum++;
就您的代码而言,即使array[count] 不是 数组,getMultiLength 也会被调用(因为如果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;
};
有些人可能更喜欢使用reduce:
Array.prototype.getLength = function() {
return this.reduce((sum, elt) =>
sum + (elt.length ? elt.getLength() : 1), 0);
};
另一种使用扁平化的解决方案
另一种解决方案是展平数组,然后找到展平数组的长度。这里我们使用generator 来创建一个真正易于阅读和理解的扁平化器(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);
flatten 的替代实现
或者,使用您自己喜欢的flatten 实现,例如这个递归版本:
function flatten(value) {
return Array.isArray(value) ? [].concat(...value.map(flatten)) ? value;
}
或在 ES5 中
function flatten(value) {
return Object.prototype.toString.call(value) === '[object Array]' ?
[].concat.apply([], value.map(flatten)) :
value;
}
把它放在Array原型上
如果你坚持把这个放在原型上,那么
Object.defineProperty(Array.prototype, 'getLength', {
value() { return flatten(this).length; }
});
使用defineProperty 使该属性不可枚举、不可配置等。