JavaScript의 배열을 다른 배열로 복사할 때:
var arr1 = ['a','b','c']; var arr2 = arr1; arr2.push('d'); //Now, arr1 = ['a','b','c','d']
arr2
가 새로운 독립 배열이 아니라 arr1
과 동일한 배열을 참조한다는 것을 깨달았습니다. 두 개의 독립적인 배열을 얻기 위해 배열을 복사하려면 어떻게 해야 합니까?
질문자 :Dan
JavaScript의 배열을 다른 배열로 복사할 때:
var arr1 = ['a','b','c']; var arr2 = arr1; arr2.push('d'); //Now, arr1 = ['a','b','c','d']
arr2
가 새로운 독립 배열이 아니라 arr1
과 동일한 배열을 참조한다는 것을 깨달았습니다. 두 개의 독립적인 배열을 얻기 위해 배열을 복사하려면 어떻게 해야 합니까?
이것을 사용하십시오:
let oldArray = [1, 2, 3, 4, 5]; let newArray = oldArray.slice(); console.log({newArray});
기본적으로 slice()
작업은 배열을 복제하고 새 배열에 대한 참조를 반환합니다.
참조, 문자열 및 숫자(실제 개체가 아님)의 경우 slice()
는 개체 참조를 새 배열에 복사합니다. 원래 배열과 새 배열은 모두 동일한 개체를 참조합니다. 참조된 객체가 변경되면 변경 사항이 새 배열과 원래 배열 모두에 표시됩니다.
문자열 및 숫자와 같은 기본 요소는 변경할 수 없으므로 문자열 또는 숫자를 변경할 수 없습니다.
Javascript에서 심층 복사 기술은 배열의 요소에 따라 다릅니다. 거기에서 시작합시다.
요소는 리터럴 값, 리터럴 구조 또는 프로토타입일 수 있습니다.
// Literal values (type1) const booleanLiteral = true; const numberLiteral = 1; const stringLiteral = 'true'; // Literal structures (type2) const arrayLiteral = []; const objectLiteral = {}; // Prototypes (type3) const booleanPrototype = new Bool(true); const numberPrototype = new Number(1); const stringPrototype = new String('true'); const arrayPrototype = new Array(); const objectPrototype = new Object(); // or `new function () {}`
이러한 요소에서 세 가지 유형의 배열을 만들 수 있습니다.
// 1) Array of literal-values (boolean, number, string) const type1 = [true, 1, "true"]; // 2) Array of literal-structures (array, object) const type2 = [[], {}]; // 3) Array of prototype-objects (function) const type3 = [function () {}, function () {}];
배열의 요소 유형에 따라 다양한 기술을 사용하여 깊은 복사를 수행할 수 있습니다.
리터럴 값 배열(type1)
[...myArray]
, myArray.splice(0)
, myArray.slice()
및 myArray.concat()
기술은 리터럴 값(부울, 숫자 및 문자열)만 있는 배열을 딥 복사하는 데 사용할 수 있습니다. 여기서 Spread 연산자 [...myArray]
가 최고의 성능을 보입니다( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ).
리터럴 값(type1) 및 리터럴 구조(type2)의 배열
JSON.parse(JSON.stringify(myArray))
기술은 리터럴 값(부울, 숫자, 문자열) 및 리터럴 구조(배열, 개체)를 딥 복사하는 데 사용할 수 있지만 프로토타입 개체는 사용할 수 없습니다.
모든 배열(유형1, 유형2, 유형3)
jQuery $.extend(myArray)
기술은 모든 배열 유형을 심층 복사하는 데 사용할 수 있습니다. Underscore 및 Lo-dash 와 같은 라이브러리는 jQuery $.extend()
와 유사한 심층 복사 기능을 제공하지만 성능은 더 낮습니다. 더 놀랍게도 $.extend()
JSON.parse(JSON.stringify(myArray))
기술 http://jsperf.com/js-deep-copy/15 보다 성능이 더 높습니다.
그리고 jQuery와 같은 타사 라이브러리를 꺼리는 개발자의 경우 다음 사용자 지정 함수를 사용할 수 있습니다. $.extend보다 성능이 높고 모든 어레이를 딥 복사합니다.
function copy(aObject) { if (!aObject) { return aObject; } let v; let bObject = Array.isArray(aObject) ? [] : {}; for (const k in aObject) { v = aObject[k]; bObject[k] = (typeof v === "object") ? copy(v) : v; } return bObject; }
질문
var arr1 = ['a','b','c']; var arr2 = arr1;
나는 arr2가 새로운 독립 배열이 아니라 arr1과 동일한 배열을 참조한다는 것을 깨달았습니다. 두 개의 독립적인 배열을 얻기 위해 배열을 복사하려면 어떻게 해야 합니까?
답변
arr1
은 리터럴 값(부울, 숫자 또는 문자열)의 배열이므로 위에서 설명한 모든 심층 복사 기술을 사용할 수 있습니다. 여기에서 확산 연산자 ...
가 가장 높은 성능을 발휘합니다.
// Highest performance for deep copying literal values arr2 = [...arr1]; // Any of these techniques will deep copy literal values as well, // but with lower performance. arr2 = arr1.slice(); arr2 = arr1.splice(0); arr2 = arr1.concat(); arr2 = JSON.parse(JSON.stringify(arr1)); arr2 = $.extend(true, [], arr1); // jQuery.js needed arr2 = _.extend(arr1); // Underscore.js needed arr2 = _.cloneDeep(arr1); // Lo-dash.js needed arr2 = copy(arr1); // Custom-function needed - as provided above
...
를 사용하여 배열을 복사할 수 있습니다.
const itemsCopy = [...items];
또한 기존 어레이가 일부인 새 어레이를 작성하려면 다음을 수행하십시오.
var parts = ['shoulders', 'knees']; var lyrics = ['head', ...parts, 'and', 'toes'];
배열 스프레드는 이제 모든 주요 브라우저에서 지원 되지만 이전 지원이 필요한 경우 typescript 또는 babel을 사용하고 ES5로 컴파일하십시오.
jQuery가 필요하지 않습니다... 작업 예제
var arr2 = arr1.slice()
0
에서 배열의 끝까지 배열을 복사합니다.
기본 유형(문자열, 숫자 등)에 대해 예상대로 작동하고 참조 유형에 대해 예상되는 동작을 설명하는 것도 중요합니다...
참조 유형의 배열이 있는 경우 유형이 Object
라고 가정합니다. 배열 이 복사되지만 두 배열 모두 동일한 Object
대한 참조를 포함합니다. 따라서 이 경우 배열이 실제로 복사 되더라도 배열이 참조로 복사되는 것처럼 보일 것입니다.
slice
의 대안은 두 가지 방법으로 사용할 수 있는 concat
첫 번째는 의도한 동작이 매우 명확하기 때문에 더 읽기 쉽습니다.
var array2 = [].concat(array1);
두 번째 방법은 다음과 같습니다.
var array2 = array1.concat();
Cohen(주석에서)은 이 후자의 방법 이 더 나은 성능을 가지고 있다고 지적했습니다.
이것이 작동하는 방식은 concat
메서드가 호출된 객체의 요소와 인수로 전달된 배열의 요소로 구성된 새 배열을 만드는 것입니다. 따라서 인수가 전달되지 않으면 단순히 배열을 복사합니다.
Lee Penkman은 또한 주석에서 array1
이 undefined
경우 다음과 같이 빈 배열을 반환할 수 있다고 지적합니다.
var array2 = [].concat(array1 || []);
또는 두 번째 방법의 경우:
var array2 = (array1 || []).concat();
slice
하여 이 작업을 수행할 수도 있습니다. var array2 = (array1 || []).slice();
.
이것이 내가 많은 접근 방식을 시도한 후 수행한 방법입니다.
var newArray = JSON.parse(JSON.stringify(orgArray));
이것은 첫 번째 것과 관련이 없는 새로운 깊은 복사본을 생성합니다(얕은 복사본이 아님).
또한 이것은 분명히 이벤트와 함수를 복제하지 않지만 한 줄로 할 수 있다는 장점이 있으며 모든 종류의 개체(배열, 문자열, 숫자, 개체 ...)에 사용할 수 있습니다.
개인적으로 Array.from 이 더 읽기 쉬운 솔루션이라고 생각합니다. 그건 그렇고, 브라우저 지원에주의하십시오.
// clone let x = [1, 2, 3]; let y = Array.from(x); console.log({y}); // deep clone let clone = arr => Array.from(arr, item => Array.isArray(item) ? clone(item) : item); x = [1, [], [[]]]; y = clone(x); console.log({y});
ES2015부터,
var arr2 = [...arr1];
중요한!
여기에 있는 대부분의 답변은 특정 경우에 적용 됩니다.
깊은/중첩 객체 및 소품 사용에 신경 쓰지 않는다면( ES6 ):
let clonedArray = [...array]
그러나 딥 클론을 수행하려면 다음을 대신 사용하십시오.
let cloneArray = JSON.parse(JSON.stringify(array))
*
* stringify를 사용하는 동안 함수는 보존(직렬화)되지 않으며, 함수 없이는 결과를 얻을 수 있습니다.
lodash 사용자의 경우:
let clonedArray = _.clone(array)
문서
그리고
let clonedArray = _.cloneDeep(array)
문서
언급된 방법 중 일부는 숫자 또는 문자열과 같은 간단한 데이터 유형으로 작업할 때 잘 작동하지만 배열에 다른 개체가 포함되어 있으면 이러한 방법이 실패합니다. 한 배열에서 다른 배열로 객체를 전달하려고 하면 객체가 아니라 참조로 전달됩니다.
JavaScript 파일에 다음 코드를 추가합니다.
Object.prototype.clone = function() { var newObj = (this instanceof Array) ? [] : {}; for (i in this) { if (i == 'clone') continue; if (this[i] && typeof this[i] == "object") { newObj[i] = this[i].clone(); } else newObj[i] = this[i] } return newObj; };
그리고 단순히 사용
var arr1 = ['val_1','val_2','val_3']; var arr2 = arr1.clone()
그것은 작동합니다.
ECMAScript 6 환경에 있다면 Spread Operator 를 사용하여 다음과 같이 할 수 있습니다.
var arr1 = ['a','b','c']; var arr2 = [...arr1]; //copy arr1 arr2.push('d'); console.log(arr1) console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>
그렇다면 이 arr을 어떻게 복사할까요?
let arr = [1,2,3,4,5];
let arrCopy = [...arr];
let arrCopy = arr.slice(); let arrCopy = [].concat(arr);
개체/배열과 같은 복합 값에서 한 변수를 다른 변수로 전달하면 다르게 작동합니다. copand 값에 부호 연산자를 사용하여 객체에 대한 참조를 전달합니다. 이것이 arr 요소를 제거/추가할 때 두 배열의 값이 모두 변경되는 이유입니다.
arrCopy[1] = 'adding new value this way will unreference';
변수에 새 값을 할당하면 참조 자체가 변경되며 원래 개체/배열에는 영향을 주지 않습니다.
array.slice() 의 솔루션에 추가; 다차원 배열 하위 배열이 있는 경우 참조로 복사됩니다. 당신이 할 수있는 일은 각 하위 배열을 개별적으로 반복하고 슬라이스()하는 것입니다.
var arr = [[1,1,1],[2,2,2],[3,3,3]]; var arr2 = arr.slice(); arr2[0][1] = 55; console.log(arr2[0][1]); console.log(arr[0][1]); function arrCpy(arrSrc, arrDis){ for(elm in arrSrc){ arrDis.push(arrSrc[elm].slice()); } } var arr3=[]; arrCpy(arr,arr3); arr3[1][1] = 77; console.log(arr3[1][1]); console.log(arr[1][1]);
동일한 것이 객체 배열에 적용되며 참조로 복사되므로 수동으로 복사해야 합니다.
let a = [1,2,3];
이제 다음 중 하나를 수행하여 배열의 복사본을 만들 수 있습니다.
let b = Array.from(a);
또는
let b = [...a];
또는
let b = new Array(...a);
또는
let b = a.slice();
또는
let b = a.map(e => e);
이제 내가 변경하면,
a.push(5);
그러면 a는 [1,2,3,5]이지만 b는 참조가 다르기 때문에 여전히 [1,2,3]입니다.
그러나 나는 위의 모든 방법에서 Array.from 이 더 좋으며 주로 배열을 복사하도록 만들어졌다고 생각합니다.
나는 개인적으로 이 방법을 선호합니다:
JSON.parse(JSON.stringify( originalObject ));
우리가 자바스크립트에서 알듯이 배열 과 객체 는 참조에 의한 것이지만, 나중에 원래 배열을 변경하지 않고 배열을 복사할 수 있는 방법은 무엇입니까?
다음은 몇 가지 방법입니다.
코드에 다음 배열이 있다고 상상해보십시오.
var arr = [1, 2, 3, 4, 5];
1) 다음과 같이 함수에서 배열을 반복하고 새 배열을 반환합니다.
function newArr(arr) { var i=0, res = []; while(i<arr.length){ res.push(arr[i]); i++; } return res; }
2) 슬라이스 방법을 사용하여 슬라이스는 배열의 일부를 슬라이스하는 것입니다. 원본을 건드리지 않고 어레이의 일부를 슬라이스합니다. 슬라이스에서 어레이의 시작과 끝을 지정하지 않으면 전체를 슬라이스합니다 배열을 만들고 기본적으로 배열의 전체 복사본을 만들어 다음과 같이 쉽게 말할 수 있습니다.
var arr2 = arr.slice(); // make a copy of the original array
3) 또한 접촉 방법, 이것은 두 배열을 병합하기 위한 것이지만 배열 중 하나를 지정할 수 있으며 기본적으로 새 접촉 배열의 값 복사본을 만들 수 있습니다.
var arr2 = arr.concat();
4) 또한 stringify 및 parse 메소드는 권장하지 않지만 Array 및 Objects를 복사하는 쉬운 방법이 될 수 있습니다.
var arr2 = JSON.parse(JSON.stringify(arr));
5) Array.from 메소드, 이것은 널리 지원되지 않습니다. 사용하기 전에 다른 브라우저에서 지원을 확인하십시오.
const arr2 = Array.from(arr);
6) ECMA6 방식도 완벽하게 지원되지는 않지만 변환하려는 경우 babelJs가 도움이 될 수 있습니다.
const arr2 = [...arr];
댄, 멋진 트릭을 사용할 필요가 없습니다. 이 작업을 수행하여 ar1의 복사본을 만들기만 하면 됩니다.
var arr1 = ['a','b','c']; var arr2 = []; var arr2 = new Array(arr1); arr2.push('d'); // Now, arr2 = [['a','b','c'],'d'] console.log('arr1:'); console.log(arr1); console.log('arr2:'); console.log(arr2); // Following did the trick: var arr3 = [...arr1]; arr3.push('d'); // Now, arr3 = ['a','b','c','d']; console.log('arr3:'); console.log(arr3);
이제 arr1
과 arr2
는 별도의 스택에 저장된 두 개의 서로 다른 배열 변수입니다. jsfiddle 에서 이것을 확인하십시오 .
제 경우에는 어레이가 손상되지 않은 상태로 유지되도록 해야 했기 때문에 다음과 같이 저에게 효과적이었습니다.
// Empty array arr1.length = 0; // Add items from source array to target array for (var i = 0; i < arr2.length; i++) { arr1.push(arr2[i]); }
다차원 배열/객체의 복사본 만들기:
function deepCopy(obj) { if (Object.prototype.toString.call(obj) === '[object Array]') { var out = [], i = 0, len = obj.length; for ( ; i < len; i++ ) { out[i] = arguments.callee(obj[i]); } return out; } if (typeof obj === 'object') { var out = {}, i; for ( i in obj ) { out[i] = arguments.callee(obj[i]); } return out; } return obj; }
이 기능에 대해 James Padolsey에게 감사드립니다.
출처: 여기
배열에 int, char 또는 string 등과 같은 기본 데이터 유형의 요소가 포함되어 있으면 .slice() 또는 .map() 또는 Spread operator()와 같은 원래 배열의 복사본을 반환하는 메서드 중 하나를 사용할 수 있습니다. ES6 덕분에).
new_array = old_array.slice()
또는
new_array = old_array.map((elem) => elem)
또는
const new_array = new Array(...old_array);
그러나 배열에 개체(또는 배열) 또는 더 많은 중첩 개체 와 같은 복잡한 요소 가 포함되어 있으면 최상위 수준에서 마지막 수준까지 모든 요소의 복사본을 만들고 있는지 확인해야 합니다. 개체가 사용되며 이는 new_array의 object_elements 값을 변경해도 여전히 old_array에 영향을 미친다는 것을 의미합니다. old_array 의 DEEP COPY 를 만드는 것으로 각 수준에서 이 복사 방법을 호출할 수 있습니다.
Deep Copy의 경우 데이터 유형에 따라 각 수준에서 기본 데이터 유형에 대해 위에서 언급한 방법을 사용하거나 많은 작업을 수행하지 않고 Deep Copy를 만들기 위해 비용이 많이 드는 이 방법(아래 언급)을 사용할 수 있습니다.
var new_array = JSON.parse(JSON.stringify(old_array));
요구 사항에 따라 사용할 수 있는 다른 방법이 많이 있습니다. 나는 값 으로 배열을 다른 배열에 복사하려고 할 때 어떤 일이 발생하는지에 대한 일반적인 아이디어를 제공하기 위해 그 중 일부만 언급했습니다.
개체나 배열의 새 복사본을 만들려면 개체의 속성이나 배열의 요소를 명시적으로 복사해야 합니다. 예를 들면 다음과 같습니다.
var arr1 = ['a','b','c']; var arr2 = []; for (var i=0; i < arr1.length; i++) { arr2[i] = arr1[i]; }
변경할 수 없는 기본 값 및 변경 가능한 개체 참조에 대한 자세한 내용은 Google에서 검색할 수 있습니다.
=
)를 사용하여 배열을 복사하려는 경우 복사본을 생성하지 않고 배열에 대한 포인터/참조만 복사합니다. 예를 들어:
const oldArr = [1,2,3]; const newArr = oldArr; // now oldArr points to the same place in memory console.log(oldArr === newArr); // Points to the same place in memory thus is true const copy = [1,2,3]; console.log(copy === newArr); // Doesn't point to the same place in memory and thus is false
종종 데이터를 변환할 때 초기 데이터 구조(예: Array)를 그대로 유지하기를 원합니다. 배열의 정확한 복사본을 만들어 이를 수행하므로 초기 배열은 그대로 유지하면서 변형될 수 있습니다.
const oldArr = [1,2,3]; // Uses the spread operator to spread out old values into the new array literal const newArr1 = [...oldArr]; // Slice with no arguments returns the newly copied Array const newArr2 = oldArr.slice(); // Map applies the callback to every element in the array and returns a new array const newArr3 = oldArr.map((el) => el); // Concat is used to merge arrays and returns a new array. Concat with no args copies an array const newArr4 = oldArr.concat(); // Object.assign can be used to transfer all the properties into a new array literal const newArr5 = Object.assign([], oldArr); // Creating via the Array constructor using the new keyword const newArr6 = new Array(...oldArr); // For loop function clone(base) { const newArray = []; for(let i= 0; i < base.length; i++) { newArray[i] = base[i]; } return newArray; } const newArr7 = clone(oldArr); console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);
배열이 중첩되면 값이 참조로 복사됩니다. 이것이 어떻게 문제로 이어질 수 있는지에 대한 예는 다음과 같습니다.
let arr1 = [1,2,[1,2,3]] let arr2 = [...arr1]; arr2[2][0] = 5; // we change arr2 console.log(arr1); // arr1 is also changed because the array inside arr1 was copied by reference
따라서 복사하려는 배열 내부에 객체나 배열이 있는 경우 이러한 방법을 사용하지 마십시오. 즉, 프리미티브 배열에서만 이 메소드를 사용하십시오.
자바스크립트 배열을 딥클론하려면 다음과 같이 JSON.stringify
JSON.parse
를 사용하세요.
let arr1 = [1,2,[1,2,3]] let arr2 = JSON.parse(JSON.stringify(arr1)) ; arr2[2][0] = 5; console.log(arr1); // now I'm not modified because I'm a deep clone
따라서 최적의 성능을 위해 어느 것을 선택합니까? 가장 장황한 방법인 for
루프가 가장 높은 성능을 보입니다. CPU를 많이 사용하는 복사(대형/다수 어레이) for
루프를 사용합니다.
그 후 .slice()
메서드도 괜찮은 성능을 가지고 있으며 프로그래머가 구현하기에도 덜 장황하고 더 쉽습니다. CPU를 많이 사용하지 않는 배열의 일상적인 복사에 .slice()
를 사용하는 것이 좋습니다. 또한 딥 클론이 필요하지 않고 성능이 문제인 경우 JSON.parse(JSON.stringify(arr))
(많은 오버헤드)를 사용하지 마십시오.
jQuery 딥 카피를 사용하면 다음과 같이 만들 수 있습니다.
var arr2 = $.extend(true, [], arr1);
ES6 스프레드 연산자를 사용하여 배열을 복사할 수도 있습니다.
var arr=[2,3,4,5]; var copyArr=[...arr];
다음은 복사하는 몇 가지 방법입니다.
const array = [1,2,3,4]; const arrayCopy1 = Object.values(array); const arrayCopy2 = Object.assign([], array); const arrayCopy3 = array.map(i => i); const arrayCopy4 = Array.of(...array );
객체를 포함하는 ES6 배열의 경우
cloneArray(arr) { return arr.map(x => ({ ...x })); }
빠른 예:
var arr1 = ['a','b','c']; // arr1 and arr2 are independent and primitive elements are stored in // different places in the memory var arr2 = arr1.slice(); arr2.push('d'); console.log(arr1); // [ 'a', 'b', 'c' ] console.log(arr2); // [ 'a', 'b', 'c', 'd' ]
var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]]; // arr1 and arr2 are independent and reference's/addresses are stored in different // places in the memory. But those reference's/addresses points to some common place // in the memory. var arr2 = arr1.slice(); arr2.pop(); // OK - don't affect arr1 bcos only the address in the arr2 is // deleted not the data pointed by that address arr2[0].x = 'z'; // not OK - affect arr1 bcos changes made in the common area // pointed by the addresses in both arr1 and arr2 arr2[1][0] = 9; // not OK - same above reason console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ] console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]
var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]]; arr2 = JSON.parse(JSON.stringify(arr1)); arr2.pop(); // OK - don't affect arr1 arr2[0].x = 'z'; // OK - don't affect arr1 arr2[1][0] = 9; // OK - don't affect arr1 console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ] console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]
다음은 변형입니다.
var arr1=['a', 'b', 'c']; var arr2=eval(arr1.toSource()); arr2.push('d'); console.log('arr1: '+arr1+'\narr2: '+arr2); /* * arr1: a,b,c * arr2: a,b,c,d */
새로 도입된 Array.from
이 있지만 불행히도 이 글을 쓰는 시점에서는 최신 Firefox 버전(32 이상)에서만 지원됩니다. 다음과 같이 간단하게 사용할 수 있습니다.
var arr1 = [1, 2, 3]; console.log(Array.from(arr1)); // Logs: [1, 2, 3]
참조: 여기
또는 Array.prototype.map
식별 기능과 함께 사용할 수 있습니다.
function identity(param) { return param; } var arr1 = [1, 2, 3], clone = arr1.map(identity);
참조: 여기
출처 : http:www.stackoverflow.com/questions/7486085/copy-array-by-value
C++에서 extern "C"의 효과는 무엇입니까? (0) | 2021.12.26 |
---|---|
PostgreSQL 명령줄 유틸리티를 종료하는 방법: psql (0) | 2021.12.26 |
원자 속성과 비 원자 속성의 차이점은 무엇입니까? (0) | 2021.12.26 |
Git 커밋의 변경 사항을 어떻게 볼 수 있습니까? (0) | 2021.12.26 |
Bash에 변수가 설정되어 있는지 확인하는 방법은 무엇입니까? (0) | 2021.12.26 |