이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

게시글

강좌25 - JavaScript - 2년 전 등록 / 8달 전 수정

객체의 복사

조회수:
0
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

안녕하세요, 이번 시간에는 객체의 복사에 대해서 알아보겠습니다.

일반 문자열, 숫자, 불린 같은 경우는

var string = 'hello';
var copy = string;
console.log(copy); // 'hello'

하면 바로 복사가 되는데요. 객체(배열, 일반 객체, 함수)도 마찬가지이긴 합니다만, 복사된 값을 조작할 때 차이가 있습니다. 다시 위의 예를 보면

var string = 'hello';
var copy = string;
console.log(copy); // 'hello'
copy = 'hi';
console.log(string); // 'hello'

이번엔 copy 값을 hi로 바꿔봤습니다. 기존 string 값은 변화가 없겠죠? copy에 값만 복사해 줬을 뿐 더이상 연관이 없으니까요. 객체의 경우를 볼까요?

var array = ['a', 'b', 'c'];
var shallow = array;
shallow[0] = 'd';
console.log(array); // ['d', 'b', 'c']

shallow 변수에 array 배열을 대입했는데요. shallow의 첫 번째 항목을 변경했더니 array의 첫 번째 항목도 같이 변경되었습니다. 이상하죠? 이게 객체의 특징입니다. 문자열, 숫자, 불린을 제외한 객체는 다른 변수에 대입할 때 을 복사하는 게 아니라 참조(메모리의 주소)를 복사합니다.

변수는 모두 메모리에 저장됩니다. 그리고 대입을 하면 변수의 이름은 저장된 메모리의 주소를 가리키게 됩니다. 메모리 어딘가에 ['a', 'b', 'c']를 저장한 게 있다면 그것을 array와 shallow 변수 두 개가 가리키고 있는겁니다. 값은 하나인데 변수는 여러 개일 수 있는거죠. 이걸 shallow copy(얕은 복사)라고 부릅니다. 따라서 shallow 변수가 바뀌면 array 값도 같이 바뀝니다. 이걸 방지하려면 메모리에 ['a', 'b', 'c'] 두 개를 만들어서 따로따로 운영되게 만들어주어야 합니다.

var array = ['a', 'b', 'c'];
var deep = Array.prototype.slice.call(array);
deep[0] = 'd';
console.log(array); // ['a', 'b', 'c']

좀 독특한 방법인데요. 지난 시간에 배운 call 함수를 사용했습니다. deep copy(깊은 복사)라고 하며, 이제는 deep 변수가 바뀌어도 array 변수에 영향을 미치지 않습니다. slice함수는 배열을 자르는 함수인데 어떻게 복사가 되냐고요? array.slice(0)이라고 생각하면 됩니다. array를 자르는 데 0개만큼 자르니까 결국 그대로 반환하는거죠.

위의 경우는 Array.prototype.slice.call(array) 대신 array.slice(0)을 해도 되지만, arguments 같은 것(유사배열이라서 배열의 메소드를 사용할 수 없습니다)을 복사할 때를 생각하면 Array.prototype.slice.call로 통일하는 게 좋습니다.

일반 객체를 복사하는 것에도 shallow copy와 deep copy가 있습니다. shallow는 그냥 대입만 해주면 되니까 deep copy하는 방법을를 살펴보겠습니다. 상속이 없는 일반 객체만 해당됩니다.

function copyObj(obj) {
  var copy = {};
  for (var attr in obj) {
    if (obj.hasOwnProperty(attr)) {
      copy[attr] = copyObj(obj[attr]);
    }
  }
  return copy;
}
var obj = { a: 1, b: 2 };
var obj2 = copyObj(obj);
obj2.a = 3;
console.log(obj.a); // 1

copyObj이란 함수를 새로 만들었습니다. 결과를 보면 obj과 obj2가 따로 놀죠. 여기서 for~inhasOwnProperty를 처음 보실 겁니다. for ~ in 은 obj안의 키를 순서대로 반복합니다. (주의할 점은 키가 숫자면 순서대로 반복되지 않는다는 겁니다. 숫자로된 키가 없을 때 사용하세요) 문제는 prototype에 있는 상속된 객체의 속성도 반복되기 때문에 obj.hasOwnProperty(keyName)메소드로 상속되지 않은 자기의 속성만 반복되도록 제한하는 겁니다. hasOwnProperty 부분을 빼고 복사하면, 왜 그 부분이 필요한지 이유를 알 수 있을 겁니다.

함수는 복사할 때 bind를 하면 됩니다. this를 기존 함수와 같게 하면 똑같게 함수가 복사됩니다.

var func = function () {
  alert('hi');
};
func2 = func.bind(this);
func2(); // 'hi'

이상으로 객체의 복사편을 마치겠습니다. 다음 시간에는 디자인 패턴에 대해서 알아보겠습니다!

투표로 게시글에 관해 피드백을 해주시면 많은 도움이 됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright © 2016- 무단 전재 및 재배포 금지

댓글

3개의 댓글이 있습니다.
한 달 전
얕은복사와 깊은복사는 이해했는데요..

복사와 복제는 같은 말인가요???
한 달 전
비슷한 뜻일거라 생각합니다
5달 전
잘봤습니다. 한가지 질문이 있는데 혹시 for in문 안의 obj키가 숫자면은 어떻게 해야하나요..? 키를 다 string타입으로 바꿔서 해야하나요?
5달 전
일단 쉬운 방법은 없어보입니다. 단순히 문자열 '3', '2', '1' 이렇게 바꿔도 순서는 항상 1, 2, 3으로 나옵니다. 사실 객체의 키가 1,2,3이라면 처음부터 배열로 하는 게 맞습니다.
8달 전
for in 문이 순서 보장되지 않는걸로 알고있는데 "for ~ in 은 obj안의 키를 순서대로 반복합니다." 이부분에서 순서대로 반복합니다 라는 내용이 오해의 소지가 있는듯 합니다~!
8달 전
for in 문은 속성의 키가 숫자가 아닌 이상은 순서를 보장하긴 합니다. 이 부분 살짝 수정해보겠습니다.