[javascript] 값으로 배열 복사

JavaScript의 배열을 다른 배열로 복사하는 경우 :

var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d');  //Now, arr1 = ['a','b','c','d']

새로운 독립형 배열이 아닌와 arr2동일한 배열 을 참조 한다는 것을 깨달았습니다 arr1. 배열을 복사하여 두 개의 독립적 인 배열을 얻으려면 어떻게해야합니까?



답변

이것을 사용하십시오 :

var newArray = oldArray.slice();

기본적으로이 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 () {}];

딥 카피 기술은 3 가지 어레이 유형에 따라 다릅니다.

배열의 요소 유형에 따라 다양한 기술을 사용하여 딥 카피 할 수 있습니다.

요소 유형별 Javascript 딥 카피 기술

  • 리터럴 값 (타입 1)의 배열 , , 및 기술은 단지 리터럴 값 (부울, 숫자 및 문자열) 깊은 복사 어레이에 사용될 수있다; Spread 연산자 가 최고의 성능을 발휘하는 곳 ( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ).
    [...myArray]myArray.splice(0)myArray.slice()myArray.concat()[...myArray]

  • 리터럴 값 (type1) 및 리터럴 구조 (type2)
    배열JSON.parse(JSON.stringify(myArray))기술을 사용하여 리터럴 값 (부울, 숫자, 문자열) 및 리터럴 구조 (배열, 객체)를 딥 카피 할 수 있지만 프로토 타입 객체는 사용할 수 없습니다.

  • 모든 배열 (type1, type2, type3)
    jQuery $.extend(myArray)기술을 사용하여 모든 배열 유형을 딥 카피 할 수 있습니다. UnderscoreLo-dash 와 같은 라이브러리는 jQuery 와 유사한 딥 카피 기능을 제공하지만 $.extend()성능은 떨어집니다. 놀랍게도 http://jsperf.com/js-deep-copy/15 기술 $.extend()보다 성능이 우수합니다 .
    jQuery와 같은 타사 라이브러리를 사용하지 않는 개발자의 경우 다음과 같은 사용자 정의 기능을 사용할 수 있습니다. $ .extend보다 성능이 높고 모든 어레이를 딥 카피합니다.JSON.parse(JSON.stringify(myArray))

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. 따라서이 경우 배열 이 실제로 복사 되더라도 배열 참조로 복사되는 것처럼 보입니다 .


답변

의 대안 sliceconcat2 가지 방법으로 사용할 수 있습니다. 의도 된 동작이 매우 명확하기 때문에 이들 중 첫 번째가 더 읽기 쉽습니다.

var array2 = [].concat(array1);

두 번째 방법은 다음과 같습니다.

var array2 = array1.concat();

Cohen (의견에서)은이 후자의 방법 이 더 나은 성능을 가지고 있다고 지적했다 .

이것이 작동하는 concat방법은 메소드가 호출되는 객체의 요소와 인수로 전달 된 배열의 요소로 구성된 새 배열을 작성하는 것입니다. 따라서 인수가 전달되지 않으면 단순히 배열을 복사합니다.

Lee Penkman은 또한 의견에서 기회 array1undefined있으면 다음과 같이 빈 배열을 반환 할 수 있다고 지적 합니다.

var array2 = [].concat(array1 || []);

또는 두 번째 방법의 경우 :

var array2 = (array1 || []).concat();

다음과 slice같이 할 수도 있습니다 var array2 = (array1 || []).slice();.


답변

이것은 많은 접근법을 시도한 후에 내가 한 일입니다.

var newArray = JSON.parse(JSON.stringify(orgArray));

이렇게하면 첫 번째 사본과 관련이없는 새 사본이 생성됩니다 (얕은 사본이 아님).

또한 이것은 분명히 이벤트와 함수를 복제하지는 않지만 한 줄로 할 수있는 좋은 방법이며 모든 종류의 객체 (배열, 문자열, 숫자, 객체 …)에 사용할 수 있습니다


답변

언급 된 메소드 중 일부는 숫자 또는 문자열과 같은 간단한 데이터 유형으로 작업 할 때 잘 작동하지만 배열에 다른 오브젝트가 포함되어 있으면 이러한 메소드가 실패합니다. 한 배열에서 다른 배열로 객체를 전달하려고하면 객체가 아니라 참조로 전달됩니다.

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()

작동합니다.