如何再现这个bug?
============================================================
var getLength = function(array) {
return array.length;
};
// JIT getLength with only arrays
for (var i = 0; i < 1000; i++) getLength([]);
alert(getLength({5: 'test'})); // 应该返回 undefined
// 64位 ios8 会返回 6.
============================================================
jQuery 和 underscore 都受到这个 bug 的影响。
比如 $.each,看到 .length 后,会把一个 object 当作数组来遍历。
underscore 的 _.each 也是同样的原理。
这个 bug 会造成莫名其妙的结果。
jQuery 1.11.3 和 underscore 1.8.3 修正了这个问题。
我看了一下 underscore 的代码,修正的代码非常难看。
很多 obj.length 都改成了 getLength(obj),以确保它不会被 jit。
相关代码:
============================================================
var property = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};
var getLength = property('length');
============================================================
这样改了以后,一个简单的属性访问,变成了带分支的函数调用,对性能肯定是会有影响的。 .each 在两个库里都是至关重要的承重函数。至少在ios上,很多关键的循环就不能被jit了。
由于别的浏览器用的也是同一套代码,而且 jQuery 和 underscore 在很长时间内都不可能去放弃 ios 8 支持,所以其他浏览器也会因此被罚一点点性能损失。
[Edit]
刚才看了一下jQuery的改法,好像就是在 isArrayLike 函数里:
把 --> var length = obj.length;
改成了--> var length = "length" in obj && obj.length;
因为 jQuery 内部已经大量使用 isArrayLike 了,
而 underscore 本来不需要多这么一个 getLength 的,
所以这个 bug 对于 jQuery 的影响比 underscore 要小一点。
[相关链接(jQuery Issue)]
https://github.com/jquery/jquery/issues/2145
[苹果的bug修正]
http://trac.webkit.org/changeset/182058
(JIT相关代码里 ">>" 写成了 ">")
--
修改:javaboy FROM 111.214.10.*
FROM 111.214.10.*