식별자 : 이름을 붙일 때 사용하는 단어(변수명,함수명,속성명,메소드명)
할당 : 식별자에 데이터를 넣는 행위
타입 : 식별자에 넣는 데이터값의 종류
자바 스크립트의 데이터타입은 원시타입과 참조타입으로 나누어져 있다.
가장 작은 데이터의 값.
객체가 아니면서 메소드도 가지고 있지 않은 더이상 쪼갤 수 없는 단위.
string, number, bigint, boolean, undefined, null, symbol
변수에 할당 시 메모리에 고정 크기로 값을 저장하고,
저장된 값의 주소를 변수가 직접적으로 가리키는 형태를 띈다.
let a = 1; a = 2;
첫 라인이 실행되면 메모리에 1이라는 값이 생성되고, 변수 a는 1의 메모리 주소를 가리킨다.
두번째 라인이 실행되면 새로운 메모리에 새로운 2라는 값이 생성되고, 변수 a 가 가리키던 주소가 2의 값의 주소로 바뀌는것이다.
메모리에는 "1"과 "2"라는 모든 값이 존재하고 있는것.
그저 변수가 가르키는 주소가 바뀌었기때문에 재할당된것으로 보일 뿐이다.
이러한 경우 1이 담긴 메모리는 가비지 컬렉터에 의해 처리된다.
- 접근속도가 빠름.
- 차지하는 메모리의 양이 참조타입에 비해 훨씬 적음.
- 불변성을 가지고있음.
자바스크립트에서 원시타입을 제외한 모든 것.(배열, 객체, 함수등)
- 크기가 정해져 있지 않은 값을 힙메모리라는 별도의 영역에 저장한다.
- 값이 저장된 힙메모리의 주소를 변수의 값에 저장하고, 그 값의 주소를 변수가 가르키는 형태를 띈다.
- 데이터 자체를 통째로 복사한다.
- 복사된 두 객체는 완전히 독립적인 메모리를 차지한다.
- 원시타입의 객체들은 깊은 복사를 하게 된다.
let a = 1;
let b = a;
a = 2;
console.log(b) // 1
변수 b에 a를 할당 하게되면 변수 b의 메모리에 a의 값을 통째로 복사하여 담게 된다.
변수 a가 2로 재할당 되더라도(가르키는 주소가 바뀌더라도) b는 가르키는 주소가 다르기때문에 전혀 영향을 받지 않는다.
- 값을 복사했을때 메모리에 새로운 값을 생성하는 것이 아니라,
주소값을 복사하여 같은 메모리의 주소를 가리키는 것.- 참조타입의 객체들은 얕은 복사를 하게 된다.
let myArr = [];
let copyArr = myArr;
myArr.push("hello");
console.log(copyArr); // ["hello"]
얕은 복사를 하게되면 같은 데이터의 주소를 가르키기 때문에,
하나의 값이 변경되면 같은 주소를 가르키는 다른 값도 같이 변경된다.
let a = {}; let b = {}; // 독립된 두 객체 alert( a == b ); // false alert( a === b ); // false
두 객체는 모두 비어있다는 점에서는 같아보이지만, 각각의 다른 주소를 가지고있는 독립된 객체이기 때문에 일치, 동등비교를 하면 거짓이 반환된다.
let a = {}; let b = a; // 참조에 의한 복사 alert( a == b ); // true, 두 변수는 같은 객체를 참조합니다. alert( a === b ); // true
얕은 복사를 하게되면 a와 b는 같은 값의 주소를 가르키기 때문에 일치, 동등비교를 하면 참이 반환된다.
데이터가 생성된 이후 그 상태를 변경할 수 없는 것을 의미합니다.
재할당을 할 경우 새로운 메모리에 재할당한 값을 저장하고 새로운 메모리를 가르키는것일뿐 기존의 메모리에있는 값은 변하거나 사라지지않음.
<->
참조타입은 얕은 복사를 하기때문에, 객체 내부의 값을 변경하면
객체를 참조하고 있는 다른 값들도 다 같이 변경되므로 불변성 이슈가 생긴다.
- 스프레드문법 (...)
- Object.assign()
var coke = { name: 'coca', price: 2980, } var new_coke = {...coke}; coke.name = 'pepsi'; console.log(coke.name,new_coke.name);//'pepsi' 'coca'
스프레드 문법과 Object.assign() 은 1레벨 깊이에서만 유효하기 때문에 객체 내부의 객체의 불변성까지는 유지할수 없습니다.
- JSON.parse && JSON.stringify
JSON.stringify()는 객체를 json 문자열로 변환 후, JSON.parse()를 이용해 다시 원래 객체로 만들어줍니다.const object = { a: "a", number: { one: 1, two: 2, }, arr: [1, 2, [3, 4]] }; const copy = JSON.parse(JSON.stringify(object)); copy.number.one = 3; copy.arr[2].push(5); console.log(object === copy); //false console.log(object.number.one === copy.number.one); // false console.log(object.arr === copy.arr); // false console.log(object); // { a: 'a', number: { one: 1, two: 2 }, arr: [ 1, 2, [ 3, 4 ] ] } console.log(copy); // { a: 'a', number: { one: 3, two: 2 }, arr: [ 1, 2, [ 3, 4, 5 ] ] }
- 반복문과 재귀함수를 이용한 방법
- lodash 라이브러리의 cloneDeep 사용
- 원시타입은 콜스택에 데이터를 메모리의 고정 크기로 값을 저장되는 반면,
- 참조타입은 메모리힙이라는 객체의 변수 영역이 추가로 존재하며 값의 크기가 동적으로 변한다는 것이다.
원시타입의 데이터(파란색 변수 a)
- 10이라는 값 자체는 원시 타입이므로 콜 스택에 저장된다.
- 변수 a에는 10이 저장된 콜 스택 메모리의 주소값이 저장된다.
참조 타입 데이터(핑크색 변수 b, c, d)
- 배열, 객체, 함수 등은 참조 타입이므로 메모리 힙에 저장된다.
- 참조타입 데이터가 저장된 메모리 힙의 주소값은 콜스택에 각각 저장된다.
- 메모리힙의 주소 값이 저장된 콜 스택의 주소값은 각각 변수 b, c, d에 저장된다.
참고 자료
https://velog.io/@nomadhash
https://velog.io/@ellyheetov
https://velog.io/@welloff_jj
https://charming-kyu.tistory.com/19
cf)
콜스택
원시타입이 저장되는 공간.(함수 호출도 이곳에 저장된다.)
실행 콘텍스트(Execution Context)를 통해
1) 변수 식별자(이름) 저장,
2) 스코프 체인 및 this 관리,
3) 코드 실행 순서 관리 등을 수행.
메모리힙
참조 타입(객체 등) 데이터가 저장된다.
메모리 할당이 일어나는 곳.