Actualización en 2018.10.31
Este error ha sido corregido en iOS 12.1, que tengas un buen día~
Encontré un problema con el estado del valor de Array's en el recién lanzado iOS 12 Safari, por ejemplo, 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>
Después de actualizar la página, el valor del array's sigue siendo invertido. ¿Es esto un error o una característica del nuevo Safari?
Aquí hay una página de demostración. Intenta usarla con Safari de iOS 12: https://abelyao.github.io/others/ios12-safari-bug.html
¡Definitivamente es un BUG! Y es un error muy grave.
El fallo se debe a la optimización de los inicializadores de arrays en los que todos los valores son literales primitivos. Por ejemplo, dada la función
function buildArray() {
return [1, null, 'x'];
}
Todas las referencias a arrays devueltas por las llamadas a buildArray()
se enlazarán a la misma memoria, y algunos métodos como toString()
tendrán sus resultados en caché. Normalmente, para preservar la consistencia, cualquier operación mutable en tales matrices optimizadas copiará los datos a un espacio de memoria separado y se vinculará a él; este patrón se llama copy-on-write, o CoW para abreviar.
El método reverse()
muta el array, por lo que debería provocar un copy-on-write. Pero no lo hace, porque el implementador original (Keith Miller de Apple) pasó por alto el caso de reverse()
, aunque había escrito muchos casos de prueba.
Este error fue reportado a Apple el 21 de agosto. La corrección aterrizó en el repositorio de WebKit el 27 de agosto y se envió a Safari 12.0.1 y a iOS 12.1 el 30 de octubre de 2018.
Escribí una librería para arreglar el error. https://www.npmjs.com/package/array-reverse-polyfill
-- begin snippet: js hide: false console: true babel: false -->
(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 que no se almacena en caché si el número de elementos cambia; He podido evitar esto de la siguiente manera
<!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>