𝗔𝗻𝗱
Đối với thực tế, một bài kiểm tra hiệu suất tại jsperf và kiểm tra một số thứ trong bảng điều khiển được thực hiện. Đối với nghiên cứu, trang web irt.org được sử dụng. Dưới đây là một tập hợp tất cả các nguồn này được đặt cùng với một hàm ví dụ ở phía dưới.
╔═══════════════╦══════╦═════════════════╦════════ ═══════╦═════════╦══════════╗
Phương thức ║Concat║slice & push.apply ║ push.apply x2 ║ ForLoop S lây lan
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ mOps / giây ║179 104 76 81 28
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
Mảng thưa thớt ║YES! ║Chỉ cắt lát ║ không Có thể 2 no ║
Giữ thưa thớt array (1st arg) ║ ║ ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
Hỗ trợ ║MSIE 4║MSIE 5.5 MSIE 5.5 MSIE 4 ║ Chỉnh sửa 12
║ ( nguồn ) ║NNav 4║NNav 4,06 ║ ║ NNav 4,06 NNav 3 ║ MSIE NNav ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
Hành động giống như phản ứng║không Chỉ bị đẩy ║ CÓ! CÓ! Nếu có ║
║like một mảng ║ ║array (2nd arg) ║ ║ ║iterator 1 ║
╚═══════════════╩══════╩═════════════════╩════════ ═══════╩═════════╩══════════╝
1 Nếu đối tượng giống như mảng không có thuộc tính Symbol.iterator , thì hãy thử
để lây lan nó sẽ ném một ngoại lệ.
2 Phụ thuộc vào mã. Mã ví dụ sau "CÓ" duy trì độ thưa thớt.
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;
}
Như đã thấy ở trên, tôi sẽ lập luận rằng Concat hầu như luôn luôn là cách để đi cả về hiệu suất và khả năng giữ lại độ thưa của các mảng dự phòng. Sau đó, đối với các lượt thích mảng (như DOMNodeLists thích document.body.children
), tôi khuyên bạn nên sử dụng vòng lặp for vì đây là phương thức hiệu quả nhất thứ 2 và là phương thức khác duy trì các mảng thưa thớt. Dưới đây, chúng tôi sẽ nhanh chóng đi qua những gì có nghĩa là các mảng thưa thớt và thích mảng để xóa sự nhầm lẫn.
𝗧𝗵𝗲 𝗙𝘂𝘁𝘂𝗿𝗲
Lúc đầu, một số người có thể nghĩ rằng đây là một con sán và các nhà cung cấp trình duyệt cuối cùng sẽ tìm cách tối ưu hóa Array.prototype.push để đủ nhanh để đánh bại Array.prototype.concat. SAI LẦM! Array.prototype.concat sẽ luôn nhanh hơn (về nguyên tắc ít nhất) bởi vì nó là một bản sao-n-dán đơn giản trên dữ liệu. Dưới đây là sơ đồ trực quan đơn giản hóa về cách triển khai mảng 32 bit có thể trông như thế nào (xin lưu ý rằng việc triển khai thực tế phức tạp hơn rất nhiều)
Byte Dữ liệu tại đây
═════╬═══════════
0x00 ║ int nonNumericProperIESLpm = 0x00000000
0x01 ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int chiều dài = 0x00000001
0x01 ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int value Index = 0x00000000
0x01 ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ uintptr_t valuePulum = 0x38d9eb60 (hoặc bất cứ nơi nào có trong bộ nhớ)
0x01 ibid
0x02 ║ ibid
0x03 ║ ibid
Như đã thấy ở trên, tất cả những gì bạn cần làm để sao chép một cái gì đó gần như đơn giản như sao chép byte cho byte. Với Array.prototype.push.apply, nó không chỉ là một bản sao-n-dán đơn giản trên dữ liệu. ".Pyly" phải kiểm tra từng chỉ mục trong mảng và chuyển đổi nó thành một tập hợp các đối số trước khi chuyển nó sang Array.prototype.push. Sau đó, Array.prototype.push phải phân bổ thêm bộ nhớ mỗi lần và (đối với một số triển khai trình duyệt) thậm chí có thể tính toán lại một số dữ liệu tra cứu vị trí cho độ thưa.
Một cách khác để nghĩ về nó là điều này. Mảng nguồn một là một chồng giấy lớn được ghim lại với nhau. Mảng nguồn hai cũng là một chồng giấy tờ lớn khác. Nó sẽ nhanh hơn cho bạn
- Đi đến cửa hàng, mua đủ giấy cần thiết cho một bản sao của từng mảng nguồn. Sau đó đặt từng chồng giấy nguồn thông qua một máy sao chép và ghim hai bản sao lại với nhau.
- Đi đến cửa hàng, mua đủ giấy cho một bản sao của mảng nguồn đầu tiên. Sau đó, sao chép mảng nguồn vào giấy mới bằng tay, đảm bảo điền vào bất kỳ chỗ trống nào. Sau đó, quay trở lại cửa hàng, mua đủ giấy cho mảng nguồn thứ hai. Sau đó, đi qua mảng nguồn thứ hai và sao chép nó trong khi đảm bảo không có khoảng trống nào trong bản sao. Sau đó, ghim tất cả các giấy tờ sao chép lại với nhau.
Trong sự tương tự ở trên, tùy chọn # 1 đại diện cho Array.prototype.concat trong khi # 2 đại diện cho Array.prototype.push.apply. Chúng ta hãy kiểm tra điều này với một JSperf tương tự chỉ khác ở chỗ cái này kiểm tra các phương thức trên các mảng thưa thớt, không phải là mảng rắn. Người ta có thể tìm thấy nó ngay tại đây .
Do đó, tôi cho rằng trường hợp tương lai của hiệu năng cho trường hợp sử dụng cụ thể này không nằm ở Array.prototype.push, mà là ở Array.prototype.concat.
𝗖𝗹𝗮𝗿𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀
𝗦𝗽𝗮𝗿𝗲 𝗔𝗿𝗿𝗮𝘆𝘀
Khi một số thành viên nhất định của mảng bị thiếu. Ví dụ:
// 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]);
Ngoài ra, javascript cho phép bạn khởi tạo các mảng dự phòng một cách dễ dàng.
var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];
𝗔𝗿𝗿𝗮𝘆-
Giống như mảng là một đối tượng có ít nhất một thuộc length
tính, nhưng không được khởi tạo với new Array
hoặc []
; Ví dụ, các đối tượng dưới đây được phân loại là giống như mảng.
{0: "foo", 1: "thanh", chiều dài: 2}
tài liệu.body.children
Uint8Array mới (3)
- Điều này giống như mảng bởi vì mặc dù đó là một mảng (n) (gõ), việc ép buộc nó vào một mảng sẽ thay đổi hàm tạo.
(hàm () {trả về đối số}) ()
Quan sát những gì xảy ra bằng cách sử dụng một phương thức ép các lượt thích mảng thành các mảng như lát.
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}() ));
- LƯU Ý: Đó là thực tế xấu khi gọi lát cắt trên các đối số chức năng vì hiệu suất.
Quan sát những gì xảy ra bằng cách sử dụng một phương thức không ép các lượt thích mảng thành các mảng như 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}() ));