此代码将显示错误:
function causeBug(d) { var k; var n = parseFloat(1); var c = Math.abs(d); if (n < 0) { k = '-'; } else { k = '+'; } return k + n; } $(function() { for (var i = 0; i <= 2000; ++i) { $('body').append(i + ': ' + causeBug(2) + '<br>'); } });
它在这个小提琴中可见:http://jsfiddle.net/H2SEN/16/(在Mobile Safari中查看,向下滚动,在某些时候你会看到parseFloat(1)< 0).从第73次迭代到超过1500次,任何地方都发现了负面消息. 注意一些看似不必要的代码,例如未使用的参数d和未使用的变量var c = Math.abs(d);实际上是发生错误所必需的.对于在return语句中使用n和parseFloat调用(尽管parseInt也会导致它)也是如此. Bug仅在真正的iPhone 4s(7.0.6)和两个iPod Touch(7.1 beta)上再现.不在iPad或iOS模拟器或任何桌面浏览器中.如果启用了远程调试并在计算机上打开了Safari控制台,则不会出现此错误. 我相信这是这个悬而未决的问题的确切原因:Strange JavaScript behaviour on mobile Safari iOS 6
任何洞察这个错误的潜在原因将不胜感激.
解决方法
也许是JIT问题?我在JavascriptCore源代码中发现了Math.abs的实现,我猜测它与Nitro(ios js引擎)不同,或者可能标记为JIT可执行文件.
Value MathFuncImp::call(ExecState *exec,Object &/*thisObj*/,const List &args) { double arg = args[0].toNumber(exec); double arg2 = args[1].toNumber(exec); double result; switch (id) { case MathObjectImp::Abs: result = ( arg < 0 || arg == -0) ? (-arg) : arg; break;
这可以直接在javascript中实现.所以你可以用你的Math.abs调用替换
result = ( arg < 0 || arg == -0) ? (-arg) : arg;
这将解决问题并与浏览器兼容.
已提交Apple Bug:16209709
有谁知道这种错误是如何发生的或更好的描述方式?
比特翻转?记忆碰撞?某种溢出?