IOS12 Array reverse方法

html页面中输入如下内容:

Use iOS12 test. <br/>
<button onclick="test()" style="border: 1px solid #ccc;">Click Refresh</button>
<script>
    function test() {
        var arr = [1, 2, 3, 4]
        document.body.innerHTML += '<br/>'+arr.join(',')
        arr.reverse()
    }
</script>

测试地址如下:

For Not fixed: https://fanmingfei.github.io/array-reverse-ios12/origin.html
For Fixed: https://fanmingfei.github.io/array-reverse-ios12/fixed.html

正常预期为

在这里插入图片描述

在IOS12 Safari下显示为:

在这里插入图片描述

随后前端元老贺师俊(@johnhax)给出了一个可能的原因:

iOS 12 safari 的 JS 引擎 reverse()惊天大 bug 之原因分析:Safari 对所有值是 primitive
literal 的 array initializer 做了优化,同一个 initializer 产生的数组在内存里永远指向一份,
reverse()之后,所有从这个 initializer 得到的数组也都倒序了。

另一方面,其 toString()的结果是预先计算缓存的,所以 toString()结果并不会修改。按正常优化来说,如果某个这样的
array 执行了任何修改操作,应该复制到一份独立内存去。这是所谓 copy-on-write 的策略。但不幸的,
reverse()方法没有触发 CoW。

另一方面,所有不修改 array 的方法应该不触发 CoW。我实测下来,甚至 copyWithin和 fill这样的方法,如果
start/end 相同使得实际上并没有修改效果,也不会触发 CoW。

但是神奇的是 slice()会触发 CoW。所以我猜有可能某个苹果的临时工把 reverse/ slice的方法索引搞颠倒了。

进行reverse polyfill:
先根据ua判断是否为IOS12:

/Version\/12\.0.*Safari\//.test(navigator.userAgent)

然后进行reverse方法重写:

(function() {
  function buggy() {
    var a = [1, 2];
    return String(a) === String(a.reverse());
  }
  if(!buggy()) return;
  var r = Array.prototype.reverse;
  Array.prototype.reverse = function reverse() {
    if (Array.isArray(this)) this.length = this.length;
    return r.call(this);
  }
})();

参考资料:
https://stackoverflow.com/questions/52390368/array-state-will-be-cached-in-ios-12-safari-is-it-a-bug-or-feature
https://github.com/fanmingfei/array-reverse-ios12/
https://www.npmjs.com/package/array-reverse-polyfill

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值