为什么Safari会递归调用function.apply?

时间:2013-01-14 22:20:15

标签: javascript safari

请考虑以下事项:

var foo = []
for (var i=0; i<100000; i++) { foo.push(97); }
var bar = String.fromCharCode.apply(String,foo)

大多数浏览器运行良好,但Safari抛出:RangeError: Maximum call stack size exceeded.

基于此,似乎Safari的Function.prototype.apply实现是递归的。这是真的吗?

上面链接的MDN页面提到了JS引擎的参数长度限制的潜在问题,但这显然不是这里的情况。

编辑:我仍然认为这不是一个争论长度问题。通过this page和我自己的测试,看起来Safari可以处理多达524197个参数,上面的代码不会超过。

加分问题:我们可以重写上面的代码,以避免在数组的每个元素上显式调用String.fromCharCodejoin将结果放在一起时使用apply,但是我怀疑会更慢(对于支持大输入apply的浏览器)。从整数字符代码数组中组装大字符串的最佳方法是什么?

1 个答案:

答案 0 :(得分:5)

Apply在某些浏览器中对它们接受的参数长度有限制。 Webkit has an observed limit of 2^16,所以如果你有任何需要,你可能想要遵循一个策略来打破争论。如果您阅读了该错误的详细信息,那么这是一个强制性的限制,而不是它是由递归引起的问题(该错误也引发了类似的RangeError)。

无论如何,我相信你对字符串连接的预感是正确的 - 连接不一定和其他方法一样好。 Here's a test反对字符串连接,我首先分解参数(类似于MDN讨论中的策略),并且它会使连接边缘化。直接将字符串添加到一起甚至逐渐加入连接,我有点惊讶(至少在Chrome中,我想他们必须只有一些可以重用现有字符串才能产生效果的智能gc,但可以肯定地说)。

编辑 - 有趣的是,就加入速度慢而言,Chrome看起来很奇怪 - 对于其他所有浏览器而言,它在性能方面更接近concat甚至更好。