SOFTWARE DEVELOPMENT | 2 mins read

Clone Deep Array in Javascript (Copy array)

By Son on 03 Jul 2020
sennalabs-blog-banner

ในปัจจุบันนี้ ปฏิเสธไม่ได้เลยว่าภาษาที่ถูกใช้ในการเขียนเว็บต่าง ๆ นั้น คงหนีไม่พ้นภาษา Javascript ซึ่งเป็นภาษาที่ถูกนำไปพัฒนาเป็น framework หรือ library ต่าง ๆ มากมาย 

ผู้พัฒนาหลายคนก็มีรูปแบบการเขียนภาษา Javascript ที่แตกต่างกัน เราเลยมีแนวทางการเขียนที่หลากหลาย มาแบ่งปันเพื่อน ๆ เกี่ยวกับการจัดการ Array ด้วยภาษา Javascript กัน เรามาดูตัวอย่างกันเลยดีกว่าโดยปกติแล้วการ copy ค่าจาก value type ธรรมดา สามารถเขียนได้ดังนี้ let value = 3;

 

let valueCopy = value; // create copy
                console.log(valueCopy); // 3
                valueCopy = 100 // Change valueCopy
                console.log(valueCopy); // 100// ✅ Original NOT affected 
                console.log(value); // 3ซึ่งค่าของ value จะไม่เกิดผลกระทบเมื่อค่าที่ถูก copy ไปถูกเปลี่ยนแปลงแต่ การ copy ค่าจาก array type นั้นไม่เหมือนกับ value type ดังตัวอย่าง
                let array = [1,2,3];
                let arrayCopy = array; // create copy
                console.log(arrayCopy); // [1,2,3];
                arrayCopy[0] = '👻'; // Change 1st element of the array
                console.log(arrayCopy); // [ '👻', 2, 3 ] // ❌Original got affected
                console.log(array); // [ '👻', 2, 3 ] 
 
จะเห็นว่า ค่าของ original array นั้นถูกเปลี่ยนค่าด้วย เมื่อทำการ copy วิธีเดียวกับ value type เนื่องจาก สิ่งที่ copy มานั้น ไม่ใช่ค่า array แต่เป็น address ที่ถูกชี้ไปยังพื้นที่หน่วยความจำของ array ที่ใช้ เมื่อเราทำการ copy ค่ามา นั่นหมายถึงตัวแปรที่ copy มาจะมีพื้นที่หน่วยความจำเดียวกัน เมื่อค่าเปลี่ยน จึงทำให้ค่า origin array ถูกเปลี่ยนค่าด้วยทันที

ดังนั้นวีธีการ clone หรือ copy ค่าจาก array ที่ถูกต้องนั้น สามารถเขียนง่าย ๆ ดังนี้let array = [1,2,3];

 

let arrayCopy = [...array]; // create TRUE copy
                console.log(arrayCopy); // [1,2,3];
                arrayCopy[0] = '👻'; // Change 1st element of the array
                console.log(arrayCopy); // [ '👻', 2, 3 ] // ✅ Original NOT affected 
                console.log(array); // [ 1, 2, 3 ] แต่ !!! การใช้ [...] spread operator ไม่สามารถใช้ได้ทุกกรณี สามารถใช้ได้ฉพาะ array ที่มี level เดียวเท่านั้น ยกตัวอย่างหากเป็น nestedArray ดังตัวอย่าง
                let nestedArray = [1, [2], 3];
                let arrayCopy = [...nestedArray3];// Make some changes
                arrayCopy[0] = '👻'; // change shallow element
                arrayCopy[1][0] = '💩'; // change nested element
                console.log(arrayCopy); // [ '👻', [ '💩' ], 3 ]// ❌ Nested array got affected
                console.log(nestedArray); // [ 1, [ '💩' ], 3 ] จะเห็นว่าค่าของ origin nestedArray ถูกเปลี่ยนแปลงค่าด้วยเช่นกัน ดังนั้นวิธีที่ปลอดภัยที่สุดมีดังนี้หากเป็น 
                nestedArraylet nestedArray = [1, [2], 3];
                let arrayCopy = JSON.parse(JSON.stringify(nestedArray));
                // Make some changes
                arrayCopy[0] = '👻'; // change shallow element
                arrayCopy[1][0] = '💩'; // change nested element
                console.log(arrayCopy); // [ '👻', [ '💩' ], 3 ]
                // ✅ Nested array NOT affected
                console.log(nestedArray); //  1, [ 2 ], 3 ]
 
ซึ่งวิธีนี้จะทำการเปลี่ยน array ให้เป็น string ด้วย JSON.stringify และเปลี่ยนกลับเป็น array อีกครั้งด้วย JSON.parse โดยจะได้ค่า array จริง ๆ แต่วิธีนี้จะไม่สามารถใช้ได้ทุกกรณีเช่นกันหาก array มีฟังก์ชั่น หรือสัญลักษณ์ต่าง ๆ

จึงทำให้วิธีการ JSON.stringify / parse กับ วิธีการ deepClone ด้วย library อื่นมาช่วย นั้นต่างกันดังนี้

  • JSON.stringify / parse ใช้ได้กับตัวอักษร Number และ String และ Object เท่านั้นโดยไม่มีฟังก์ชันหรือคุณสมบัติ Symbol

  • deepClone ทำงานกับทุกประเภทฟังก์ชั่นและสัญลักษณ์จะถูกคัดลอกโดย reference
 

จากตัวอย่างที่กล่าวไปข้างต้น เรามีวิธีที่ช่วย clone array ที่ง่ายและขึ้นอยู่กับการใช้งาน ดังนี้


1. ใช้ JSON.parse(JSON.stringify(array)) (ใช้ได้กับตัวอักษร Number และ String และ Object)

2. ใช้  library อื่น ๆ ที่ช่วยในการจัดการ array เช่น _.cloneDeep ของ library lodash เป็นต้น (ใช้ได้ทุกกรณี)
 

// How to deep clone array const numbers = [1, [2], [3,[4],5]] // Using javascript JSON.parse(JSON.stringify(numbers)) // Using lodash _.cloneDeep(numbers)

[แปลจากบทความของคุณ Samantha Ming]

Written By
Son