𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵 𝗔𝗻𝗱 𝗥𝗲𝘀𝘂𝗹𝘁𝘀
사실, jsperf 의 성능 테스트 와 콘솔의 일부 검사가 수행됩니다. 연구를 위해 irt.org 웹 사이트 가 사용됩니다. 아래는 이러한 모든 소스의 모음이며 하단에 예제 기능입니다.
╔ ================ ╦ ====== ╦ =========================== ======== ╦ ========== ╦ ============
║ 방법 ║Concat║slice & push.apply ║ push.apply x2 ║ ForLoop ║Spread ║
╠ ================ ╬ ====== ╬ =========================== ======== ╬ ========== ╬ ============
Op mOps / Sec 79179 ║104 ║ 76 ║ 81 ║28 ║
╠ ================ ╬ ====== ╬ =========================== ======== ╬ ========== ╬ ============
par 스파 스 배열 ║ 예! ║ 슬라이스 만 ║ 아니오 ║ 어쩌면 2 ║no ║
spa 스파 스 유지 ║ ║ 배열 (첫 번째 인수) ║ ║ ║ ║
╠ ================ ╬ ====== ╬ =========================== ======== ╬ ========== ╬ ============
║ 지원 ║MSIE 4║MSIE 5.5║ MSIE 5.5║ MSIE 4║Edge 12║source
( 출처 ) ║NNav 4║NNav 4.06 ║ NNav 4.06 ║ NNav 3 ║ MSIE NNav ║
╠ ================ ╬ ====== ╬ =========================== ======== ╬ ========== ╬ ============
║ 배열 같은 행동 ║ 아니오 ║ 누른 ║ 예만! 예! ║있는 경우
║ 배열처럼 ║ (배열 (2 번째 인수) ║ ║ ║ 반복자 1 ║
╚ ================ ╩ ====== ╩ =========================== ======== ╩ ========== ╩ ============
1 배열과 같은 객체에 Symbol.iterator 속성 이없는 경우
퍼 뜨리면 예외가 발생합니다.
2 코드에 따라 다릅니다. 다음 예제 코드 "YES"는 희소성을 유지합니다.
function mergeCopyTogether(inputOne, inputTwo){
var oneLen = inputOne.length, twoLen = inputTwo.length;
var newArr = [], newLen = newArr.length = oneLen + twoLen;
for (var i=0, tmp=inputOne[0]; i !== oneLen; ++i) {
tmp = inputOne[i];
if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
}
for (var two=0; i !== newLen; ++i, ++two) {
tmp = inputTwo[two];
if (tmp !== undefined || inputTwo.hasOwnProperty(two)) newArr[i] = tmp;
}
return newArr;
}
위에서 볼 수 있듯이, Concat은 거의 항상 성능과 여분의 스페어 어레이를 유지하는 기능을 모두 수행 할 수있는 방법이라고 주장합니다. 그런 다음 배열과 같은 (예 : DOMNodeLists와 같은 document.body.children
) for 루프는 두 번째로 성능이 높고 스파 스 배열을 유지하는 유일한 다른 방법이기 때문에 for 루프를 사용하는 것이 좋습니다. 아래에서는 희소 배열 및 배열과 같은 의미를 신속하게 살펴보고 혼란을 해결합니다.
𝗧𝗵𝗲 𝗙𝘂𝘁𝘂𝗿𝗲
처음에 일부 사람들은 이것이 우연이라고 생각할 수 있으며 브라우저 공급 업체는 결국 Array.prototype.push를 Array.prototype.concat을 이길 수있을 정도로 빠르도록 최적화 할 것입니다. 잘못된! Array.prototype.concat은 데이터를 복사하는 간단한 붙여 넣기이므로 항상 원칙적으로 더 빠릅니다. 아래는 32 비트 배열 구현의 모습을 단순화 한 설득력있는 시각적 다이어그램입니다 (실제 구현은 훨씬 더 복잡합니다)
바이트 ║ 여기에 데이터
====== ╬ ============
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드
0x00 ║ 정수 길이 = 0x00000001
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드
0x00 ║ int valueIndex = 0x00000000
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드
0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (또는 메모리에있는 곳)
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드
위에서 본 것처럼, 이와 같은 것을 복사하기 위해해야 할 일은 바이트 단위로 복사하는 것만큼이나 간단합니다. Array.prototype.push.apply를 사용하면 데이터를 복사하여 붙여 넣기하는 것 이상의 의미를 갖습니다. ".apply"는 Array.prototype.push에 전달하기 전에 배열의 각 인덱스를 확인하여 인수 집합으로 변환해야합니다. 그런 다음 Array.prototype.push는 매번 추가 메모리를 추가로 할당해야하며 (일부 브라우저 구현의 경우) sparseness를 위해 일부 위치 조회 데이터를 다시 계산할 수도 있습니다.
그것을 생각하는 다른 방법은 이것입니다. 소스 배열 1은 큰 용지 묶음입니다. 소스 어레이 2는 또 다른 큰 용지 더미입니다. 당신이 더 빠를까요
- 상점에 가서 각 소스 어레이의 사본에 필요한 충분한 용지를 구입하십시오. 그런 다음 각 소스 배열 용지 더미를 복사기를 통해 넣고 결과물 두 장을 스테이플합니다.
- 상점에 가서 첫 번째 소스 어레이의 단일 사본에 충분한 용지를 구입하십시오. 그런 다음 빈 배열이 빈 공간이 없도록 수동으로 소스 배열을 새 용지에 복사하십시오. 그런 다음 상점으로 돌아가서 두 번째 소스 배열에 충분한 용지를 구입하십시오. 그런 다음 두 번째 소스 배열을 통해 복사하면서 복사본에 공백이 생기지 않도록 복사하십시오. 그런 다음 복사 된 모든 용지를 함께 스테이플하십시오.
위의 비유에서 옵션 # 1은 Array.prototype.concat을 나타내고 # 2는 Array.prototype.push.apply를 나타냅니다. 솔리드 배열이 아닌 희소 배열에 대한 메소드를 테스트한다는 점만 다른 유사한 JSperf로 이것을 테스트 해 보겠습니다. 여기서 바로 찾을 수 있습니다 .
따라서이 특정 사용 사례의 성능 미래는 Array.prototype.push가 아니라 Array.prototype.concat에 있다고 생각합니다.
𝗖𝗹𝗮𝗿𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀
𝗦𝗽𝗮𝗿𝗲 𝗔𝗿𝗿𝗮𝘆𝘀
배열의 특정 구성원이 단순히 누락 된 경우 예를 들면 다음과 같습니다.
// This is just as an example. In actual code,
// do not mix different types like this.
var mySparseArray = [];
mySparseArray[0] = "foo";
mySparseArray[10] = undefined;
mySparseArray[11] = {};
mySparseArray[12] = 10;
mySparseArray[17] = "bar";
console.log("Length: ", mySparseArray.length);
console.log("0 in it: ", 0 in mySparseArray);
console.log("arr[0]: ", mySparseArray[0]);
console.log("10 in it: ", 10 in mySparseArray);
console.log("arr[10] ", mySparseArray[10]);
console.log("20 in it: ", 20 in mySparseArray);
console.log("arr[20]: ", mySparseArray[20]);
또는 자바 스크립트를 사용하면 예비 배열을 쉽게 초기화 할 수 있습니다.
var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];
𝗔𝗿𝗿𝗮𝘆-𝗟𝗶𝗸𝗲𝘀
배열과 같은 length
속성 은 최소한 속성이 있지만 new Array
또는로 초기화되지 않은 객체입니다 []
. 예를 들어, 아래의 객체는 배열 형으로 분류됩니다.
{0 : "foo", 1 : "bar", 길이 : 2}
document.body.children
새로운 Uint8Array (3)
- 배열과 비슷하지만 배열로 강제 변환하면 생성자가 변경되기 때문에 배열과 비슷합니다.
(function () {반환 인수}) ()
배열과 같은 배열을 슬라이스와 같은 배열로 강제 변환하는 방법을 사용하여 어떤 일이 발생하는지 관찰하십시오.
var slice = Array.prototype.slice;
// For arrays:
console.log(slice.call(["not an array-like, rather a real array"]));
// For array-likes:
console.log(slice.call({0: "foo", 1: "bar", length:2}));
console.log(slice.call(document.body.children));
console.log(slice.call(new Uint8Array(3)));
console.log(slice.call( function(){return arguments}() ));
- 참고 : 성능 때문에 함수 인수에서 슬라이스를 호출하는 것은 좋지 않습니다.
배열과 같은 배열을 concat과 같은 배열로 강제 하지 않는 방법을 사용하여 발생하는 일을 관찰하십시오 .
var empty = [];
// For arrays:
console.log(empty.concat(["not an array-like, rather a real array"]));
// For array-likes:
console.log(empty.concat({0: "foo", 1: "bar", length:2}));
console.log(empty.concat(document.body.children));
console.log(empty.concat(new Uint8Array(3)));
console.log(empty.concat( function(){return arguments}() ));