𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵𝗔𝗻𝗱𝗥𝗲𝘀𝘂𝗹𝘁𝘀
สำหรับข้อเท็จจริงการทดสอบประสิทธิภาพที่ jsperfและการตรวจสอบบางสิ่งในคอนโซลจะดำเนินการ สำหรับการวิจัยirt.org เว็บไซต์ถูกนำมาใช้ ด้านล่างคือชุดของแหล่งข้อมูลเหล่านี้ทั้งหมดที่รวมเข้าด้วยกันพร้อมฟังก์ชั่นตัวอย่างที่ด้านล่าง
╔═══════════════╦══════╦═════════════════╦════════ ═══════╦═════════╦══════════╗
║วิธีการ║ควบคุม & กดส่งใช้ app กด. ใช้ x2 ║ ForLoop ║กระจาย║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ mOps / วินาที║179║104║ 76 ║ 81 ║28║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
arr อาร์เรย์เบาบาง║YES! slic เฉพาะส่วนที่หั่น║ไม่ใช่║อาจจะ2 ║ไม่ได้║
║เก็บกระจัดกระจาย║║array (หาเรื่องที่ 1) ║║║║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║รองรับ║MSIE4║MSIE 5.5 ║ MSIE 5.5 ║ MSIE 4 ║Edge 12 ║
║ ( แหล่งที่มา ) ║NNav4║NNav 4.06 ║ NNav 4.06 ║ NNav 3 ║ MSIE NNav ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║การกระทำที่คล้ายอาเรย์║ไม่เพียง แต่ผลัก║ใช่! ║ใช่! ║หากมี║
array like a array ║║array (2nd ARG) ║║║iterator 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 เนื่องจากเป็นทั้งตัวที่มีประสิทธิภาพมากที่สุดอันดับสองและอีกวิธีเดียวที่เก็บอาร์เรย์เบาบาง ด้านล่างเราจะไปอย่างรวดเร็วสิ่งที่มีความหมายโดยอาร์เรย์เบาบางและชอบอาร์เรย์เพื่อล้างความสับสน
𝗧𝗵𝗲𝗙𝘂𝘁𝘂𝗿𝗲
ในตอนแรกบางคนอาจคิดว่านี่เป็นความบังเอิญและในที่สุดผู้ขายเบราว์เซอร์ก็จะสามารถปรับแต่ง Array.prototype.push ให้เร็วที่สุดเพื่อเอาชนะ Array.prototype.concat ไม่ถูกต้อง! Array.prototype.concat จะเร็วขึ้นเสมอ (ตามหลักการอย่างน้อยที่สุด) เพราะมันเป็น copy-n-paste อย่างง่าย ๆ เหนือข้อมูล ด้านล่างนี้เป็นไดอะแกรมแบบ persuado-visual ที่เรียบง่ายของการใช้อาร์เรย์แบบ 32 บิต (โปรดทราบว่าการใช้งานจริงมีความซับซ้อนมากขึ้น)
ไบต์║ข้อมูลที่นี่
═════╬═══════════
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 ║อ้างแล้ว
0x02 ║อ้างแล้ว
0x03 ║อ้างแล้ว
ความยาว 0x00 ║ int = 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 มันเป็นมากกว่าการคัดลอก -n-paste อย่างง่าย ๆ เหนือข้อมูล ".apply" จะต้องตรวจสอบแต่ละดัชนีในอาร์เรย์และแปลงเป็นชุดของอาร์กิวเมนต์ก่อนส่งผ่านไปยัง Array.prototype.push จากนั้น Array.prototype.push จะต้องจัดสรรหน่วยความจำเพิ่มเติมในแต่ละครั้งและ (สำหรับเบราว์เซอร์ที่ใช้งาน) อาจจะคำนวณข้อมูลการค้นหาตำแหน่งเพื่อความกระจ่าง
อีกทางเลือกหนึ่งในการคิดคือ อาร์เรย์ต้นทางหนึ่งคือกองกระดาษขนาดใหญ่ที่เย็บเข้าด้วยกัน อาร์เรย์ของแหล่งที่มาสองเป็นอีกหนึ่งกองเอกสารขนาดใหญ่ มันจะเร็วขึ้นหรือเปล่า
- ไปที่ร้านซื้อกระดาษให้เพียงพอเพื่อคัดลอกอาเรย์แต่ละชุด จากนั้นให้วางชุดกระดาษต้นฉบับแต่ละชุดผ่านเครื่องถ่ายเอกสารและเย็บเล่มผลสองชุดเข้าด้วยกัน
- ไปที่ร้านซื้อกระดาษให้เพียงพอเพื่อทำสำเนาอาร์เรย์แรกชุดแรก จากนั้นคัดลอกอาเรย์แหล่งลงในกระดาษใหม่ด้วยมือเพื่อให้แน่ใจว่าเติมลงในช่องว่างที่กระจัดกระจาย จากนั้นกลับไปที่ร้านซื้อกระดาษให้เพียงพอสำหรับอาร์เรย์แหล่งที่สอง จากนั้นไปยังอาร์เรย์แหล่งที่สองและคัดลอกในขณะที่มั่นใจว่าไม่มีช่องว่างว่างในการคัดลอก จากนั้นเย็บเล่มเอกสารที่คัดลอกทั้งหมดเข้าด้วยกัน
ในการเปรียบเทียบข้างต้นตัวเลือก # 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]);
อีกวิธีหนึ่งคือ javascript ช่วยให้คุณสามารถเริ่มต้นอาร์เรย์ว่างได้อย่างง่ายดาย
var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];
𝗔𝗿𝗿𝗮𝘆-𝗟𝗶𝗸𝗲𝘀
อาร์เรย์เหมือนเป็นวัตถุที่มีlength
คุณสมบัติอย่างน้อยแต่ไม่ได้เริ่มต้นด้วยnew Array
หรือ[]
; ตัวอย่างเช่นวัตถุด้านล่างถูกจัดประเภทเป็นเหมือนอาร์เรย์
{0: "foo", 1: "bar", ความยาว: 2}
document.body.children
ใหม่ Uint8Array (3)
- นี่เป็นเหมือนอาร์เรย์เนื่องจากแม้ว่าจะเป็นอาร์เรย์ (n) (พิมพ์) การบังคับให้อาร์เรย์เปลี่ยนโครงสร้างตัวสร้าง
(function () {return อาร์กิวเมนต์}) ()
สังเกตสิ่งที่เกิดขึ้นโดยใช้วิธีการที่บังคับให้อาร์เรย์ชอบเข้าไปในอาร์เรย์เช่นชิ้น
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}() ));
- หมายเหตุ:มันเป็นวิธีปฏิบัติที่ไม่ดีในการเรียกใช้ slice บนอาร์กิวเมนต์ของฟังก์ชันเนื่องจากประสิทธิภาพ
สังเกตสิ่งที่เกิดขึ้นโดยใช้วิธีที่ไม่บีบบังคับอาร์เรย์ - ชอบเข้าไปในอาร์เรย์เหมือน 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}() ));