递归迭代器上的最大调用堆栈大小错误

Maximum call stack size error on recursive iterator

本文关键字:调用 堆栈 错误 迭代器 递归      更新时间:2023-09-26

我正在用JavaScript做实验,只是为了学习目的,我正在编写一个forEach迭代器,它可以遍历嵌套数组或任何其他包含length property的可迭代对象。

这是我写的:

var forEach = function(obj, callback, options) {
  var options = options || {};
  var context = options.context || this;    
  if(!isEmpty(obj)) { // isEmpty function just evaluates `return !(!!obj.length);`
    for(var x = 0; x < obj.length; x++) {
      if(!isEmpty(obj[x]) && options.deep === true) {
        forEach.call(context, obj[x], callback, options);
        continue;
      }
      callback.call(context, obj[x]);
    }
  }
};

如果我传递一个嵌套数组,我得到RangeError: Maximum call stack size exceeded:

forEach(['a', 'b', ['c', 'd']], function(x) {
  console.log(x);
}, { deep: true });

但这似乎只发生如果我检查长度属性在obj[x]

如果我替换:

if(!isEmpty(obj[x]) && options.deep === true) {
为:

if((obj[x] instanceof Array) && options.deep === true) {

我将神奇地工作。然而,并非只有Arrays具有长度属性。String有它,所以这不是一个广泛的方法。

如何防止RangeError,但仍然检查length property ?

编辑:

我运行这个示例 NodeJS v0.8.12

考虑'a'[0][0][0][0][0][0][0]...是无限有效的,并且每个值都是string类型。如果类型是string,那么不应该递归地迭代它。还要注意,function对象有一个length属性,而function参数可以是对function本身的自引用。这将导致另一个无限递归。我认为用不同的方式处理不同的类型可能比试图开发一个包罗万象的函数更有意义。

您还可以使用maxLevel属性来限制递归的深度,默认值为10。这样,无限递归就不容易实现了。

forEach(['a', 'b', ['c', 'd']], function(x) {
  console.log(x);
}, { deep: true, maxLevel: 10 });
var forEach = function(obj, callback, options, level) {
    var options = options || {};
    var context = options.context || this;
    if (!level) level = 1;
    if (!options.maxLevel) options.maxLevel = 10;
    if (level > options.maxLevel) return;
    ...
        forEach.call(context, obj[x], callback, options, level + 1);
    ...
}

演示:http://jsfiddle.net/bjpx5/