JavaScript에서 배열을 딥 클론하는 방법



어레이 복제에는 얕은 복제와 깊은 복제의 두 가지 유형이 있습니다. 얕은 복사본은 배열의 첫 번째 수준만 다루고 나머지는 참조됩니다. 중첩 배열의 진정한 복사본을 원한다면 딥 클론이 필요합니다. 딥 클론의 경우 JSON 방식을 사용하거나 Lodash를 사용하는 것이 더 좋습니다 👍

const numbers = [1, [2], [3, [4]], 5];

// Using JavaScript
JSON.parse(JSON.stringify(numbers));

// Using Lodash
_.cloneDeep(numbers);


배열은 참조 유형입니다.



두 가지 유형의 복제가 있는 이유를 이해하기 위해. 기본 사항을 자세히 살펴보고 참조 유형이 무엇인지 설명하겠습니다.

기본 유형(예: 숫자 또는 문자열)과 달리 배열은 참조 유형입니다. 즉, 배열을 변수에 할당할 때 실제 배열 자체가 아니라 메모리 주소를 할당하는 것입니다. WTH 😱. 나는 이것이 약간 혼란 스럽다는 것을 압니다. 그럼 예를 들어 설명해 보겠습니다.

값 유형 복사



그래서 여기에 큰 문제는 없습니다. value 의 복사본을 만들고 있습니다. 그리고 valueCopy 를 변경해도 원본value 에는 영향을 미치지 않습니다. 의미가 있습니다. 사본을 변경할 때 원본에 전혀 영향을 미치지 않아야 합니다. 여기 다 좋아요👍

let value = 3;
let valueCopy = value; // create copy

console.log(valueCopy); // 3

// Change valueCopy
valueCopy = 100
console.log(valueCopy); // 100

// ✅ Original NOT affected 
console.log(value); // 3


참조 유형 복사



자, 이제 상황이 이상해집니다. 값 유형을 복사할 때와 동일한 방법을 사용하여 배열을 복사해 보겠습니다.

let array = [1,2,3];
let arrayCopy = array; // create copy

console.log(arrayCopy); // [1,2,3];

// Change 1st element of the array
arrayCopy[0] = '👻';
console.log(arrayCopy); // [ '👻', 2, 3 ]

// ❌Original got affected
console.log(array); // [ '👻', 2, 3 ]


원래 어레이도 영향을 받은 이유는 무엇입니까? 복사한 것은 배열 자체가 아니라 배열이 차지하는 메모리 공간에 대한 포인터이기 때문입니다. 참조 유형은 값을 보유하지 않으며 메모리의 값에 대한 포인터입니다.

참조 유형 복사에 대한 솔루션

따라서 해결책은 포인터가 아닌 값을 복사하는 것입니다. 이와 같이:

let array = [1,2,3];
let arrayCopy = [...array]; // create TRUE copy

console.log(arrayCopy); // [1,2,3];

// Change 1st element of the array
arrayCopy[0] = '👻';
console.log(arrayCopy); // [ '👻', 2, 3 ]

// ✅ Original NOT affected 
console.log(array); // [ 1, 2, 3 ]


얕은 대 딥 클론



확산...을 사용하여 배열을 복사할 때 얕은 복사본만 생성합니다. 배열이 중첩되거나 다차원이면 작동하지 않습니다. 한 번 보자:

let nestedArray = [1, [2], 3];
let arrayCopy = [...nestedArray]; 

// 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 ]


보시다시피 얕거나 첫 번째 레이어가 좋습니다. 그러나 중첩된 요소를 변경하면 원래 배열도 영향을 받습니다. 따라서 해결책은 딥 클론을 수행하는 것입니다.

let 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 ]



커뮤니티 입력



JSON과 호환되지 않는 값




: JSON 솔루션은 정말 조심해야 합니다! JSON과 호환되지 않는 값으로는 작동하지 않습니다. 이러한 데이터로 작업해야 하는 경우 라이브러리 기능 사용을 고려하십시오.

function nestedCopy(array) {
    return JSON.parse(JSON.stringify(array));
}

// undefineds are converted to nulls
nestedCopy([1, undefined, 2]) // -> [1, null, 2]

// DOM nodes are converted to empty objects
nestedCopy([document.body, document.querySelector('p')]) // -> [{}, {}]

// JS dates are converted to strings
nestedCopy([new Date()]) // -> ["2019-03-04T10:09:00.419Z"]


deepClone 대 JSON




: deepClone과 JSON.stringify/parse 간에 약간의 차이가 있음을 알려드립니다.

  • JSON.stringify/parse는 함수 또는 기호 속성이 없는 숫자, 문자열 및 개체 리터럴에서만 작동합니다.

  • deepClone은 모든 유형, 함수 및 기호에 대한 작업을 참조로 복사합니다.

  • 예를 들면 다음과 같습니다.

    const lodashClonedeep = require("lodash.clonedeep");
    
    const arrOfFunction = [() => 2, {
        test: () => 3,
    }, Symbol('4')];
    
    // deepClone copy by refence function and Symbol
    console.log(lodashClonedeep(arrOfFunction));
    // JSON replace function with null and function in object with undefined
    console.log(JSON.parse(JSON.stringify(arrOfFunction)));
    
    // function and symbol are copied by reference in deepClone
    console.log(lodashClonedeep(arrOfFunction)[0] === lodashClonedeep(arrOfFunction)[0]);
    console.log(lodashClonedeep(arrOfFunction)[2] === lodashClonedeep(arrOfFunction)[2]);
    


    재귀 사용



    Tareq Al-Zubaidi : 이 문제에 대한 또 다른 간단하고 성능이 뛰어난 솔루션이 있습니다. 나는 이것을 해결하기 위해 재귀를 사용할 것입니다.

    const clone = (items) => items.map(item => Array.isArray(item) ? clone(item) : item);
    


    비교 테스트 참조here


    자원


  • MDN Web Docs - JSON.stringify
  • MDN Web Docs - JSON.parse
  • Lodash: cloneDeep
  • Stack Overflow: How do you clone an Array of Objects in Javascript?
  • How to differentiate between deep and shallow copies in JavaScript
  • JS: Clone, Deep Copy Object/Array
  • JavaScript Deep copy for array and object
  • Gist: Primitive Types & Reference Types in JavaScript
  • Explaining Value vs. Reference in Javascript
  • Understanding Deep and Shallow Copy in Javascript



  • 읽어주셔서 감사합니다 ❤
    안녕하세요! | | Facebook | Medium | Blog

    좋은 웹페이지 즐겨찾기