您的代码存在问题
您现有的代码失败是因为递归检查的顺序错误。如果长度 不为零,则需要递归。所以应该是:
if (array[count].length) getMultiLength(array[count]);
else sum++;
您的代码中,即使
array[count]
不是数组(因为如果
array[count]
不是数组,则
length
将未定义),
getMultiLength
也会被调用。因此,它将一直递归下去。通过在调试器中逐步执行代码,这将很容易发现。
顺便说一下,在这种情况下,您不需要
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);
};
使用扁平化的另一种解决方案
另一种解决方案是将数组扁平化,然后找到扁平化数组的长度。这里我们使用一个生成器来创建一个扁平化器,它非常容易阅读和理解(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
使该属性不可枚举,不可配置等。
each
引入 jQuery - 使用 ES6 方法并指向一个 polyfill。 - Jeremy J Starcher