วิธีที่เร็วที่สุดในการทำซ้ำอาร์เรย์ใน JavaScript - slice vs. 'for' loop


634

ในการทำซ้ำอาร์เรย์ใน JavaScript: ข้อใดต่อไปนี้เร็วกว่าที่จะใช้

วิธีการแบ่ง

var dup_array = original_array.slice();

For ห่วง

for(var i = 0, len = original_array.length; i < len; ++i)
   dup_array[i] = original_array[i];

ฉันรู้ว่าทั้งสองวิธีทำสำเนาตื้นเท่านั้น: ถ้า original_array มีการอ้างอิงถึงวัตถุวัตถุจะไม่ถูกคัดลอก แต่จะมีการคัดลอกข้อมูลอ้างอิงเท่านั้นดังนั้นทั้งสองอาร์เรย์จึงมีการอ้างอิงไปยังวัตถุเดียวกัน แต่นี่ไม่ใช่ประเด็นของคำถามนี้

ฉันถามแค่ความเร็วเท่านั้น


3
jsben.ch/#/wQ9RU <= มาตรฐานสำหรับวิธีทั่วไปในการโคลนอาเรย์
EscapeNetscape

คำตอบ:


776

มีอย่างน้อย5 (!) วิธีในการโคลนอาร์เรย์:

  • ห่วง
  • ชิ้น
  • Array.from ()
  • concat
  • ผู้ประกอบการแพร่กระจาย (เร็วที่สุด)

มีเธรดของ BENCHMARKS huuuge แล้วโดยให้ข้อมูลต่อไปนี้:

  • สำหรับเบราว์เซอร์กะพริบตาslice()เป็นวิธีที่เร็วที่สุดconcat()ช้าลงเล็กน้อยและwhile loopช้ากว่า 2.4 เท่า

  • เบราว์เซอร์อื่น ๆwhile loopเป็นวิธีที่เร็วที่สุดตั้งแต่เบราว์เซอร์ผู้ที่ไม่ได้มีการเพิ่มประสิทธิภาพภายในและsliceconcat

สิ่งนี้ยังคงเป็นจริงในเดือนกรกฎาคม 2559

ด้านล่างเป็นสคริปต์ง่ายๆที่คุณสามารถคัดลอกวางลงในคอนโซลของเบราว์เซอร์และเรียกใช้หลายครั้งเพื่อดูรูปภาพ พวกมันเอาต์พุตมิลลิวินาทีต่ำกว่าดีกว่า

ในขณะที่วง

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = Array(n); 
i = a.length;
while(i--) b[i] = a[i];
console.log(new Date() - start);

ชิ้น

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = a.slice();
console.log(new Date() - start);

โปรดทราบว่าวิธีการเหล่านี้จะคัดลอกวัตถุ Array เองเนื้อหาอาร์เรย์จะถูกคัดลอกโดยอ้างอิงและไม่ได้โคลนแบบลึก

origAr == clonedArr //returns false
origAr[0] == clonedArr[0] //returns true

48
@ cept0 ไม่มีอารมณ์แค่มาตรฐานjsperf.com/new-array-vs-splice-vs-slice/31
ด่าน

2
@ แดนดังนั้นอะไร ผลการทดสอบของคุณ: Firefox 30 ทุกคืนยังเร็วกว่า Chrome ถึง 230% ตรวจสอบซอร์สโค้ดของ V8 สำหรับspliceและคุณจะประหลาดใจ (ในขณะที่ ... )
mate64

4
น่าเศร้าสำหรับอาร์เรย์สั้นคำตอบที่แตกต่างกันอย่างมากมาย ตัวอย่างเช่นการโคลนอาร์เรย์ของผู้ฟังก่อนเรียกแต่ละรายการ อาร์เรย์เหล่านั้นมักจะมีขนาดเล็กมักจะเป็น 1 องค์ประกอบ
gman

6
คุณพลาดวิธีนี้:A.map(function(e){return e;});
wcochran

13
คุณกำลังเขียนเกี่ยวกับการกระพริบตาเบราว์เซอร์ ไม่กระพริบตาเพียงแค่ตัวเลย์เอาต์ที่มีผลต่อการเรนเดอร์ HTML เป็นหลักและไม่สำคัญเลยใช่ไหม ฉันคิดว่าเราควรพูดถึง V8, Spidermonkey และเพื่อน ๆ ที่นี่ สิ่งที่ทำให้ฉันสับสน สอนฉันถ้าฉันผิด
Neonit

241

เทคนิคslice เป็นวิธีที่เร็วที่สุด อย่างไรก็ตามจะเร็วยิ่งขึ้นหากคุณเพิ่ม0ดัชนีเริ่มต้น

myArray.slice(0);

เร็วกว่า

myArray.slice();

http://jsperf.com/cloning-arrays/3


และmyArray.slice(0,myArray.length-1);เร็วกว่าmyArray.slice(0);?
jave.web

1
@ jave.web คุณเพิ่งลบองค์ประกอบสุดท้ายของอาร์เรย์ สำเนาเต็มคือ array.slice (0) หรือ array.slice (0, array.length)
Marek Marczak

137

แล้ววิธี es6 ล่ะ

arr2 = [...arr1];

23
ถ้าแปลงด้วย Babel:[].concat(_slice.call(arguments))
CHAN

1
ไม่แน่ใจว่าargumentsมาจากไหน... ฉันคิดว่าเอาต์พุต babel ของคุณกำลังทำให้ฟีเจอร์ต่างกัน arr2 = [].concat(arr1)มันมีแนวโน้มที่จะ
Sterling Archer

3
@SterlingArcher จะแตกต่างจากarr2 = [].conact(arr1) ไวยากรณ์จะแปลงหลุม ตัวอย่างเช่น. arr2 = [...arr1][...arr1]undefinedarr1 = Array(1); arr2 = [...arr1]; arr3 = [].concat(arr1); 0 in arr2 !== 0 in arr3
tsh

1
ฉันทดสอบในเบราว์เซอร์ของฉัน (Chrome 59.0.3071.115) กับคำตอบของ Dan ด้านบน มันช้ากว่า. slice () มากกว่า 10 เท่า n = 1000*1000; start = + new Date(); a = Array(n); b = [...a]; console.log(new Date() - start); // 168
Harry Stevens

1
[{a: 'a', b: {c: 'c'}}]จะยังคงสิ่งที่ไม่โคลนเช่นนี้ หากcมีการเปลี่ยนแปลงค่าในอาเรย์ "ที่ซ้ำกัน" มันจะเปลี่ยนไปในอาเรย์ดั้งเดิมเนื่องจากมันเป็นเพียงการคัดลอกอ้างอิงไม่ใช่โคลน
Neurotransmitter

44

วิธีที่ง่ายที่สุดในการโคลน Array หรือ Object:

var dup_array = JSON.parse(JSON.stringify(original_array))

56
หมายเหตุสำคัญสำหรับผู้เริ่มต้น: เนื่องจากสิ่งนี้ขึ้นอยู่กับ JSON สิ่งนี้จึงสืบทอดข้อ จำกัด ของมันเช่นกัน เหนือสิ่งอื่นใดนั่นหมายความว่าอาร์เรย์ของคุณไม่สามารถมีundefinedหรือfunctions ทั้งสองจะถูกแปลงเป็นnullสำหรับคุณในระหว่างJSON.stringifyกระบวนการ กลยุทธ์อื่น ๆ เช่น(['cool','array']).slice()จะไม่เปลี่ยนพวกเขา แต่ยังไม่ได้โคลนวัตถุลึกภายในอาร์เรย์ ดังนั้นจึงมีการแลกเปลี่ยน
Seth Holladay

27
ความสมบูรณ์แบบที่แย่มากและไม่ทำงานกับวัตถุพิเศษเช่น DOM, date, regexp, function ... หรือวัตถุต้นแบบ ไม่สนับสนุนการอ้างอิงแบบวนซ้ำ คุณไม่ควรใช้ JSON สำหรับการโคลนแบบลึก
Yukulélé

17
วิธีที่เลวร้ายที่สุดที่เป็นไปได้! ใช้เฉพาะในกรณีที่ปัญหาบางอย่างอื่น ๆ ทั้งหมดไม่ทำงาน ช้ามันเป็นทรัพยากรที่รุนแรงและมีข้อ จำกัด ของ JSON ทั้งหมดที่ระบุไว้ในความคิดเห็นแล้ว ไม่สามารถจินตนาการได้ว่าจะได้ 25 คะแนนขึ้นไป
Lukas Liesis

2
มันจะคัดลอกอาร์เรย์ที่มี primitives และที่ซึ่งคุณสมบัติคือ arrays ที่มี primitives / arrays เพิ่มเติม เพื่อที่มันจะโอเค
Drenai

4
ฉันทดสอบในเบราว์เซอร์ของฉัน (Chrome 59.0.3071.115) กับคำตอบของ Dan ด้านบน มันช้ากว่า. slice () เกือบ 20 เท่า n = 1000*1000; start = + new Date(); a = Array(n); var b = JSON.parse(JSON.stringify(a)) console.log(new Date() - start); // 221
Harry Stevens

29
var cloned_array = [].concat(target_array);

3
โปรดอธิบายสิ่งนี้
Jed Fox

8
แม้ว่าข้อมูลโค้ดนี้อาจตอบคำถาม แต่ก็ไม่มีบริบทใด ๆ ที่จะอธิบายว่าอย่างไร ลองเพิ่มประโยคหนึ่งหรือสองประโยคเพื่ออธิบายคำตอบของคุณ
brandonscript

32
ฉันเกลียดความคิดเห็นแบบนี้ เห็นได้ชัดว่ามันทำอะไร!
EscapeNetscape

6
คำตอบง่ายๆสำหรับคำถามง่ายๆไม่มีเรื่องใหญ่ให้อ่าน ฉันชอบคำตอบแบบนี้ +1
Achim

15
"ฉันกำลังขอความเร็วเท่านั้น" - คำตอบนี้ไม่ได้บอกถึงความเร็ว นั่นคือคำถามหลักที่ถูกถาม brandonscript มีจุดดี ต้องการข้อมูลเพิ่มเติมเพื่อพิจารณาคำตอบนี้ แต่ถ้ามันเป็นคำถามที่ง่ายกว่านี้จะเป็นคำตอบที่ยอดเยี่ยม
TamusJRoyce

26

ฉันรวบรวมตัวอย่างด่วน: http://jsbin.com/agugo3/edit

ผลลัพธ์ของฉันใน Internet Explorer 8 คือ 156, 782 และ 750 ซึ่งจะบ่งบอกว่าsliceในกรณีนี้เร็วกว่ามาก


อย่าลืมค่าใช้จ่ายเพิ่มเติมของตัวเก็บขยะหากคุณต้องทำสิ่งนี้ให้เร็วมาก ฉันกำลังคัดลอกอาเรย์เพื่อนบ้านสำหรับแต่ละเซลล์ในออโตมาตาเซลลูล่าร์ของฉันโดยใช้ชิ้นและมันช้ากว่าการนำอาเรย์ก่อนหน้านี้มาใช้ซ้ำและคัดลอกค่า Chrome ระบุว่าประมาณ 40% ของเวลาทั้งหมดถูกใช้ไปกับการรวบรวมขยะ
drake7707

21

a.map(e => e)เป็นอีกทางเลือกหนึ่งสำหรับงานนี้ ณ วันนี้.map()มีความรวดเร็วมาก (เกือบเร็วเท่ากับ.slice(0)) ใน Firefox แต่ไม่ใช่ใน Chrome

ในทางตรงกันข้ามถ้าอาร์เรย์มีหลายมิติเนื่องจากอาร์เรย์เป็นวัตถุและวัตถุที่เป็นประเภทอ้างอิงจึงไม่มีวิธีการฝานหรือ concat ที่จะรักษา ... ดังนั้นวิธีหนึ่งที่เหมาะสมในการโคลนอาร์เรย์คือการประดิษฐ์Array.prototype.clone()เป็น ดังต่อไปนี้

Array.prototype.clone = function(){
  return this.map(e => Array.isArray(e) ? e.clone() : e);
};

var arr = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 , 5], 6 ],
    brr = arr.clone();
brr[4][2][1] = "two";
console.log(JSON.stringify(arr));
console.log(JSON.stringify(brr));


ไม่เลว แต่น่าเสียดายที่นี่ใช้งานไม่ได้หากคุณมี Object ในอาร์เรย์: \ JSON.parse (JSON.stringify (myArray)) ทำงานได้ดีขึ้นในกรณีนี้
GBMan

17

Way วิธีที่เร็วที่สุดในการโคลนอาร์เรย์

ฉันทำฟังก์ชันยูทิลิตี้ธรรมดา ๆ นี้เพื่อทดสอบเวลาที่ใช้ในการโคลนอาร์เรย์ ไม่น่าเชื่อถือ 100% แต่สามารถให้แนวคิดแบบกลุ่มกับคุณได้ว่าต้องใช้เวลานานเท่าใดในการโคลนอาร์เรย์ที่มีอยู่:

function clone(fn) {
    const arr = [...Array(1000000)];
    console.time('timer');
    fn(arr);
    console.timeEnd('timer');
}

และทดสอบวิธีการต่าง ๆ :

1)   5.79ms -> clone(arr => Object.values(arr));
2)   7.23ms -> clone(arr => [].concat(arr));
3)   9.13ms -> clone(arr => arr.slice());
4)  24.04ms -> clone(arr => { const a = []; for (let val of arr) { a.push(val); } return a; });
5)  30.02ms -> clone(arr => [...arr]);
6)  39.72ms -> clone(arr => JSON.parse(JSON.stringify(arr)));
7)  99.80ms -> clone(arr => arr.map(i => i));
8) 259.29ms -> clone(arr => Object.assign([], arr));
9) Maximum call stack size exceeded -> clone(arr => Array.of(...arr));

UPDATE :
หมายเหตุ: JSON.parse(JSON.stringify(arr))ออกจากพวกเขาทุกวิธีเดียวที่จะโคลนลึกอาร์เรย์คือการใช้ ที่กล่าวว่าไม่ได้ใช้ข้างต้นถ้าอาร์เรย์ของคุณอาจจะรวมถึงฟังก์ชั่นในขณะที่มันจะกลับมา

ขอบคุณ @GilEpshtain สำหรับการอัปเดตนี้null


2
ฉันพยายามเปรียบเทียบคำตอบของคุณและฉันได้ผลลัพธ์ที่แตกต่างกันมาก: jsben.ch/o5nLG
mesqueeb

@mesqueeb การทดสอบอาจมีการเปลี่ยนแปลงขึ้นอยู่กับเครื่องของคุณแน่นอน อย่างไรก็ตามโปรดอัปเดตคำตอบด้วยผลการทดสอบของคุณ เยี่ยมมาก!
Lior Elrom

ฉันชอบคำตอบของคุณมาก แต่ฉันลองทดสอบของคุณและทำให้arr => arr.slice()เร็วที่สุด
Gil Epshtain

1
@ LiorElrom การอัปเดตของคุณไม่ถูกต้องเนื่องจากวิธีการที่ไม่ได้ต่อเนื่องกัน ตัวอย่างเช่น: JSON.parse(JSON.stringify([function(){}]))จะส่งออก[null]
Gil Epshtain

1
เกณฑ์มาตรฐานที่ดี ผมได้ทดสอบนี้บน Mac ของฉันใน 2 เบราว์เซอร์: Chrome เวอร์ชัน 81.0.4044.113 และ Safari เวอร์ชั่น 13.1 (15609.1.20.111.8) และเร็วที่สุดคือการดำเนินการการแพร่กระจาย: [...arr]มี4.653076171875msใน Chrome และ8.565msใน Safari ได้อย่างรวดเร็วที่สองใน Chrome เป็นฟังก์ชั่นชิ้นarr.slice()ด้วย6.162109375msและใน Safari ที่สองคือมี[].concat(arr) 13.018ms
edufinn

7

ลองดูที่: การเชื่อมโยง มันไม่ได้เกี่ยวกับความเร็ว แต่ความสะดวกสบาย นอกจากนี้อย่างที่คุณเห็นคุณสามารถใช้slice (0)กับประเภทดั้งเดิมเท่านั้น

ในการสร้างอาเรย์อิสระแทนที่จะคัดลอกการอ้างอิงไปยังอาเรย์คุณสามารถใช้วิธีการแบ่งส่วนอาเรย์

ตัวอย่าง:

ในการสร้างอาเรย์อิสระแทนที่จะคัดลอกการอ้างอิงไปยังอาเรย์คุณสามารถใช้วิธีการแบ่งส่วนอาเรย์

var oldArray = ["mip", "map", "mop"];
var newArray = oldArray.slice();

ในการคัดลอกหรือคัดลอกวัตถุ:

function cloneObject(source) {
    for (i in source) {
        if (typeof source[i] == 'source') {
            this[i] = new cloneObject(source[i]);
        }
        else{
            this[i] = source[i];
  }
    }
}

var obj1= {bla:'blabla',foo:'foofoo',etc:'etc'};
var obj2= new cloneObject(obj1);

แหล่งที่มา: ลิงค์


1
ดั้งเดิมประเภทความคิดเห็นนำไปใช้กับforวงในคำถามได้เป็นอย่างดี
user113716

4
หากฉันกำลังคัดลอกอาเรย์ของวัตถุฉันคาดว่าอาเรย์ใหม่จะอ้างอิงวัตถุเดียวกันมากกว่าที่จะทำการคัดลอกวัตถุ
lincolnk

7

ดังที่ @Dan กล่าวว่า "คำตอบนี้ล้าสมัยอย่างรวดเร็วใช้มาตรฐานเพื่อตรวจสอบสถานการณ์จริง" มีคำตอบเฉพาะจาก jsperf ที่ไม่มีคำตอบสำหรับตัวเอง: ในขณะที่ :

var i = a.length;
while(i--) { b[i] = a[i]; }

มี 960,589 ops / วินาทีกับ runnerup a.concat()ที่ 578,129 ops / วินาทีซึ่งคือ 60%

นี่เป็น Firefox รุ่นล่าสุด (40) 64 บิต


@aleclarson สร้างมาตรฐานใหม่ที่เชื่อถือได้มากขึ้น


1
คุณควรเชื่อมโยง jsperf จริงๆ สิ่งที่คุณคิดว่าเสียหายเพราะอาร์เรย์ใหม่ถูกสร้างขึ้นในทุกกรณีทดสอบยกเว้นการทดสอบ 'while loop'
aleclarson

1
ฉันสร้าง jsperf ใหม่ที่แม่นยำยิ่งขึ้น: jsperf.com/clone-array-3
aleclarson

60% คืออะไร เร็วขึ้น 60%?
Peter Mortensen

1
@PeterMortensen: 587192 คือ ~ 60% (61.1 ... ) จาก 960589.
serv-inc

7

ECMAScript 2015 วิธีใช้Spreadตัวดำเนินการ:

ตัวอย่างพื้นฐาน:

var copyOfOldArray = [...oldArray]
var twoArraysBecomeOne = [...firstArray, ..seccondArray]

ลองในคอนโซลเบราว์เซอร์:

var oldArray = [1, 2, 3]
var copyOfOldArray = [...oldArray]
console.log(oldArray)
console.log(copyOfOldArray)

var firstArray = [5, 6, 7]
var seccondArray = ["a", "b", "c"]
var twoArraysBecomOne = [...firstArray, ...seccondArray]
console.log(twoArraysBecomOne);

อ้างอิง


อาจเป็นสิ่งเดียวที่รวดเร็วในการแพร่กระจายคือการพิมพ์ มันเป็นการแสดงที่น้อยกว่าวิธีอื่น ๆ
XT_Nova

3
โปรดระบุลิงก์เกี่ยวกับการโต้แย้งของคุณ
Marian07

6

มันขึ้นอยู่กับเบราว์เซอร์ หากคุณดูในโพสต์บล็อกArray.prototype.slice vs การสร้างอาร์เรย์ด้วยตนเองมีคำแนะนำคร่าวๆเกี่ยวกับประสิทธิภาพของแต่ละรายการ:

ป้อนคำอธิบายภาพที่นี่

ผล:

ป้อนคำอธิบายภาพที่นี่


1
argumentsไม่ใช่อาร์เรย์ที่เหมาะสมและเขาใช้callเพื่อบังคับsliceให้ทำงานในคอลเลกชัน ผลลัพธ์อาจทำให้เข้าใจผิด
lincolnk

ใช่ฉันหมายถึงพูดถึงว่าในโพสต์ของฉันว่าสถิติเหล่านี้อาจมีการเปลี่ยนแปลงในขณะนี้ด้วยการปรับปรุง broswers แต่มันให้ความคิดทั่วไป
kyndigs

2
@diugalde ฉันคิดว่าสถานการณ์เดียวที่รหัสการโพสต์เป็นภาพเป็นที่ยอมรับคือเมื่อรหัสอาจเป็นอันตรายและไม่ควรคัดลอกวาง ในกรณีนี้มันค่อนข้างไร้สาระ
Florian Wendelborn

6

มีวิธีแก้ปัญหาที่สะอาดกว่ามาก:

var srcArray = [1, 2, 3];
var clonedArray = srcArray.length === 1 ? [srcArray[0]] : Array.apply(this, srcArray);

ต้องมีการตรวจสอบความยาวเนื่องจากตัวArrayสร้างทำงานแตกต่างกันเมื่อมีการเรียกด้วยอาร์กิวเมนต์หนึ่งตัว


2
แต่มันเร็วที่สุด?
Chris Wesseling

14
ความหมายมากกว่าsplice()บางที แต่จริงๆใช้และนี่คือทั้งหมดที่ใช้งานง่าย
Michael Piefel

แสดงประสิทธิภาพที่ช้าที่สุดใน chrome- jsperf.com/new-array-vs-splice-vs-slice/113
chrismarx

3
คุณสามารถใช้Array.ofและเพิกเฉยต่อความยาว:Array.of.apply(Array, array)
Oriol

6

โปรดจำไว้ว่า. slice () จะไม่ทำงานสำหรับอาร์เรย์สองมิติ คุณจะต้องมีฟังก์ชันดังนี้:

function copy(array) {
  return array.map(function(arr) {
    return arr.slice();
  });
}

3
ใน Javascript ไม่มีอาร์เรย์สองมิติ มีเพียงอาร์เรย์ที่มีอาร์เรย์อยู่ สิ่งที่คุณพยายามทำคือสำเนาที่ไม่จำเป็นในคำถาม
Aloso

5

ขึ้นอยู่กับความยาวของอาเรย์ หากความยาวของอาร์เรย์คือ <= 1,000,000 วิธีการsliceและconcatวิธีการใช้เวลาประมาณเดียวกัน แต่เมื่อคุณให้ช่วงกว้างขึ้นconcatเมธอดจะชนะ

ตัวอย่างเช่นลองใช้รหัสนี้:

var original_array = [];
for(var i = 0; i < 10000000; i ++) {
    original_array.push( Math.floor(Math.random() * 1000000 + 1));
}

function a1() {
    var dup = [];
    var start = Date.now();
    dup = original_array.slice();
    var end = Date.now();
    console.log('slice method takes ' + (end - start) + ' ms');
}

function a2() {
    var dup = [];
    var start = Date.now();
    dup = original_array.concat([]);
    var end = Date.now();
    console.log('concat method takes ' + (end - start) + ' ms');
}

function a3() {
    var dup = [];
    var start = Date.now();
    for(var i = 0; i < original_array.length; i ++) {
        dup.push(original_array[i]);
    }
    var end = Date.now();
    console.log('for loop with push method takes ' + (end - start) + ' ms');
}

function a4() {
    var dup = [];
    var start = Date.now();
    for(var i = 0; i < original_array.length; i ++) {
        dup[i] = original_array[i];
    }
    var end = Date.now();
    console.log('for loop with = method takes ' + (end - start) + ' ms');
}

function a5() {
    var dup = new Array(original_array.length)
    var start = Date.now();
    for(var i = 0; i < original_array.length; i ++) {
        dup.push(original_array[i]);
    }
    var end = Date.now();
    console.log('for loop with = method and array constructor takes ' + (end - start) + ' ms');
}

a1();
a2();
a3();
a4();
a5();

หากคุณตั้งค่าความยาวของ original_array เป็น 1,000,000 sliceวิธีและconcatวิธีการใช้เวลาประมาณเดียวกัน (3-4 มิลลิวินาทีขึ้นอยู่กับตัวเลขสุ่ม)

หากคุณตั้งค่าความยาวของ original_array เป็น 10,000,000 sliceวิธีการนั้นจะใช้เวลานานกว่า 60 ms และconcatวิธีนั้นจะใช้เวลามากกว่า 20 ms


dup.pushผิดควรใช้a5แทนdup[i] =
4esn0k


2
        const arr = ['1', '2', '3'];

         // Old way
        const cloneArr = arr.slice();

        // ES6 way
        const cloneArrES6 = [...arr];

// But problem with 3rd approach is that if you are using muti-dimensional 
 // array, then only first level is copied

        const nums = [
              [1, 2], 
              [10],
         ];

        const cloneNums = [...nums];

// Let's change the first item in the first nested item in our cloned array.

        cloneNums[0][0] = '8';

        console.log(cloneNums);
           // [ [ '8', 2 ], [ 10 ], [ 300 ] ]

        // NOOooo, the original is also affected
        console.log(nums);
          // [ [ '8', 2 ], [ 10 ], [ 300 ] ]

ดังนั้นเพื่อหลีกเลี่ยงสถานการณ์เหล่านี้ให้ใช้

        const arr = ['1', '2', '3'];

        const cloneArr = Array.from(arr);

มันเป็นสิ่งที่ถูกต้องที่จะชี้ให้เห็นว่าการเปลี่ยนแปลงcloneNums[0][0]ในตัวอย่างของคุณแพร่กระจายการเปลี่ยนแปลงอย่างไรnums[0][0]- แต่นั่นเป็นเพราะnums[0][0]วัตถุที่มีประสิทธิภาพซึ่งมีการคัดลอกข้อมูลอ้างอิงcloneNumsโดยผู้ดำเนินการแพร่กระจาย ทั้งหมดที่กล่าวมาพฤติกรรมนี้จะไม่ส่งผลกระทบต่อโค้ดที่เรากำลังคัดลอกโดยค่า (int, สตริง ฯลฯ ตัวอักษร)
Aditya MP

1

เวลามาตรฐาน!

function log(data) {
  document.getElementById("log").textContent += data + "\n";
}

benchmark = (() => {
  time_function = function(ms, f, num) {
    var z = 0;
    var t = new Date().getTime();
    for (z = 0;
      ((new Date().getTime() - t) < ms); z++)
      f(num);
    return (z)
  }

  function clone1(arr) {
    return arr.slice(0);
  }

  function clone2(arr) {
    return [...arr]
  }

  function clone3(arr) {
    return [].concat(arr);
  }

  Array.prototype.clone = function() {
    return this.map(e => Array.isArray(e) ? e.clone() : e);
  };

  function clone4(arr) {
    return arr.clone();
  }


  function benchmark() {
    function compare(a, b) {
      if (a[1] > b[1]) {
        return -1;
      }
      if (a[1] < b[1]) {
        return 1;
      }
      return 0;
    }

    funcs = [clone1, clone2, clone3, clone4];
    results = [];
    funcs.forEach((ff) => {
      console.log("Benchmarking: " + ff.name);
      var s = time_function(2500, ff, Array(1024));
      results.push([ff, s]);
      console.log("Score: " + s);

    })
    return results.sort(compare);
  }
  return benchmark;
})()
log("Starting benchmark...\n");
res = benchmark();

console.log("Winner: " + res[0][0].name + " !!!");
count = 1;
res.forEach((r) => {
  log((count++) + ". " + r[0].name + " score: " + Math.floor(10000 * r[1] / res[0][1]) / 100 + ((count == 2) ? "% *winner*" : "% speed of winner.") + " (" + Math.round(r[1] * 100) / 100 + ")");
});
log("\nWinner code:\n");
log(res[0][0].toString());
<textarea rows="50" cols="80" style="font-size: 16; resize:none; border: none;" id="log"></textarea>

มาตรฐานจะทำงานเป็นเวลา 10 วินาทีตั้งแต่คุณคลิกปุ่ม

ผลลัพธ์ของฉัน:

Chrome (เครื่องมือ V8):

1. clone1 score: 100% *winner* (4110764)
2. clone3 score: 74.32% speed of winner. (3055225)
3. clone2 score: 30.75% speed of winner. (1264182)
4. clone4 score: 21.96% speed of winner. (902929)

Firefox (SpiderMonkey Engine):

1. clone1 score: 100% *winner* (8448353)
2. clone3 score: 16.44% speed of winner. (1389241)
3. clone4 score: 5.69% speed of winner. (481162)
4. clone2 score: 2.27% speed of winner. (192433)

รหัสผู้ชนะ:

function clone1(arr) {
    return arr.slice(0);
}

ผู้ชนะเครื่องยนต์:

SpiderMonkey (Mozilla / Firefox)


1

วิธีที่รวดเร็วในการทำซ้ำอาร์เรย์ใน JavaScript ตามลำดับ:

#1: array1copy = [...array1];

#2: array1copy = array1.slice(0);

#3: array1copy = array1.slice();

หากวัตถุอาร์เรย์ของคุณมีเนื้อหา JSON ที่ไม่สามารถทำให้เป็นลำดับ (ฟังก์ชั่น, Number.POSITIVE_INFINITY และอื่น ๆ ) ได้ดีกว่าที่จะใช้

array1copy = JSON.parse(JSON.stringify(array1))


0

คุณสามารถติดตามรหัสนี้ วิธีอาร์เรย์โคลนที่ไม่เปลี่ยนรูป นี่เป็นวิธีที่สมบูรณ์แบบในการโคลนอาร์เรย์


const array = [1, 2, 3, 4]

const newArray = [...array]
newArray.push(6)
console.log(array)
console.log(newArray)

0

ใน ES6 คุณสามารถใช้ไวยากรณ์ Spread ได้ได้

ตัวอย่าง:

let arr = ['a', 'b', 'c'];
let arr2 = [...arr];

โปรดทราบว่าผู้ประกอบการแพร่กระจายสร้างอาร์เรย์ใหม่ที่สมบูรณ์ดังนั้นการแก้ไขหนึ่งจะไม่ส่งผลกระทบต่ออีก

ตัวอย่าง:

arr2.push('d') // becomes ['a', 'b', 'c', 'd']
console.log(arr) // while arr retains its values ['a', 'b', 'c']
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.