자바스크립트에서 제공하는 7가지 데이터 타입(number, string, boolean, Null, undefined, symbol, object)은 number
, string
, boolean
, null
, undefined
, symbol
과 같이 고정된 저장 공간을 가진 자료형인 원시 자료형과, 대량의 데이터를 다루기에 적합한 배열
과 객체
등의 참조 자료형으로 구분할 수 있다.
: 원시 타입의 값, 즉 원시 값은 변경 불가능한 값이다. 읽기 전용 값으로서 변경할 수 없다.
변경 불가능하다는 것은 변수가 아닌 값에 대한 진술이다. "원시 값은 변경 불가능하다"는 말은 원시 값 자체를 변경할 수 없다는 것이지 변수 값을 변경할 수 없다는 것이 아니다.
원시 자료형의 특징
- 변경 불가능한 값, 즉, 읽기 전용이다.
- 어떤 일이 있어도 불변하는 특성 덕분에 데이터의 신뢰성을 보장한다.
- 변수에 할당하면 메모리 공간에 값 자체가 저장 된다.
- 원시 값을 갖는 변수를 다른 변수에 할당하면 원시 값 자체가 복사되어 전달 된다.
- 원시 값을 할당한 변수에 새로운 원시 값을 재할당하면 메모리 공간에 저장되어 있는 재할당 이전의 원시 값이 아니라 새로운 메모리 공간을 확보하고 재할당한 원시 값을 저장한 후, 변수는 새롭게 재할당한 원시 값을 가리킨다. → 이런 특성을 불변성
이라고 한다.
- 두 변수의 원시 값은 서로 다른 메모리 공간에 저장된 별개의 값이 되어 어느 한쪽에서 재할당을 통해 값을 변경하더라도 서로 간섭 할 수 없다.
: 참조(객체) 타입의 값, 즉 객체는 변경 가능한 값이다. 참조 값은 생성된 객체가 저장된 메모리 공간의 주소, 그 자체다.
참조 자료형의 특징
- 변수에 할당하면 주솟값이 저장 된다.
- 참조 값을 갖는 변수를 다른 변수에 할당하면 주솟값이 복사되어 전달된다.
- 참조 자료형은 변경이 가능한 값이다.
- 객체를 할당한 변수는 재할당 없이 객체를 직접 변경할 수 있다.
- 여러 개의 식별자가 하나의 객체를 공유할 수 있다는 단점을 가진다.
얕은 복사는 객체에 중첩되어 있는 객체의 경우 참조 값을 복사하고, 깊은 복사는 객체에 중첩되어 있는 객체까지 모두 복사해서 원시 값처럼 완전히 복사본을 만든다는 차이가 있다.
→ 원시 값을 할당한 변수를 다른 변수에 할당하는 것을 깊은 복사, 객체를 할당한 변수를 다른 변수에 할당하는 것을 얕은 복사라고도 부른다.
: 배열 내장 메서드. 주소가 다르기 때문에 복사한 배열에 요소를 추가해도 원본 배열에는 추가 되지 않는다.
let arr = [0, 1, 2, 3];
let copiedArr = arr.slice();
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
copiedArr.push(4);
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr); // [0, 1, 2, 3]
: ES6에서 새롭게 추가된 문법으로, 배열을 펼칠 수 있다. 배열이 할당 된 변수 명 앞에 ...
을 붙여주면 된다.
let arr = [0, 1, 2, 3];
let copiedArr = [...arr];
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
copiedArr.push(4);
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr); // [0, 1, 2, 3]
// 각각 다른 주소를 참조한다.
let obj = { firstName: "ori", lastName: "nuguri" };
let copiedObj = Object.assign({}, obj);
console.log(copiedObj) // { firstName: "ori", lastName: "nuguri" }
console.log(obj === copiedObj) // false
let obj = { firstName: "ori", lastName: "nuguri" };
let copiedObj = {...obj};
console.log(copiedObj) // { firstName: "ori", lastName: "nuguri" }
console.log(obj === copiedObj) // false
: 참조자료형 내부에 참조 자료형이 중첩되어있는 경우 slice()
, Object.assign()
, spread syntax
를 사용해도 참조 자료형 내부에 참조 자료형이 중첩된 구조는 한 단계까지만 복사한다.
이것을 얕은 복사(shallow copy)라고 한다.
: 참조 자료형 내부에 참조 자료형이 중첩된 구조를 복사할 때 한 단계까지만 복사되는 것을 말한다.
: 참조 자료형 내부에 중첩되어 있는 모든 참조 자료형을 복사하는 것을 깊은 복사(deep copy)라고 한다.
JS 내부적으로는 깊은 복사를 수행할 수 있는 방법은 없으며, 다른 문법을 응용하여 같은 결과물을 만들어 낼 순 있다.
JSON.stringify()
: 참조자료형 → 문자열 형태로 변환하여 반환JSON.parse()
: 문자열 형태 → 객체로 변환하여 반환const arr = [1, 2, [3, 4]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
단, 함수가 포함되어 있을 경우 함수는 null로 바뀌게 되기 때문에 완전한 깊은 복사 방법이라 보기 어렵다.
node.js
환경에서 외부라이브러리인 lodash 또는 ramda를 설치하면 된다.
ladash 예시
const lodash = require('lodash');
const arr = [1, 2, [3, 4]];
const copiedArr = lodash.cloneDeep(arr);
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
const namazuo = {'i', 'love', 'namazuo'};
const cute = namazuo.slice(1, -1);
console.log(
you ${cute[0]} ${cute[1]}
);// you love namazuo