2018.10.31에 업데이트
이 버그는 iOS 12.1에서 수정되었습니다. 좋은 하루 되세요 ~
새로 출시 된 iOS 12 Safari에서 Array의 값 상태에 문제가 있음을 발견했습니다 (예 : 다음과 같은 코드).
<!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>
페이지를 새로 고친 후에도 여전히 배열 값이 반대로 바뀝니다. 이것은 새로운 Safari의 버그입니까?
여기 데모 페이지가 있습니다. iOS 12 Safari에서 사용하십시오 :
https://abelyao.github.io/others/ios12-safari-bug.html
답변
확실히 버그입니다! 그리고 그것은 매우 심각한 버그입니다.
버그는 모든 값이 기본 리터럴 인 배열 이니셜 라이저의 최적화 때문입니다. 예를 들어 다음과 같은 기능이 주어집니다.
function buildArray() {
return [1, null, 'x'];
}
호출에서 반환 된 모든 배열 참조 buildArray()
는 동일한 메모리에 연결되며 toString()
결과 와 같은 일부 메서드 는 캐시됩니다. 일반적으로 일관성을 유지하기 위해 최적화 된 어레이에서 변경 가능한 조작은 데이터를 별도의 메모리 공간에 복사하여 링크합니다. 이 패턴이라고 기록 중 복사 짧게, 또는 소.
이 reverse()
메소드는 배열을 변경하므로 기록 중 복사를 트리거해야합니다. 그러나 원래의 구현 자 (Apple의 Keith Miller)는 reverse()
많은 테스트 사례를 작성했지만 사례를 놓 쳤기 때문에 그렇지 않습니다 .
이 버그는 8 월 21 일 Apple에보고되었습니다 .이 수정 프로그램 은 8 월 27 일 WebKit 저장소 에 제공되어 2018 년 10 월 30 일 Safari 12.0.1 및 iOS 12.1에 제공되었습니다.
답변
버그를 해결하기 위해 lib를 작성했습니다.
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);
}
})();
답변
이것은 웹킷 의 버그입니다 . 이것은 최종적으로 해결되었지만 아직 iOS GM 릴리스와 함께 제공되지는 않았습니다. 이 문제에 대한 해결책 중 하나 :
(function() {
function getReverseStr() {
return [1, 2].reverse();
}
var n1 = getReverseStr()[0];
var n2 = getReverseStr()[0];
// check if there is an issue
if(n1 != n2) {
var origReverseFunction = Array.prototype.reverse;
Array.prototype.reverse = function() {
var newArr = this.slice();
// use original reverse function so that edge cases are taken care of
origReverseFunction.apply(newArr, arguments);
var that = this;
// copy reversed array
newArr.forEach(function(value, index) {
that[index] = value;
});
return this;
}
}
})();
답변
요소 수가 변경되면 캐시되지 않는 것 같습니다.
나는 이것을 이렇게 피할 수 있었다.
<!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>