(SEB_FE) Section1 Unit9 JS 핵심 개념과 주요 문법

PYM·2023년 3월 2일
0

(SEB_FE) SECTION1

목록 보기
30/38
post-thumbnail
  1. 원시 자료형(primitive data type)과 참조 자료형(reference data type)의 구분이 왜 필요한지 이해할 수 있다.
  2. 원시 자료형과 참조 자료형의 차이를 이해하고, 각자 맞는 상황에서 사용할 수 있다.
  3. 원시 자료형이 할당될 때는 변수에 값(value) 자체가 담기고, 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담긴다는 개념을 코드로 설명할 수 있다.
  4. 참조 자료형은 기존에 고정된 크기의 보관함이 아니라, 동적으로 크기가 변하는 특별한 보관함을 사용한다는 것을 이해할 수 있다.
  5. 참조 자료형인 값을 복사하는 방법에 대해서 이해한다.

⭐원시 자료형 VS 참조 자료형

JavaScript에서 자료형(type)이란 값(value)의 종류이다. 크게 원시 자료형과 참조 자료형 두 가지로 나뉘며, 각각의 자료형은 고유한 속성과 메서드를 가지고 있다.

💫 원시 자료형(primitive data type)

  • number, string, boolean, undefined, null 과 같이 고정된 저장 공간을 차지하는 자료형

  • 변수를 선언하면 그 변수 이름의 사물함 하나가 주어지고, 거기에 값을 할당하면 사물함 안에 값이 들어가는 것!

  • 변수를 호출하게 되면, 변수이름을 가진 사물함을 찾아서 그 안에 있는 값을 반환한다.

  • 이렇듯 원시 자료형은 각각의 사물함 공간을 가지고 있어서 값 복사 시 사물함 안의 데이터를 복사한 복사본을 자신의 사물함에 넣기 때문에, 값을 수정해도 원본 데이터는 수정되지 않는다 (불변 값; immutable value)

    • 즉, 한 번 생성된 원시 자료형은 읽기 전용(read only) 값이다
    • 이렇게 값의 변경이 불가능하기 때문에 원시 자료형은 신뢰성이 높다

💫 참조 자료형(reference data type)

  • array, object function 처럼 대량의 데이터를 다루기 적합한 자료형(원시 자료형이 아닌 자료형은 전부 참조 자료형이다!)

  • 원시 자료형처럼 대량 데이터를 사물함으로 하나하나 줄 경우 삭제, 추가 등이 매우 복잡해진다

  • 따라서 어떤 부분의 사물함을 시원하게 밀어버리고 특별한 저장 공간 heap을 만듬

  • 참조 자료형을 선언하게 되면, 사물함에 변수 이름을 붙이고, 데이터를 할당할 경우엔 사물함의 안에는 데이터가 아닌, 그 데이터가 있는 heap의 주소가 들어가게 된다

  • 즉, 사물함은 그 주소를 가리키고 있는 것!

  • 변수를 호출하게 되면, 그 이름의 사물함을 찾고, 그 안에 적힌 주소로 찾아가 주르륵 연결된 대량의 데이터를 반환하는 것! (이를 "참조한다(refer)" 라고 함)

  • 참조 자료형은 원시 자료형과 달리 데이터 자체를 복사하는 것이 아니라 주소를 복사해 간다. 따라서 각각 다른 변수라도 같은 주소를 가리키고, 데이터 내용을 변경하면 그 주소에 있는 데이터 값이 변경되는 것이기 때문에 영향을 받게 된다
    (가변값; mutable value)

그렇다면, 배열과 객체 같은 참조 자료형을 복사하여, 똑같은 요소와 프로퍼티를 가지지만 원본과 복사본이 서로 영향을 미치지 않도록 할 수는 없을까?


⭐얕은 복사와 깊은 복사

🟡 얕은 복사(shallow copy)

💫 배열 복사하기

1. slice()

let arr = [0, 1, 2, 3];
let copiedArr = arr.slice();
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false

slice는기존 배열의 데이터 값 자체를 똑같이 복사해서 '새로운' 배열을 생성한다.
이는 원본 배열과 같은 요소를 갖지만, 참조하고 있는 주소는 다르다.

2. spread syntax

ES6에서 새롭게 추가된 문법으로, spread라는 단어의 뜻처럼 배열을 펼칠 수 있다.

  • 배열이 할당된 변수명 앞에 ... 을 붙여주면 펼칠 수 있다.
let arr = [0, 1, 2, 3];

console.log(...arr); // 0 1 2 3

💫 객체 복사하기

1. Object.assign()

let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = Object.assign({}, obj);

console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false

2. spread syntax

배열뿐만 아니라 객체에도 사용할 수 있다.

let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = {...obj};

console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false

🚨얕은 복사는 참조 자료형이 몇 단계로 중첩되어 있던지, 한 단계까지만 복사할 수 있다🚨
➡ 즉, 참조 자료형 내부에 참조 자료형이 중첩되어 있는 경우, slice(),Object.assign(), spread syntax 사용해도 참조 자료형 내부에 참조 자료형이 중첩된 구조는 복사할 수 없다.

🟡 깊은 복사(Deep Copy)

참조 자료형 내부에 중첩되어 있는 모든 참조 자료형을 복사하는 것.
BUT, JavaScript 내부적으로는 깊은 복사를 수행할 수 있는 방법이 없다.

➡ 다른 문법을 응용해서 해야 함

💫 JSON.stringify()JSON.parse()

JSON.stringify()참조 자료형을 문자열 형태로 변환하여 반환하고,
JSON.parse()문자열의 형태를 객체로 변환하여 반환한다. 따라서,

  1. 먼저 중첩된 참조 자료형을 JSON.stringify()를 사용하여 문자열의 형태로 변환한다.
  2. 이후 반환된 값에 다시 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를 설치

1. lodash의 cloneDeep

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

2. ramda의 clone

const ramda = require('ramda');

let arr = [1, 2, [3, 4]];;
let copiedArr = ramda.clone(arr);

사진 출처: 코드스테이츠

profile
목표는 "함께 일하고 싶은, 함께 일해서 좋은" Front-end 개발자

0개의 댓글