*Atualização em 2018.10.31**
Este erro foi corrigido no iOS 12.1, tenha um bom dia~
Encontrei um problema com Array's value state no recém lançado iOS 12 Safari, por exemplo, um código como este:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>iOS 12 Safari bugs</title>
<script type="text/javascript">
window.addEventListener("load", function ()
{
let arr = [1, 2, 3, 4, 5];
alert(arr.join());
document.querySelector("button").addEventListener("click", function ()
{
arr.reverse();
});
});
</script>
</head>
<body>
<button>Array.reverse()</button>
<p style="color:red;">test: click button and refresh page, code:</p>
</body>
</html>
Depois de actualizar a página, o valor da matriz's ainda é invertido. Isto é um bug ou uma característica do novo Safari?
Aqui está uma página de demonstração. Tente utilizá-la com o iOS 12 Safari: https://abelyao.github.io/others/ios12-safari-bug.html[2]
It's definitivamente um BUG! E it's é um bug muito sério.
O bug deve-se à optimização dos inicializadores de array em que todos os valores são literais primitivos. Por exemplo, dada a função:
function buildArray() {
return [1, null, 'x'];
}
Todas as referências de matriz retornadas das chamadas para 'buildArray()ligar-se-ão à mesma memória, e alguns métodos como 'toString()
terão os seus resultados armazenados em cache. Normalmente, para preservar a consistência, qualquer operação mutável em tais matrizes optimizadas copiará os dados para um espaço de memória separado e ligar-se-á a ele; este padrão é chamado copy-on-write, ou CoW para abreviar.
O método reverse()
muda a matriz, pelo que deve desencadear uma cópia-em-escrita. Mas não o faz't, porque o implementador original (Keith Miller da Apple) falhou o caso reverse()
, apesar de ter escrito muitos casos de teste.
Este erro foi reportado à Apple em 21 de Agosto. A correcção aterrou no repositório WebKit a 27 de Agosto e foi enviada no Safari 12.0.1 e iOS 12.1 a 30 de Outubro de 2018.
Escrevi uma libra para corrigir o bug. https://www.npmjs.com/package/array-reverse-polyfill
(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);
}
})();
Parece não estar em cache se o número de elementos mudar.
Consegui evitar isto desta forma.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>iOS 12 Safari bugs</title>
<script type="text/javascript">
window.addEventListener("load", function ()
{
let arr = [1, 2, 3, 4, 5];
arr.push('');
arr.pop();
alert(arr.join());
document.querySelector("button").addEventListener("click", function ()
{
arr.reverse();
});
});
</script>
</head>
<body>
<button>Array.reverse()</button>
<p style="color:red;">test: click button and refresh page, code:</p>
</body>
</html>