JS 3주차 정리 :: 메모리 | 데이터 할당 | 불변객체 (얕은복사 & 깊은복사)

728x90
반응형

1. 데이터타입의 종류 및 메모리

값의 저장 방식 & 불변성 여부에 따라 2가지로 나눔

 

(1) 기본형

: Number, String, Boolean, null, undefined, Symbol

-  값의 저장 방식 : 주소값 바로 복제

- 불변성 : 불변하다--> 메모리 관점에서 봐야함

 

(2) 참조형 (reference)

: Object > Array, Function, Date, RegExp, Map, Set 

-  값의 저장 방식 : 주소값 묶음을 가르키는 주소값을 복제

- 불변성 : 불병성을 띄지 않음

 

* 메모리

(1) 비트 : 가장 작은 단위 (0과 1) :: 메모리를 구성하기 위한 작은 조각 

(2) 바이트 : 8비트 = 1바이트 

(3) 메모리 : 모든 데이터는 바이트 단위의 메모리 주소 -> 구분이 된다.

    * 64비트 = 8바이트 (연속된 8개의 바이트에 저장)

    * JS는 let -> 8 바이트  / c,java 는 byte (1), short(2), int(4), long(8)

 

# 식별자(변수명) & 변수(데이터) : var testValue(식별자) = 3 (변수)

2. 변수 선언과 데이터 할당 (기본형데이터)

let str ;

str = 'test!';

변수 영역 1002 1003 1004
이름 : str
데이터 : @5003
  이름: 기본형 
데이터 : @5003->5004
데이터 영역 5002 5003 5004
  'test!' 'test modify!!!'
(데이터영역 변경 x
새로운 영역 줌:불변)

* 값을 변수에 직접 대입 x, 주소를 저장함 

- 자유로운 데이터 변환  & 효율적인 메모리 관리를 위해서 

* 변수: 변수 영역 메모리 변경 가능

* 상수: 변수 영역 메모리 변경 불가능

* 불변하다 : 데이터 영역 메모리를 변경 불가능

* 불변하지 않다 : 데이터 영역 메모리 변경 가능 

 

(1) 기본형 데이터

: 변수 영역에서 데이터를 변경하면, 데이터 영역의 주소가 변경되는것 뿐, 변경 불가능 > 불변하다

: 데이터가 (@5003 -> @5004로 변경 / @5003은 사용 안하니 가비지컬렉터 대상임)

 

3. 변수 선언과 데이터 할당 (참조형데이터) 변수복사의 비교

let obj ={

 a:1 , 

 b:'bbb'

}

 

//데이터 변형 : obj.a = 2

변수 영역 1001 1002 1003
obj / @7103~    
데이터 영역 5001 5002 5003
1 'bbb' 2
obj 별도 영역
(참조형데이터)
7103 7014 7015
a / @5001
> @5003으로 변경
b / @5002  

* 참조형 데이터는 객체의 변수(프로퍼티)의 영역이 별도로 존재함

* 데이터 영역은 변경x, obj별도 영역 데이터가 변함 (@5001> @5003) = 불변하지 않다, 가변하다

 

#중첩객체

: 객체 안에 또 다른 객체

var obj ={
     x:3,
  arr : [3,4,5]
};
변수 영역 1001 1002 1003
obj 
@7103~
   
데이터 영역  5001 5002 5003
3 4 5
 obj 별도 영역 7103 7104  
x
@5001
arr
@8104~
 
arr 별도 영역 8104 8105 8106
arr[0]
@5001
arr[1]
@5002
arr[2]
@5003

* 참조 카운터 : 다른 곳에서 참조하거나 나타내지 않기에 0이 됨 > 가비지 컬렉터에 의해 메모리에서 제거

 

#변수 복사의 비교

let a = 10; //기본형
let obj1 = {c : 10, d: 'ddd'} //참조형

let b =a;
let obj2 = obj2;

//값 수정
b= 15;
obj2.c = 20;
변수 영역 1001 1002 1003 1004
a
@5001
obj1
@8104~ (변함없음)
b
@5001 (복사)
>@5003 (값 변경)
obj2
@8104~ (변함 없음)
데이터 영역  5001 5002 5003 5004
10 'ddd' 15 20
 obj 별도 영역 8104 8105 8106 8107
c
@5001
>@5004 (값 변경)
d
@5002
   

이렇게 되면 문제는,

obj2 (복사본) c의 값 = 20 // obj(원본) c의 값 = 20 (여기는 10이여야함)

* 기본형 : 복사 결과와 다른 값 ! (a = @5001  / b = @5003 )

* 참조형 : 복사 결과는 같은 값 ! (obj1 = @8104 / obj2 = @8104 )

 

해결방법은, 객체 자체를 변경하기! ( obj1 != obj2  )

obj.2= 20; 이 아닌 obj2 = { b: 20 , d : 'aaa'} 이렇게 새롭게 넣어주면 obj별도 영역이 새로 생김

변수영역

: 1004 -> obj = @8106

데이터 영역

: 5005 ('aaa')

obj 별도 영역

: 8106 (b: @5004 ) / 8107 (d:@5005) 

 

4. 불변 객체 (얕은 복사 / 깊은 복사) 

- 데이터 영역은 안 변하고, 객체 별도 영역만 변함 --> 불변 (데이터 영역)

 

(1) 객체의 속성(프로퍼티)에 접근

//user 객체 생성
let user = {
 name: "홍",
 age: 20
}

// 이름 변경하는 함수
// 입력값 : 변경 대상 user 객체, 변경할 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티(속성)에 접근해서 이름 변경 --> 가변
// 객체의 속성 (newUser.name)으로 변경하면 "객체 영역의 주소값만 변경, 변수의 주소값 변경 x" 
let changeName = function (user, newName){
  let newUser = user;
  newUser.name = newName; //박
  return newUser;
}

// user2의 이름을 "박"으로 변경하려했지만, user1도 "박"으로 변함
// user2, user1이 속성만 바꾼걸로, 같은 주소값을 바라봄
let user2 = changeName(user, "박");

console.log(user.name, user2.name); //박, 박
console.log(user === user2); //true

(2) 새로운 객체를 반환

//user 객체 생성
let user = {
 name: "홍",
 age: 20
}

// 이름 변경하는 함수
// 입력값 : 변경 대상 user 객체, 변경할 이름
// 출력값 : 새로운 user 객체
// 새로운 객체를 반환 (프로퍼티 접근 x)
let changeName = function (user, newName){
  return{ //새로운 객체 반환
   name: newName,
   age: user.age,
  };
}

// user2가 새로운 주소값을 바라봄
let user2 = changeName(user, "박");

console.log(user.name, user2.name); //박, 홍
console.log(user === user2); //false

 

(3) 얕은 복사

- 중첩된 객체에 대해서는 완벽한 복사 불가능 

- for(~in) : 반복하면서 1 deth만 가능 + 중첩된 곳은 메모리 복사를 할 수 밖에 없음

// 얕은 복사 패턴
let copyObject = function (객체명) {
	let result ={};
    
    for(let prop in 객체명){
     	result[prop] = 객체명[prop]
    }
    return result;
}


let user = { name :"홍", age : 20};

let user2 = copyObject(user);
user2.name = "박";

 

(4) 깊은 복사

: 재귀적 수행 (re+cursive : 다시 돌아간다 )

: 아래 코드 콘솔 찍으면서 공부해보

let copyObjectDeep = function(target) {
	let result = [];
    if(typeof target === 'object' && target != null){
		for(var prop in target){
          result[prop] = copyObjectDeep(target[prop]); //객체&&null 아니면 재귀적으로 다시 들어옴
        }
    }
    else { result = target ;}
    
    return result;
}

 

* JSON(= JavaScript Object Notation)을 이용하는 방법도 존재--> 참고만 하

 

[출처]

1. 스파르타 코딩, JavaScript 문법 종합반 3주차 (1강-4강)

반응형