“RangeError:超出最大调用堆栈大小”为什么?
如果我跑
Array.apply(null, new Array(1000000)).map(Math.random); 
在Chrome 33上,我明白了
RangeError: Maximum call stack size exceeded
为什么?
浏览器不能处理那么多的参数。 看这个例子,例如:
 alert.apply(window, new Array(1000000000)); 
 这将导致RangeError: Maximum call stack size exceeded ,与您的问题相同。 
要解决这个问题,请执行:
 var arr = []; for(var i = 0; i < 1000000; i++){ arr.push(Math.random()); } 
 这里在Array.apply(null, new Array(1000000))而不是.map调用失败。 
所有的函数参数都必须适用于callstack(至less是每个参数的指针),所以在这个参数中,callstack的参数太多了。
你需要了解什么是调用堆栈 。
Stack是一个LIFO数据结构,就像一个只支持push和pop方法的数组。
让我通过一个简单的例子来解释它是如何工作的:
 function a(var1, var2) { var3 = 3; b(5, 6); c(var1, var2); } function b(var5, var6) { c(7, 8); } function c(var7, var8) { } 
 当这里调用函数a ,它会调用b和c 。 当调用b和c ,由于Javascript的作用域angular色, a的局部variables不可访问,但是JavaScript引擎必须记住局部variables和参数,所以它会将它们推入调用堆栈。 假设您正在使用像Narcissus这样的Javascript语言来实现JavaScript引擎。 
我们实现callStack作为数组:
 var callStack = []; 
每次调用一个函数,我们将局部variables推入堆栈:
 callStack.push(currentLocalVaraibles); 
 一旦函数调用完成(如在a ,我们已经调用b , b完成执行,我们必须返回a ),我们通过popup堆栈来取回局部variables: 
 currentLocalVaraibles = callStack.pop(); 
 所以当我们想再次调用c时,推入堆栈中的局部variables。 如您所知,编译器要高效地定义一些限制。 这里当你在做Array.apply(null, new Array(1000000)) ,你的currentLocalVariables对象将是巨大的,因为它里面会有1000000variables。 由于.apply会将每个给定的数组元素作为parameter passing给函数。 一旦推入调用堆栈,将超出调用堆栈的内存限制,并会抛出该错误。 
 同样的错误发生在无限recursion( function a() { a() } )太多的时候,东西已经被推到调用堆栈。 
请注意,我不是编译器工程师,这只是对正在发生的事情的简化表示。 这确实比这更复杂。 一般来说,推送到调用堆栈的内容被称为堆栈框架 ,其中包含参数,局部variables和函数地址。
 用for的答案是正确的,但是如果你真的想使用函数式避免语句 – 你可以使用下面的代替expression式: 
Array.from(Array(1000000),()=> Math.random());
Array.from()方法从类似数组或类的对象中创build一个新的数组实例。 这个方法的第二个参数是一个map函数来调用数组的每个元素。
遵循相同的想法,您可以使用ES2015 Spread操作符重写它:
[… Array(1000000)]。map(()=> Math.random())
在这两个示例中,如果需要,您可以获得迭代的索引,例如:
[… Array(1000000)]。map((_,i)=> i + Math.random())