JavaScript 알쓸신잡 - 2

Published on Jul 8, 2024

해당 포스트는 JavaScript의 기초 문법을 정리한 알쓸신잡 포스트입니다.

1. 이전 포스팅

JavaScript 알쓸신잡 - 1
위 포스팅에 이어 JavaScript 기초 문법을 정리한 포스트입니다.

2. JavaScript 알쓸신잡 목차

이전 포스팅에 이어서 공부한 내용을 하나씩 정리하며 포스트를 작성해보고자 합니다.

12. 구조 분해 할당
13. Spread & Rest
14. 타입
15. 반복문
16. 배열 메서드 - 조작
17. 배열 메서드 - 순회 & 탐색
18. 배열 메서드 - 변형
19. Date 객체
20. 동기 & 비동기
21. Promise
22. async & await

3. JavaScript 알쓸신잡

3-12. 구조 분해 할당

구조 분해 할당이라는 기능은 이름에서 추론할 수 있다시피 데이터를 분해해서 받아올 수 있는 기능을 의미합니다.
아래의 간단한 예제를 살펴봅시다.

const arr = [1, 2, 3];
const [one, two, three] = arr;

console.log(one); // 1출력
console.log(two); // 2출력
console.log(three); // 3출력

위 코드를 실행하면 arr의 배열의 element가 one, two, three라는 변수에 각각 할당되는 결과를 확인할 수 있습니다
이러한 구조 분해 할당은 배열뿐만 아니라, 객체 타입에서도 사용할 수 있습니다.
아래의 예제를 살펴봅시다.

const person = {
  name: "정성엽",
  age: 26,
  "like cat": true,
};

const { name, age, "like cat": likeCat } = person;

console.log(name); // 정성엽 출력
console.log(age); // 26 출력
console.log(likeCat); // true 출력

위 코드처럼 객체 변수에 대해서도 구조 분해 할당으로 값을 받을 수 있습니다.
여기서 기억해야할 부분은 우선 객체는 key값을 기준으로 구조 분해 할당이 가능하다는 것입니다.
만약 기존 예제와 다르게 name과 age의 순서가 뒤바뀐 ‘const {age, name} = person;’과 같은 형태로 구조 분해 할당을 진행해도 문제는 발생하지 않습니다.
왜냐하면 키값을 기준으로 구조 분해 할당이 진행되기 때문입니다.
다음으로 기억해야할 부분은 구조 분해 할당으로 데이터를 할당하는 과정에서 key의 이름을 변경할 수 있다는 것입니다.
즉, 변수의 이름을 새롭게 지정하여 값을 저장할 수 있습니다.
위 예제 코드에서는 person 객체에 “like cat”이라는 띄어쓰기가 포함된 내용으로 키가 정해져있습니다.
띄어쓰기가 포함되지 않은 형태로 변수를 저장하기 위해서는 ‘const {“like cat” : likeCat } = person;’과 같이 콜론을 기준으로 새로운 변수명을 지정하여 사용할 수 있습니다.

3-13. Spread & Rest

Spread 연산자(…)는 객체나 배열에 저장된 element들을 펼쳐주는 연산자입니다.
조금더 쉽게 이해하기 위해서 아래의 예제 코드를 살펴봅시다.

const arr = [1, 2, 3];
const new_arr = [4, ...arr, 5, 6];

console.log(new_arr); // [4, 1, 2, 3, 5, 6] 출력

위 코드 예시를 살펴보면 arr이라는 배열은 1, 2, 3 요소를 가지고 있습니다.
new_arr이라는 새로운 배열 변수를 지정할 때, 요소에 …arr을 사용하여 새로운 배열을 선언하고 있습니다.
결과를 살펴보면 spread 연산자는 배열의 요소를 하나씩 가져와서 순서대로 뿌려준다는 것을 알 수 있습니다.
이를 조금더 활용해보면 함수에서 배열이나 객체 변수의 요소를 각각 넘길때 유용하게 사용할 수 있습니다.

const arr1 = [1, 2, 3];

function funcA(p1, p2, p3) {
  console.log(p1, p2, p3);
}

funcA(...arr1); // 1 2 3 출력
-------------------------------------------------
const obj1 = {
  name: "정성엽",
  age: 26,
  "like cat": true,
};

function funcB(p1, p2, p3) {
  console.log(p1, p2, p3);
}

funcB(Object.values(obj1)); // ['정성엽', 26, true] 출력
funcB(...Object.values(obj1)); // 정성엽, 26, true 출력

위 예제를 살펴보면 배열의 요소를 함수의 파라미터로 전달하기 위해 스프레드 연산자(…)을 사용할 수 있는 것을 확인할 수 있습니다.
다음으로 객체를 전달하는 경우를 살펴봅시다.
우선, Object.values 내장 함수를 사용해서 이전에 선언한 객체 변수 obj1의 값들을 추출하여 전달하도록 합니다.
스프레드 연산자를 사용하지 않고 파라미터를 전달하면 funcB의 매개변수 p1에 Object.values(obj1)의 값인 배열 [‘정성엽’, 26, true]가 전달됩니다.
반면, 스프레드 연산자를 사용하여 전달하면 p1, p2, p3 파라미터에 배열의 요소들이 각각 할당되는 것을 확인할 수 있습니다.


다음으로 Rest 연산자(…)는 Spread 연산자와 동일하지만 사용되는 위치가 파라미터를 받는 공간으로 한정됩니다.
Rest 연산자를 사용하여 파라미터를 전달받으면 해당 파라미터들은 배열 형태로 전달된다는 것을 기억해야합니다.
또한, Rest 연산자는 나머지 파라미터들을 받아들이는 역할이기 때문에 Rest 연산자 뒤에 추가적인 파라미터는 올 수 없습니다.
아래의 예제 코드를 살펴보도록 합시다.

const obj1 = {
  name: "정성엽",
  age: 26,
  "like cat": true,
};

const outt = (value1, ...rest) => {
  console.log(value1, ...rest); // 정성엽, 26, true 출력
  console.log(rest); // [26, true] 출력
};

outt(...Object.values(obj1));

위 코드를 살펴보면 outt 함수는 파라미터를 받는 공간에서 …rest (Rest 연산자)를 이용해서 나머지 변수를 받아오도록 했습니다.
이후, console.log에서는 rest 배열을 스프레드 연산자를 이용해서 요소들을 하나씩 출력하도록 했습니다.
따라서 해당 함수의 결과는 주석처리한 부분과 같습니다.

3-14. 타입

JavaScript은 값을 원시타입과 객체타입으로 분류합니다.
원시타입의 경우, 값을 수정해도 메모리에 저장된 값이 변경되지 않습니다.
하지만, 객체 타입의 경우 참조 레퍼런스를 사용하기 때문에 메모리에는 변수의 주소가 저장되어있습니다.
따라서, 값을 변경할 때 원본 데이터의 변경을 불러일으킬 수 있습니다.
아래의 코드를 통해 살펴보도록 합시다.

let o1 = { name: "정성엽" };
let o2 = o1; // o1의 메모리 주소를 그대로 복사
o2.name = "김김김";
console.log(o1.name, o2.name); // 김김김 김김김 출력

let o3 = { ...o1 };
o3.name = "정성엽";
console.log(o1.name, o3.name); // 김김김 정성엽 출력

위 코드에서 o2는 o1의 객체가 저장된 메모리 주소를 그대로 복사하기 때문에 o2와 o1이 가리키는 주소가 동일합니다.
따라서, o2의 프로퍼티를 변경하게되면 o1의 프로퍼티도 동일하게 변경이 되기 때문에 콘솔에 출력했을 때, 두 객체 모두가 변경되는 것을 확인할 수 있습니다.
반면, o3는 스프레드 연산자를 통해 o1의 요소를 복사합니다.
이렇게하면 o3는 새로운 메모리 주소를 가리키지만 o1의 요소를 모두 동일하게 가지고 있게됩니다.
따라서, o3의 프로퍼티를 변경하더라도 o1의 프로퍼티는 변경되지 않는 것을 확인할 수 있습니다.

3-15. 반복문

배열을 순회하는 반복문으로는 ‘for of’를 사용합니다.
사용 예시는 아래와 같습니다.

const arr = [1, 2, 3, 4, 5];
for (let item of arr) {
  console.log(item);
} // 1 2 3 4 5 출력

다음으로 객체를 순회하는 반복문으로는 ‘for in’을 사용합니다
사용 예시는 아래와 같습니다.

const obj = {
  name: "정성엽",
  age: 26,
  "like cat": true,
};

for (let key in obj) {
  console.log(key + ":" + obj[key]);
}

객체를 반복하는 ‘for in’을 사용할 경우, 각 반복마다 key값이 임시 변수에 할당된다는 것을 기억해야 합니다.

3-16. 배열 메서드 - 조작

이번에는 배열을 조작할 수 있는 메서드들에대해서 알아보고자 합니다.
첫번째로는 배열의 추가 메서드 ‘push’입니다. push 메서드를 사용하면 배열의 요소 맨 뒤에 새로운 요소들을 추가합니다.
한번에 여러개의 요소를 추가할 수 있으며, push 메서드는 마지막에 배열의 총 길이를 반환합니다.
아래 코드 예시를 통해 살펴봅시다.

let arr = [1, 2, 3];
arr.push(4);
console.log(arr); // [1, 2, 3, 4] 출력

const arr_length = arr.push(5, 6, 7, 8);
console.log(arr_length); // 8 출력


두번째로는 배열의 마지막 요소를 제거하는 ‘pop’ 메서드입니다.
pop 메서드는 배열의 마지막 요소를 제거하며 제거된 요소를 반환하는 특징이 있습니다.
코드 예시는 아래와 같습니다.

let arr = [1, 2, 3];
let value = arr.pop();
console.log(arr); // [1, 2] 출력
console.log(value); // 3 출력


세번째로는 배열의 첫번째 요소를 제거하고 반환하는 ‘shift’ 메서드입니다.
코드 예시는 아래와 같습니다.

let arr = [1, 2, 3];
let value = arr.shift();
console.log(arr); // [2, 3] 출력
console.log(value); // 1 출력


네번째로는 배열의 맨 앞에 새로운 요소를 추가하는 ‘unshift’ 메서드입니다.
unshift 메서드는 새로운 요소를 추가하고 최종 배열의 길이를 반환하는 특징이 있습니다.
코드 예시는 아래와 같습니다.

let arr = [1, 2, 3];
let length = arr.unshift(0);
console.log(arr); // [0, 1, 2 ,3] 출력
console.log(length); // 4


다섯번째로는 배열의 특정 범위를 잘라내서 새로운 배열을 반환하는 ‘slice’ 메서드입니다.
한 가지 특징으로는 slice 메서드의 첫번째 부분은 ‘자르고 싶은 배열의 시작 인덱스’를 넣어주고, 뒤에는 자르고 싶은 배열의 마지막 인덱스 + 1’을 넣어줍니다.
만약, 자르고 싶은 배열의 시작 인덱스만 넣어준다면 해당 인덱스부터 배열의 마지막까지 잘라서 반환합니다.
또한, 음수의 값을 넣게되면 배열의 마지막 부분부터 입력한 숫자만큼 배열을 잘라서 반환합니다.
잘라낼 범위를 지정하는 메서드이므로 요소의 순서가 변경되지는 않습니다. 또한, 기억해야할 부분은 원래의 배열은 그대로 유지된다는 것입니다.
코드 예시는 아래와 같습니다.

let arr = [1, 2, 3, 4, 5];
let sliced_arr1 = arr.slice(2, 5);
console.log(arr); // [1, 2, 3, 4, 5] 출력
console.log(sliced_arr1); // [3, 4, 5] 출력

let sliced_arr2 = arr.slice(1);
console.log(sliced_arr2); // [2, 3, 4, 5] 출력

let sliced_arr3 = arr.slice(-2);
console.log(sliced_arr3); // [4, 5] 출력


마지막으로는 두개의 서로다른 배열을 합치고 반환하는 ‘concat’ 메서드입니다.
코드 예시는 아래와 같습니다.

let arr_1 = [1, 2, 3];
let arr_2 = [4, 5, 6];

let new_arr = arr_1.concat(arr_2);
console.log(new_arr); // [1, 2, 3, 4, 5, 6] 출력

3-17. 배열 메서드 - 순회 & 탐색

첫번째로 소개할 메서드는 ‘forEach’입니다.
해당 메서드는 배열의 모든 요소들을 하나씩 순회하는 특징이 있습니다. forEach 메서드와 콜백 함수를 이용해서 배열의 값을 이용할 수 있습니다.
코드 예시는 아래와 같습니다.

let arr = [1, 2, 3, 4, 5];
arr.forEach((value) => {
  console.log(value);
});


두번째로 소개할 메서드는 배열에 특정요소가 존재하는지 확인하는 ‘includes’입니다.
Boolean 값을 반환하는 특징이 있습니다. 코드 예시는 아래와 같습니다.

let arr = [1, 2, 3, 4, 5];
console.log(arr.includes(5)); // true 출력
console.log(arr.includes(6)); // false 출력


세번째로 소개할 메서드는 특정 요소의 위치를 찾아서 인덱스를 반환하는 ‘indexOf’ 입니다.
코드 예시는 아래와 같습니다.

let arr = [1, 2, 3, 4];
console.log(arr.indexOf(4)); // 3 출력


네번째로 소개할 메서드는 ‘findIndex’ 입니다.
해당 메서드는 배열의 모든 요소를 순회하면서 콜백 함수를 만족하는 특정 요소의 첫 번째 인덱스를 반환하는 메서드입니다.
즉, 조건을 여러개 만족하더라도 첫 번째 요소만 반환하게 됩니다.
또한, 깊은 비교를 사용하기 때문에 배열이 객체를 가지고 있어도 비교가 가능하다는 특징이 있습니다.
코드 예시는 아래와 같습니다.

let arr = [1, 2, 3, 4, 5, 6];
const finded = arr.findIndex((value) => {
  if (value % 2 === 0) return true;
});
console.log(finded); // 1 출력

객체를 요소로 가진 배열에 대한 예시는 아래와 같습니다.

let arr_obj = [
  {
    name: "정성엽",
    age: 26,
  },
  {
    hobby: "computer",
    bio: "dream is come true",
  },
  {
    hobby: "computer",
    "like cat": true,
  },
];

const finded = arr_obj.findIndex((value) => {
  if (value.hobby === "computer") return true;
});

console.log(finded); // 1 출력


마지막으로, 모든 요소를 순회하면서 콜백 함수를 만족하는 요소를 찾아서 해당 요소를 그대로 반환하는 ‘find’ 메서드입니다.
해당 메서드도 ‘findIndex’와 마찬가지로 조건을 만족하는 첫번째 요소만 반환합니다.
코드 예시는 아래와 같습니다.

let arr = [{ name: "정성엽" }, { age: 26 }, { name: "정성엽", age: 28 }];

const finded = arr.find((value) => value.name === "정성엽");

console.log(finded); // {name : '정성엽'} 출력

3-18. 배열 메서드 - 변형

첫번째로 기존 배열에서 조건을 만족하는 요소들만 필터링하여 새로운 배열로 변환하는 ‘filter’ 메서드입니다.
위에서 설명드린 ‘find’ 메서드와 다른 부분은 조건을 만족하는 모든 요소들을 저장하는 배열로 반환한다는 점입니다.
코드 예시는 아래와 같습니다.

let arr = [
  { name: "정성엽", hobby: "게임" },
  { name: "김김김", hobby: "컴퓨터" },
  { name: "이이이", hobby: "컴퓨터" },
];

let new_arr = arr.filter((value) => value.hobby === "컴퓨터");
console.log(new_arr); // [{name : "김김김", hobby : "컴퓨터"}, {name : "이이이", hobby : "컴퓨터"}] 출력


두번째로 기존 배열에서 조건을 만족하는 요소들을 필터링하여 개발자가 지정한 새로운 배열로 변환하여 반환하는 ‘map’ 메서드입니다.
‘filter’는 그대로 반환했다면 ‘map’은 요소를 변환하여 반환할 수 있다는 것이 특징입니다.
다만, map 메서드는 조건에 맞지 않는 요소라면 undefined를 추가합니다.

let arr = [
  { name: "정성엽", hobby: "게임" },
  { name: "김김김", hobby: "컴퓨터" },
  { name: "이이이", hobby: "컴퓨터" },
];

let new_arr = arr.map((value) => {
  if (value.hobby === "컴퓨터") return value.name + "3";
});

console.log(new_arr); // [undefined, "김김김3", "이이이3"] 출력

만약 조건에 맞는 메서드만 추출해서 개발자가 지정한 내용을 처리 & 반환하고 싶다면 아래와 같이 filter와 map 메서드를 같이 사용할 수 있습니다.

let arr = [
  { name: "정성엽", hobby: "게임" },
  { name: "김김김", hobby: "컴퓨터" },
  { name: "이이이", hobby: "컴퓨터" },
];

let new_arr = arr
  .filter((value) => value.hobby === "컴퓨터")
  .map((value) => value.name + "3");
console.log(new_arr); // ["김김김3", "이이이3"] 출력


세번째로 배열을 정렬하는 ‘sort’ 메서드입니다.
기본적으로 sort 메서드는 배열을 사전 순으로 정렬하기 때문에 숫자에 대해서는 일반적으로 동작하지 않습니다.
코드 예시는 아래와 같습니다.

let arr = ["cycle", "banana", "apple"];
console.log(arr.sort()); // ['apple', 'banana', 'cycle'] 출력

숫자에 대해서 정렬을 진행하고 싶다면 아래와 같이 콜백함수를 사용해야 합니다.
1을 반환하면 파라미터로 전달된 매개변수들의 자리를 변경하도록하고, -1과 0을 반환하면 자리를 변경하지 않도록 하는 규칙을 사용합니다.

let arr = [3, 5, 1];
let new_arr = arr.sort((a, b) => {
  if (a < b) {
    return 1;
  }
  if (a > b) {
    return -1;
  }
  return 0;
});
console.log(new_arr); // [5, 3, 1] 출력
console.log(arr); // [5, 3, 1] 출력


네번째로 배열을 새롭게 반환하는 ‘toSorted’ 메서드입니다.
동작 과정은 sort와 동일하지만 한가지 중요한 차이점은 원본 배열은 그대로 보존한다는 것입니다.
코드 예시는 아래와 같습니다.

let arr = ["cycle", "banana", "apple"];
console.log(arr.toSorted()); // ['apple', 'banana', 'cycle'] 출력
console.log(arr); // ['cycle', 'banana', 'apple'] 출력
console.log(arr.sort()); // ['apple', 'banana', 'cycle'] 출력
console.log(arr); // ['apple', 'banana', 'cycle'] 출력


마지막으로 배열의 모든 요소들을 하나의 문자열로 합쳐서 반환하는 메서드인 ‘join’입니다.
내장 함수 join의 파라미터로 전달하는 값을 기준으로 문자열을 연결할 수 있습니다.
코드 예시는 아래와 같습니다.

let arr = ["i", "am", "good", "man"];
let result1 = arr.join();
let result2 = arr.join(" ");
let result3 = arr.join("-");

console.log(arr); // ['i', 'am', 'good', 'man'] 출력
console.log(result1); // i,am,good,man 출력
console.log(result2); // i am good man 출력
console.log(result3); // i-am-good-man 출력

3-19. 동기와 비동기

JavaScript 엔진은 다른 언어와 다르게 멀티 쓰레드 방식을 지원하지 않습니다.
즉, 싱글 쓰레드 방식을 지원하기 때문에 작업의 성능을 높이기 위해 JS 엔진은 ‘비동기’ 방식을 지원합니다.
비동기 방식이란 작업을 순차적으로 처리하지 않고 개발자가 지정한 시간 이후 콜백 함수를 동작하도록 하는 ‘setTimeout()’ 메서드를 사용하는 방법입니다.
코드 사용 예시는 아래와 같습니다.

console.log(1);
setTimeout(() => {
  console.log(2);
}, 3000);
console.log(3);
// 1 3 2 출력

위 코드를 살펴보면 setTimeout 함수는 첫번째 인자로 콜백함수를 전달하고, 두번째 인자로 콜백함수를 실행하기까지 기다릴 시간을 전달해줍니다.
따라서, 1이 출력되고 setTimeout 함수는 Web APIs라는 Web Browser의 비동기 함수를 처리하는 영역으로 이동합니다.
Web APIs 영역에서 setTimeout은 지정해준 시간을 기다리고 시간이 모두 지나면 콜백함수를 다시 반환합니다.
하지만, setTimeout의 콜백함수가 반환되기 이전에 console.log(3)이 출력되어 결과적으로 1 3 2가 출력됩니다.
비동기 함수는 아래와 같이 응용할 수 있습니다.

const item = "육개장";

const orderedItem = (item, callback) => {
  console.log("주문 상품 : ", item);
  setTimeout(() => {
    callback(item);
  }, 1000);
};

const deliveredItem = (item, callback) => {
  console.log("배달중 상품 : ", item);
  console.log("배송중");
  setTimeout(() => {
    callback(item);
  }, 4000);
};

const arrivedItem = (item, callback) => {
  console.log("도착 상품 : ", item);
  setTimeout(() => {
    callback(item);
  }, 1000);
};

orderedItem(item, () => {
  console.log("주문완료");
  deliveredItem(item, () => {
    arrivedItem(item, () => {
      console.log("배송완료");
    });
  });
});

3-20. Promise

비동기 작업을 효율적으로 처리할 수 있도록 도와주는 JS의 내장 객체가 ‘promise’입니다.
promise는 비동기 작업들을 wrapping하고 있는 객체임을 기억해야 합니다.
비동기 함수는 아래와 같은 시퀀스를 거치게 됩니다.

대기 (Pending) -> 성공 (Fulfilled) / 실패 (Rejected)
resolve : Pending -> Fulfilled
reject : Pending -> Rejected

Promise는 생성자를 통해서 사용할 수 있으며 사용 예시를 통해서 하나씩 알아보도록 합시다.

const promise = new Promise(() => {
  //executor

  setTimeout(() => {
    console.log("안녕");
  }, 2000);
});

console.log(promise);

위 코드에서 콘솔에 출력되는 promise의 promiseState를 살펴보면 pending 상태임을 확인할 수 있습니다.
promiseState를 변경하기 위해서는 executor에 resolve, reject에 대한 파라미터를 넘겨줘야 합니다.
코드 예시는 아래와 같습니다.

const promise = new Promise((resolve, reject) => {
  //executor

  setTimeout(() => {
    console.log("안녕");
    resolve();
  }, 2000);
});

console.log(promise);

위 코드에서 콘솔에 출력되는 promise의 promiseState를 살펴보면 resolve() 메서드가 실행되었기 때문에 ‘fulfilled’ 상태로 변경되었음을 확인할 수 있습니다.
resolve() 함수에 파라미터를 넘겨주면 해당 값은 PromiseResult 값에 저장됩니다.


다음으로 알아봐야할 부분은 promise의 executor에서 resolve를 호출하게 되면, then의 콜백함수가 실행됩니다.
반면, promise의 executor에서 reject를 호출하게 되면, catch의 콜백함수가 실행됩니다.
아래는 이를 응용한 코드입니다.

function add10(num) {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      if (typeof num === "number") {
        resolve(num + 10);
      } else {
        reject("num이 숫자가 아닙니다.");
      }
    }, 2000);
  });
  return promise;
}

add10(0)
  .then((result) => {
    console.log(result);
    return add10(result);
  })
  .then((result) => {
    console.log(result);
    return add10(result);
  })
  .catch((result) => {
    console.log(result);
  });

위 코드에서 눈에띄는 부분은 첫번째로 함수뒤에 .연산자를 통해 then과 catch 함수를 실행할 수 있다는 것입니다.
두번째로 .then의 매개변수로 result를 받았는데 promise의 PromiseResult 값을 즉시 매개변수로 사용할 수 있다는 것입니다.

3-21. async & await

async는 특정 함수를 비동기 함수로 만들어주는 키워드입니다.
즉, 함수가 promise를 반환하도록 만들어주는 키워드입니다.
코드 예시는 아래와 같습니다.

async function getData() {
  return {
    name: "정성엽",
    age: 26,
  };
}

console.log(getData()); // promise를 반환합니다. 반환된 값은 PromiseResult에 저장됩니다.


await는 async 함수 내부에서만 사용이 가능한 키워드로써 비동기 함수가 다 처리되기를 기다리는 역할을 진행합니다.
코드 예시는 아래와 같습니다.

async function getData() {
  return {
    name: "정성엽",
    age: 26,
  };
}

async function printData() {
  const data = await getData();
  console.log(data.name);
}

printData();

결국 resolve가 호출되었을 때 어떤 작업을 수행하도록 하는 메서드인 .then을 사용하지 않고도 개발자가 원하는 작업을 진행하도록 코드를 작성할 수 있습니다.

4. 마무리

2편에 걸쳐서 javascript 기본 문법을 정리해봤습니다.
당연히 javascript의 모든 부분을 정리한 것은 아니기 때문에 이후 직접 개발하면서 마주치는 문제들은 정리하여 다음 포스팅으로 돌아오겠습니다.


참고 : [2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지