데이터 타입의 종류
자바스크립트의 데이터 타입에는 크게 2가지가 있습니다.
- 기본형(원시형, primitive type) : 숫자, 문자열, 불리언, null, undefined, es6 추가(심볼) 등..
- 참조형(reference type) : 객체, 배열, 함수, 날짜, 정규식, es6 추가(Map, WeakMap, Set, WeakSet) 등..
그렇다면 어떤 기준으로 기본형과 참조형을 구분하는 걸까요 ?
일반적으로 기본형은 할당이나 연산시 복제되고 참조형은 참조된다고 알려져 있습니다. 엄밀히 말하면 둘 모두 복제를 하긴 합니다. 다만 이 둘의 차이점은,
- 기본형은 값이 담긴 주소값을 바로 복제하하고
- 참조형은 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제한다는 점이 다릅니다.
기본형은 불변성(immutability)을 띕니다. 기본형인 숫자 10을 담은 변수 a에 다시 숫자 15를 담으면 a의 값은 문제 없이 15로 변하는데 '변하지 않는다'는 게 어떤 의미 일까요 ?
불변성을 잘 이해하려면 개략적으로나마 메모리와 데이터에 대한 지식이 필요하고, 나아가 '식별자'와 '변수'의 개념을 구분할 수 있어야 합니다. 지금부터는 배경지식을 얇게 깐 다음, 메모리 영역에서 자바스크립트의 데이터가 처리되는 과정을 살펴보겠습니다.
데이터 타입에 관한 배경지식
1. 메모리와 데이터
컴퓨터는 모든 데이터를 0또는 1로 바꾸어 관리합니다. 0또는 1만 표현할 수 있는 하나의 메모리 조각을 비트(bit)라고 합닌다. 메모리는 매우 많은 비트들로 구성되어 있는데 각 비트는 고유한 식별자(unique identifier)를 통해 위치를 확인할 수 있습니다. 8개의 비트를 묶어 바티으(byte)라고 하며 비트마다 0또는 1의 두 가지 값을 표현할 수 있으므로 1바이트는 총 256(2^8)개의 값을 표현할 수 있습니다.
C/C++, 자바 등의 정적 타입 언어는 메모리의 낭비를 최소화 하기 위해 데이터 타입별로 할당할 메모리 영역을 2바이트, 4바이트 등으로 나누어 정해놓았습니다. 예를 들어 2바이트 크기의 정수형 타입(short)는 0을 포함해 -32768 ~ +32768의 숫자만 허용합니다. 그보다 더 큰 숫자에 대해서는 사용자가 직접 형변환을 해야하며 이는 꽤나 번거로운 작업입니다. 하지만 메모리 용량이 부족했던 시절에는 불가피한 선택이었습니다.
한편 메모리 용량이 과거보다 월등히 커진 상황에서 등장한 자바스크립트는 상대적으로 메모리 관리에 대한 압박에서 자유로워졌습니다. 숫자의 경우 정수형인지 부동소수형인지를 구분하지 않고 64비트를 확보합니다.
앞서 각 비트는 고유한 식별자를 지닌다고 했습니다. 바이트 역시 시작하는 비트의 식별자로 위치를 파악할 수 있을 것입니다. 모든 데이터는 바이트 단위의 식별자, 더 정확하게는 메모리 주소값을 통해 서로 구분하고 연결할 수 있습니다.
2. 식별자와 변수
보통 변수(variable)와 식별자(identifier)를 혼용하는 경우가 많습니다.
변수는 '변경 가능한 데이터가 담길 수 있는 공간 또는 그릇' 입니다. 수학 용어를 차용했기 때문에 숫자를 의미하는 '수'가 붙었을 뿐, 값이 반드시 '숫자'여야 하는 것은 아닙니다. 영어 단어 variable은 원래 '변할 수 있다' 라는 형용사지만 컴퓨터 용어로 쓸 때는 '변할 수 있는 무언가'라는 명사로 확장시켰습니다. 여기서 무언가란 데이터를 의미하며 숫자, 문자열, 객체 배열 모두 데이터 입니다.
식별자는 어떤 데이터를 식별하는 데 사용하는 이름, 즉 변수명 입니다.
변수 선언과 데이터 할당
1. 변수 선언
변수 선언하는 방법은 모두 알고 있을 것입니다. 하지만 여기서는 방법이 아닌 동작원리를 알아보고자 합니다.
1 var a;
위의 코드를 풀어쓰면 '변할 수 있는 데이터를 만든다. 이 데이터의 식별자는 a로 한다' 가 됩니다. 변할 수 있는 데이터이니 선언할 때는 undefined이더라도 나중에 다른 값으로 바꾸면 됩니다.
이를 바탕으로 컴퓨터가 위의 명령을 받아 메모리 영역에서 어떤 작업을 수행하는지 한번 보겠습니다.
var a;에서 컴퓨터는 메모리에서 비어있는 공간 하나를 확보합니다. 예제에서는 임의로 1002를 지정하였습니다. 이 공간의 이름(식별자)를 'a'라고 하며 여기까지가 변수 선언 과정입니다. 이후에 사용자가 a에 접근하고자 하면 컴퓨터는 메모리에서 a라는 이름을 가진 수로를 검색해 해당 공간에 담긴 데이터를 반환할 것입니다.
2. 데이터 할당
1 var a; // 변수 a 선언
2 a = 'abc'; // 변수 a에 데이터 할당
3
4 var a = 'abc; // 변수 선언과 할당을 한 문장으로 표현
1,2번째 줄과 같이 두 문장으로 나누어 명령하든 4번째 줄과 같이 한문장으로 명령하든 자바스크립트 엔진은 결국 같은 동작을 수행합니다. 메모리에서 비어있는 공간을 확보하고 그 공간의 이름을 설정하는 선언 과정은 앞서 살펴본 것과 같습니다. 이어서 할당 과정은 a라는 이름을 가진 주소를 검색해서 그곳에서 문자열 'abc'를 할당하면 될 것 같아 보입니다.
그런데 실제로는 해당 위치에 문자열 'abc'를 직접 저장하지 않습니다. 데이터를 저장하기 위한 별도의 메모리 공간을 다시 확보해서 문자열 'abc'를 저장하고, 그 주소를 변수 영역에서 저장하는 식으로 이뤄집니다. 이제부터는 데이터의 성질에 따라 '변수 영역', '데이터 영역'으로 구분해서 설명하겠습니다.
- 변수 영역에서 빈 공간(@1002)를 확보합니다.
- 학보환 공간의 식별자를 a로 지정합니다.
- 데이터 영역의 빈 공간(@5004)에 문자열 'abc'를 저장합니다.
- 변수 영역에서는 a라는 식별자를 검색합니다(@1002)
- 앞서 저장한 문자열의 주소(@5004)를 @1002에 대입합니다.
이런 과정을 거치는 이유은,
이는 데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 더욱 효율적으로 관리하기 위함입니다.
앞서 자바스크립트는 숫자형 데이터에 대해 64비트의 공간을 확보한다고 했습니다. 반면 문자열을 특별히 정해진 규격이 없습니다. 한 글자마다 영어는 1바이트, 한글은 2바이트 등으로 각각 필요한 메모리 용량이 가변적이며 전체 글자 수 역시 가변적이기 때문입니다.
만약 미리 확보한 공간 내에서만 데이터 변환을 할 수 있다면 변환한 데이터를 다시 저장하기 위해서는 '확보된 공간을 변환된 데이터 크기에 맞게 늘리는 작업'이 선행되야 할 것입니다. 결국 효율적으로 문자열 데이터의 변환을 처리하려면 변수와 데이터를 별도의 공간에 나누어 저장하는 것이 최적입니다.
문자열 'abc'의 마지막에 'def'를 추가하라고 하면 컴퓨터는 앞서 'abc'가 저장된 공간에 'abcdef'를 할당하는 대신 'abcdef'라는 문자열을 새로 만들어 별도의 공간에 저장하고 그 주소를 변수 공간에 연결하면 됩니다.
기본형 데이터와 참조형 데이터
1. 불변값
변수(variable)와 상수(constant)를 구분하는 성질은 '변경 가능성' 입니다. 바꿀 수 있으면 변수, 바꿀 수 없으면 상수 입니다. 불변값과 상수를 같은 개념으로 오해하기 쉬운데 이 둘은 명확히 구분할 필요가 있습니다.
변수와 상수를 구분짓는 변경 가능성의 대상은 '변수 영역 메모리' 입니다. 한 번의 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지 여부가 관건입니다.
반면 불변성 여부를 구분할 때의 변경 가능성의 대상은 '데이터 영역 메모리' 입니다.
1 var a = 'abc';
2 a = a + 'def';
3
4 var b = 5;
5 var c = 5;
6 b = 7;
1~3번째 줄은 보면 변수 a에 'abc'를 할당 했다가 뒤에 'def'를 새로운 'abcdef'를 만들어 그 주소를 변수 a에 저장합니다. 'abc'와 'abcdef'를 완전히 별개의 데이터 입니다.
4번째 줄에서는 변수 b에 숫자 5를 할당합니다. 그러면 컴퓨터는 일단 데이터 영역에서 5를 찾고 없으면 그제서야 데이터 공간을 하나 만들어 저장하고 그 주소를 b에 저장합니다. 5번째 줄에서는 다시 같은 수인 5를 할당하려고 합니다. 컴퓨터는 데이터 영역에서 5를 찾고 4번째 줄에서 이미 만들어 놓은 값이 있으니 그 주소를 재활용 합니다.
6번째 줄에서는 변수 b의 값을 7로 바꾸고자 합니다. 그러면 기존에 저장된 5 자체를 7로 바꾸는 것이 아니라 데이터 영역에서 7을 찾아서 있으면 재활용하고 없으면 새로 만들어 b에 저장합니다. 결국 5와 7은 모두 다른 값으로 변경할 수 없습니다.
변경은 새로 만드는 동작을 통해서만 이뤄집니다. 이것이 바로 불변값의 성질입니다. 한 번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않습니다.
2. 가변값
기본형 데이터는 모두 불변값이라고 했습니다. 그렇다면 참조형 데이터는 모두 가변값일 것 같은 느낌이 듭니다. 기본적인 성질은 가변값이 경우가 많지만 설정에 따라 변경 불가능한 경우도 있고, 아예 불변값을 활용하는 방안도 있습니다.
1 var obj1 = {
2 a: 1,
3 b: 'bbb'
4};
- 컴퓨터는 우선 변수 영역의 빈 공간(@1002)를 확보하고 그 주소의 이름을 obj1로 지정합니다.
- 임의의 데이터 저장 공간(@5001)에 데이터를 저장하려고 보니 여러 개의 프로퍼티로 이뤄진 데이터 그룹입니다. 이 그룹 내 부의 프로퍼티들을 저장하기 위해 별도의 변수 영역을 마련하고 그 영역의 주소(@7001 ~ ?)를 @5001에 저장합니다.
- @7103 밑 @7104에 각각 a와 b라는 프로퍼티 이름을 지정합니다.
- 데이터 영역에서 숫자 1을 검색합니다. 검색 결과가 없으므로 임의로 @5003에 저장하고, 이 주소를 @7103에 저장합니다. 문자열 'bbb'역시 @5004에 저장하고 이 주소를 @7104에 저장합니다.
기본형 데이터와의 차이는 '객체의 변수(프로퍼티) 영역'이 별도로 존재한다는 점입니다. 그림을 자세히 보면 객체가 별도로 할애한 영역은 변수 영역일 뿐 '데이터 영역'은 기존의 메모리 공간을 그대로 활용하고 있습니다. 데이터 영역에 저장된 값은 모두 불변값입니다. 그러나 변수에는 다른 값을 얼마든지 대입할 수 있습니다. 바로 이 부분 때문에 흔히들 참조형 데이터는 불변하지 않다(가변값이다)라고 하는 것이죠.
그럼 프로퍼티에 다른값을 넣는 경우를 보겠습니다.
1 var obj1 = {
2 a: 1,
3 b: 'bbb'
4 };
5
6 obj1.a = 2;
obj1객체의 a프로퍼티에 새로운 값을 넣은 경우 데이터 영역에서 숫자 2를 검색합니다. 검색결과가 없으므로 빈 공간인 @5005에 2를 저장하고 이 주소를 @7103에 저장합니다. 변수 obj1이 바라보고 있는 주소는 @5001로 변하지 않았습니다. 즉 '새로운 객체'가 만들어진 것이 아니라 기존의 객체 내부의 값만 바뀐 것이죠.
이번에는 참조형 데잍의 프로퍼티에 다시 참조형 데이터를 할당하는 경우를 살펴 보겠습니다. 참고로 이런 경우를 일컬어 중첩 객체(nested object)라고 합니다
1 var obj = {
2 x: 3,
3 arr: [3,4,5]
4};
- 컴퓨터는 우선 변수 영역의 빈 공간(@1002)을 확보하고 그 주소의 이름을 obj로 지정합니다.
- 임의의 데이터 저장공간(@5001)에 데이터를 저장하려는데 이 데이터는 여러 개의 변수와 값들을 모아놓은 그룹(객체)입니다. 이 그룹의 각 변수(프로퍼티)들을 저장하기 위해 별도의 변수 영역을 마련하고(@7103 ~ ?) 그 영역을 @5001에 저장합니다.
- @7103에 이름 x를, @7104에 이름 arr를 지정합니다.
- 데이터 영역에서 숫자 3을 검색합니다. 없으므로 임의로 @5002에 저장하고, 이 주소를 @7103에 저장합니다.
- @7104에 저장할 값은 배열로서 역시 데이터 그룹입니다. 이 그룹 내부의 프로퍼티들을 저장하기 위해 별도의 변수 영역을 마련하고(@7104 ~ ?) 그 영역의 주소를 @7104에 저장합니다.
- 배열의 요소가 총 3개이므로 3개의 변수 공간을 확보하고 각각 인덱스를 부여합니다(0,1,2)
- 데이터 영역에서 숫자 3을 검색해서(@5002) 그 주소를 @8104에 저장합니다.
- 데이터 영역에 숫자 4가 없으므로 @5004에 저장하고, 이 주소를 @8105에 저장합니다.
- 데이터 영역에 숫자 5가 없으므로 @5005에 저장하고, 이 주소를 @8106에 저장합니다.
이제 obj.arr[1]을 검색하고자 하면 메모리에서는 다음과 같은 과정을 거칩니다.
- obj 검색 1 : obj라는 식별자를 가진 주소를 찾습니다(@1002)
- bj 검색 2 : 값이 주소이므로 그 주소로 이동합니다(@5001)
- bj 검색 3 : 값이 주소이므로 그 주소로 이동합니다(@7103 ~ ?)
- obj.arr 검색 1 : arr이라는 식별자를 가진 주소를 찾습니다(Q7104)
- obj.arr 검색 2 : 값이 주소이므로 그 주소로 이동합니다(@5003)
- obj.arr 검색 3 : 값이 주소이므로 그 주소로 이동합니다(@8104)
- obj.arr[1] 검색 1 : 인덱스 1에 해당하는 주소를 찾습니다(Q8105)
- obj.arr[1] 검색 2 : 값이 주소이므로 그 주소로 이동합니다(@5004)
- obj.arr[1] 검색 3 : 값이 숫자형 데이터이므로 4를 반환합니다.
만약 이 상태에서 다음과 같이 재할당 명령을 내리면 어떻게 될까요 ?
1 ob.arr = 'str';
어떤 데이터에 대해 자신의 주소를 참조하는 변수의 개수를 참조 카운트라고 합니다. @5003의 참조 카운트는 @7104에 @5003이 저장돼 있던 시점까지는 1이었다가 @7104에 @5006이 저장되는 순간 0이 됩니다. 참조 카운트가 0인 메모리 주소는 가비지 컬렉터의 수거 대상이 됩니다. 가비지 컬렉터는 런타임 환경에 따라 특정 시점이나 메모리 사용량이 포화 상태에 임박할 때마다 자동으로 수거 대상들을 수거 합니다. 수거된 메모리는 다시 새로운 값을 할당할 수 있는 빈 공간이 됩니다.
3. 변수 복사 비교
변수를 복사하는 과정은 기본형 데이터와 참조형 데이터 모두 같은 주소를 바라보게 되는 점에서 동일합니다.
변수 복사 이후 객체의 프로터피를 변경하는 경우를 살펴보겠습니다.
1 var a = 10;
2 var b = a;
3 var ob1 = { c: 10, d: 'ddd' };
4 var obj2 = obj1;
5
6 b = 15;
7 obj2.c = 20;
7번째 줄에서는 데이터 영역에 아직 20이 없으므로 새로운 공간 @5005에 저장하고, 그 주소를 든 채로 변수 영역에서 obj2를 찾고(@1004), obj2의 값인 @5002가 가리키는 변수 영역에서 다시 c를 찾아(@7103) 그곳에 @5005에 대입합니다.
기본형 데이터를 복사한 변수 b의 값을 바꿧더니 @1002의 값이 달라진 반면, 참조형 데이터를 복사한 변수 obj2의 프로퍼티의 값을 바꾸었더니 @1004의 값은 달라지지 않았습니다. 즉, 변수 a와 b는 서로 다른 주소를 바라보게 됐으나, 변수 obj1과 obj2는 여전히 같은 객체를 바라보고 있는 상태입니다. 이를 코드로 표현하면 다음과 같습니다.
a !== b
obj1 === obj2
이 결과가 바로 기본형과 참조형 데이터의 가장 큰 차이점 입니다. 대부분의 자바스크립트 책에서는 '기본형은 값을 복사하고 참조형은 주솟값을 복사한다'라고 설명하지만 사실은 어떤 데이터 타입이든 변수에 할당하기 위해서는 주솟값을 복사해야 하기 때문에, 엄밀히 따지면 자바스크립트의 모든 데이터 타입은 참조형 데이터일 수 밖에 없습니다. 다만 기본형은 주솟값을 복사하는 과정이 한 번만 이뤄지고, 참조형은 한 단계를 더 거치게 된다는 차이가 있는 것입니다.
즉 참조형 데이터가 '가변값'이라고 설명할 때의 '가변'은 참조형 데이터 자체를 변경할 경우가 아니라 그 내부의 프로퍼티를 변경할 때만 성립합니다.
불변 객체
그렇다면 내부 프로퍼티를 변경할 필요가 있을 때마다 매번 새로운 객체를 만들어 재할당하기로 규칙을 정하거나 자동으로 새로운 객체를 만드는 도구(immutable.js, immer.js, es6의 spread operator, Object.assign 메서드)를 사용한다면 객체 역시 불변성을 확보할 수 있을 것입니다.
그럼 어떤 상황에서 불변 객체가 필요할까요 ? 값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우 입니다.
1 var user = {
2 name: 'jaenam',
3 genger: 'male',
4 };
5
6 var changeName = function(user,newName){
7 var newUser = user;
8 newUser.name = newName;
9 return newUser;
10 };
11
12 var user2 = changeName(user,'jung');
13
14 if(user!==user2){
15 console.log('유저 정보가 변경되었습니다.');
16 }
17 console.log(user.name, user2.name); // jung, jung
18 console.log(user === user2) // true
user객체를 만든 후 name 프로퍼티를 바꾸는 changeName을 호출하고 그 결과값은 user2에 담았습니다. 7번라인에서 user를 newUser에 대입했다는 의미는 newUser와 user가 보는 주소공간이 같다는 의미 입니다. 때문에 8번 라인에서 name 프로퍼티를 바꾸면 기존의 객체 user에도 영향이 가게 됩니다. 그렇기 때문에 이후에 user와 user2객체는 완전히 같다고 나오고, name 프로퍼티 값까지 같게 나옵니다.
만약 14번 라인처럼 정보가 바뀐 시점에 알림을 보내야 한다거나, 바뀌기 전의 정보와 바뀐 후의 정보의 차이를 가시적으로 보여줘야 하는 등의 기능을 구현하려면 이대로는 안되겠습니다. 변경 전과 후에 서로 다른 객체를 바라보게 만들어야 겠죠.
1 var user = {
2 name: 'jaenam',
3 genger: 'male',
4 };
5
6 var changeName = function(user,newName){
7 return {
8 name: newName,
9 gender: user.gender
10 };
11 };
12 var user2 = changeName(user,'jung');
13
14 if(user!==user2){
15 console.log('유저 정보가 변경되었습니다.'); // 유저 정보가 변경되었습니다.
16 }
17 console.log(user.name, user2.name); // jaenam, jung
18 console.log(user === user2) // false
기존의 changeName함수에서는 user를 newUser에 대입했고, 이렇게 되면 user와 newUser는 같은 주소공간을 바라보기 때문에 name 프로퍼티를 수정하면 user와 user2 모두 영향을 및비니다. 하지만 수정된 changeName의 경우 새로운 객체를 return 하기 때문에 user와 user2는 서로 다른 주소공간을 바라보기 때문에 즉, 서로 다른 객체이므로 안전하게 변경 전과 후를 비교할 수 있습니다.
하지만 이런 방법의 경우 대상 객체에 정보가 많은 수록, 변경해야 할 정보가 많을 수록 사용자가 입력하는 수고가 늘어날 것입니다. 만약 address, age라는 프로퍼티가 changeName함수도 수정해주어야 합니다. 이런 방식보다는 대상의 객체의 프로퍼티 개수에 상관없이 모든 프로퍼티를 복사하는 함수를 만드는 것이 좋습니다.
1 var copyObject = function(target){
2 var result = {};
3 for(var prop in target){
4 result[prop] = target[prop];
5 }
6 return result;
7 }
copyObject는 for in 문법을 이용해 target의 프로퍼티 개수에 상관없이 모든 프로퍼티를 result에 복사할 수 있습니다. 하지만 copyObject의 가장 큰 문제는 '얕은 복사만 수행한다는 것입니다' 이는 다음 챕터에서 알아 보겠습니다.
2. 얕은 복사와 깊은 복사
위의 copyObject함수를 다시 보겠습니다. target의 프로퍼티를 result에 복사하고 있는데 만약 target의 프로퍼티들이 다음과 같으면 어떻게 될까요 ?
1 var target = {
2 age: 12,
3 familyAge: {
4 mother: 45,
5 father: 50,
6 brother: 21
7 }
8 }
9 var obj1 = copyObject(target);
10 var obj2 = copyObject(target);
11
12 obj1.familyAge.mother = 50;
이런 경우 target의 familyAge 프로퍼티를 복사하는데 이때 복사되는 값은 familyAge의 주소공간 값입니다. 12번 라인에서 mother의 값을 바꾸게 되면 obj2의 값도 같이 바뀌게 됩니다. 이를 '얕은 복사'라고 합니다.
얕은 복사(shallow copy)는 바로 아래 단계의 값만 복사하는 방법이고, 깊은 복사(deep copy)는 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법입니다. 이 말은 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주솟값만 복사한다는 의미 입니다. 때문에 사본을 바꾸면 원본도 바뀌고 원본을 바뀌면 사본도 바뀝니다.
어떤 객체를 복사할 때 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고자 할 때, 객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우에는 그대로 복사하면 되지만 참조형 데이터는 다시 그 내부의 프로터피들을 복사해야 합니다.
이 개념을 바탕으로 copyObject 함수를 깊은 복사 방식으로 고친 코드는 다음과 같습니다.
1 var copyObjectDeep = function(target){
2 var result = {};
3 if(typeof target === 'object' && target !== null){
4 for(var prop in target){
5 result[prop] = copyObjectDeep(target[prop]);
6 }else{
7 result = target;
8 }
9 return result;
10 };
재귀적인 방법을 사용해서 target이 기본형 데이터인 경우에만 복사를 하고 있습니다. 이 함수를 사용해 객체를 복사한 다음에는 원본과 사본이 서로 완전히 다른 객체를 참조하게 되어 어느 쪽의 프로퍼티를 변경하더라도 다른 쪽에 영향을 주지 않습니다. 여기서 target !== null조건을 추가한 이유는 자바스크립트의 typeof 명령어가 null에 대해서도 'object'를 반환하기 때문입니다.
이런 방법 말고도 간단하게 깊은 복사를 처리할 수 있는 방법으로 '객체를 JSON 문법으로 표현된 문자열로 전환했다가 다시 JSON 객체로 바꾸는 겁니다'. 이 방법은 단순함에도 불구하고 잘 동작합니다.
1 var copyObjectViaJSON = function(target){
2 return JSON.parse(JSON.stringify(target));
3 }
참고 : 코어 자바스크립트(Core JavaScript), 정재남
'javascript' 카테고리의 다른 글
[javascript] 클로저 (0) | 2020.05.08 |
---|---|
[javascript] this (0) | 2020.05.04 |
[javascript] 실행 컨텍스트 (0) | 2020.05.02 |
[javascript] undefined와 null (0) | 2020.05.02 |
[javascript] 프로토타입(prototype) (0) | 2019.03.14 |