3 minute read

변수

  • 하나의 값을 저장하기 위해 확보한 메모리 공간 혹은 식별을 위해 붙인 이름
  • let variable = 123 ⇒ 키워드 변수명 = 값 의 형태
    • 변수명은 메모리상의 주소를, 값은 주소에 해당하는 값을 의미함
    • 메모리상 값은 언제든 변경이 가능

image

  • 변수 호이스팅: 변수 선언문이 코드의 가장 처음에 위치한 것처럼 동작하는 JS 고유의 특징
    • 즉, 자바스크립트 엔진은 변수 선언이 어디에 위치하든 다른 코드보다 먼저 실행함
    • 변수 선언은 런타임 이전에 먼저 실행되나 값의 할당은 런타임에 실행됨

상수

  • 상수는 변하지 않는 값을 의미. 즉, 값을 재할당할 수 없음

undefined: 값이 정의되지 않은 상태

  • undefined는 원시 타입의 값

null: 해당 변수가 비어있음을 사용자가 의도적으로 나타낼 때 사용

메모리

  • 할당 → 사용 → 해제 의 순서를 거침
  • JS는 garbage collector를 통해 사용하지 않는 메모리를 정리함
  • JS 엔진은 가상머신으로 구성되어 있음

    • Heap: 참조 타입이 들어가며, 메로리 크기가 동적으로 변함
    • Call Stack: 원시 타입이 들어감

    image

    • arr.push(3)과 같은 경우 Heap 메모리 변경
  • 메모리가 지워지는 것은 참조가 중요함! (클로저가 가능한 이유도 참조 덕분이라고 할 수 있음)

원시 타입과 객체 타입

  • 변수를 위해선 임시적인 저장 공간인 메모리 구조를 알아야함
  • 원시 타입은 단일 메모리에 할당 되지만, 객체 타입은 메모리 주소가 할당됨
    • 변수는 변수가 지정된 주소를 참조하는 것
  • 원시 타입(primitive type): 변경 불가능한 값으로, 원시 값을 변수에 할당하면 메모리 공간에는 실제 값이 저장됨
    • 원시 타입은 값이 변경시 항상 새로운 메모리에 할당됨
    • 읽기 전용의 값
    • 재할당 이외에 변수 값을 변경할 수 있는 방법은 없음
    • cf) 객체를 변수에 할당하면 메모리에는 참조값이 저장됨
  • 객체 는 변경 가능한 값으로, 객체를 할당한 변수는 재할당 없이 객체를 직접 변경할 수 있음

Shallow Copy(얕은 복사)

동일한 메모리 주소를 참조하는 할당 방식

const obj1 = obj2;
console.log(obj1 === obj2); //true

Deep Copy(깊은 복사)

다른 메모리 주소를 가지도록 하는 할당 방식 이때, 할당하는 객체가 1차원 객체인지 2차원 이상 객체인지에 따라 깊은 복사인지의 여부가 결정됨

  • 1차원 객체인 경우, 객체 전부가 깊은 복사를 진행함. 하지만 2차원 이상 객체인 경우, 객체 중 1차원 객체만 깊은 복사를 진행하고 2차원 이상 객체는 얕은 복사를 진행한다!

  • 2차원 이상 객체 역시 깊은 복사를 하고 싶은 경우, 직접 값을 할당하거나 JSON,parse, JSON,stringfy를 활용하여 할당해야함

  • 1차원 객체 복사

    • 이때, 2차원 이상 객체의 경우 일부만 깊은 복사를 진행
const obj1 = { ...obj2 };
const obj1 = object.assign({}, obj2);
const obj1 = Array.from(obj2);
  • 2차원 객체 복사
const obj1 = JSON.parse(JSON.stringfy(obj2));

예시

구조분해할당 연습

const hyeinInfo = {
  name: "hyein",
  age: 2,
  job: "학생",
};

const { name, age, job: job2, pet = "강아지" } = hyeinInfo;
  • hyeinInfo의 job의 키값을 job2로 사용하겠다는 의미와 같으며, 이전에 존재하지 않았던 pet 속성은 영향을 주지않는다!
console.log(hyeinInfo);
/*
{name: 'hyein', age: 2, job: '학생'}
*/
console.log(name, age, job2, pet);
// hyein 2 학생 강아지
  • 즉, 기본값 설정은 해당 속성이 객체에 없을 때만 적용된다
const hyeinInfo = {
  name: "hyein",
  age: 2,
  job: "학생",
  pet: "고양이",
};

const { name, age, job: job2, pet = "강아지" } = hyeinInfo;

console.log(hyeinInfo);
// {name: 'hyein', age: 2, job: '학생', pet: '고양이'}

console.log(name, age, job2, pet);
// hyein 2 학생 고양이

깊은 복사와 얕은 복사

얕은 복사

  • 원본 배열과 복사된 배열이 같은 객체를 참조
  • 복사한 배열의 값을 변경하면 원본 배열의 값도 변경됨
let arr = [1, 2, { a: 3 }];
let shallowCopy = arr;

shallowCopy[0] = 10;
shallowCopy[2].a = 100;

console.log("=== shallowCopy ===");
console.log(arr); // [10, 2, {a: 100}]
console.log(shallowCopy); // [10, 2, {a: 100}]

깊은 복사 (1차원 요소)

  • 배열의 1차원 요소만 복사
  • 배열의 요소가 객체라면 해당 객체의 “참조”만 복사
  • 원본 배열과 복사된 배열이 같은 객체를 참조
  • 복사한 배열의 객체값을 변경하면 원본 배열의 객체값도 변경됨
arr = [1, 2, { a: 3 }];
let deepCopy = [...arr]; // 또는 arr.slice() 등

deepCopy[0] = 10;
deepCopy[2].a = 100;

console.log("=== deepCopy ===");
console.log(arr); // [1, 2, {a: 100}]
console.log(deepCopy); // [10, 2, {a: 100}]

깊은 복사 (2단계 깊이까지 복사하고 싶다면) 🤔

  • 모든 레벨의 요소를 새로운 메모리 공간에 복사
  • 배열 내에 중첩된 객체, 배열이 있을 때 유용함
  • 원본 배열과 복사한 배열이 독립적으로 동작
arr = [1, 2, { a: 3 }];
let deepDeepCopy = JSON.parse(JSON.stringify(arr));

deepDeepCopy[0] = 10;
deepDeepCopy[2].a = 100;

console.log("=== deepDeepCopy ===");
console.log(arr); // [1, 2, {a: 3}]
console.log(deepDeepCopy); // [10, 2, {a: 100}]

참고 https://poiemaweb.com/