diff --git "a/week-01/\352\271\200\353\257\274\355\230\201.md" "b/week-01/\352\271\200\353\257\274\355\230\201.md"
new file mode 100644
index 0000000..b664885
--- /dev/null
+++ "b/week-01/\352\271\200\353\257\274\355\230\201.md"
@@ -0,0 +1,1115 @@
+## 1. 동등 연산자(`==`)와 일치 연산자(`===`)
+
+### 동등 연산자란?
+
+동등 연산자 `==`는 두 값의 **타입이 다르더라도 값이 같으면 `true`를 반환**한다.
+
+```js
+6 == "6"; // true
+0 == ""; // true
+false == 0; // true
+null == undefined; // true
+```
+
+반면 일치 연산자 `===`는 **타입과 값이 모두 같아야 `true`를 반환**한다.
+
+```js
+6 === "6"; // false
+6 === 6; // true
+```
+
+### 쿼리스트링 값 비교에 `==`를 사용해도 될까?
+
+예를 들어 URL 쿼리스트링으로 받은 값은 보통 문자열이다.
+
+```js
+const pageFromQuery = "5";
+const pageFromState = 5;
+
+pageFromQuery == pageFromState; // true
+```
+
+코드 상에서 보통 숫자는 Number 형식으로 처리될 것이다. 하지만, URL 쿼리스트링은 문자열 형식의 숫자값이다.
+이는 서로 타입은 다르지만, '=='로 비교하였을 때 같은 값으로 인식된다.
+
+하지만 이러한 비교는 권장되지는 않는다.
+이유는 `==`가 자동 타입 변환을 수행하기 때문에, 의도하지 않은 비교 결과가 나올 수 있기 때문이다.
+
+```js
+0 == ""; // true
+"0" == false; // true
+null == undefined; // true
+```
+
+- 자세한 자료: [MDN - 동등 비교 및 동일성](https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Equality_comparisons_and_sameness)
+
+따라서 쿼리스트링 값은 명시적으로 변환한 뒤 `===`로 비교하는 것이 더 안전한다.
+
+```js
+const pageFromQuery = Number(searchParams.get("page"));
+const currentPage = 5;
+
+pageFromQuery === currentPage; // true
+```
+
+### 정리
+
+`==`는 JavaScript의 암묵적 타입 변환 규칙을 정확히 알고 있을 때만 제한적으로 사용할 수 있다.
+일반적인 서비스 코드에서는 예측 가능성을 높이기 위해 `===`를 기본으로 사용하는 것이 좋다.
+
+---
+
+## 2. 문자열은 원시 타입이며 변경 불가능하다
+
+JavaScript에서 문자열은 원시 타입이다.
+그리고 원시 타입의 값은 **변경 불가능한 값**, 즉 immutable value이다.
+
+```js
+const text = "hello";
+
+text[0] = "H";
+
+console.log(text); // "hello"
+```
+
+위 코드에서 `"hello"`의 첫 번째 문자를 직접 바꾸려고 했지만, 원본 문자열은 변경되지 않는다.
+
+### 그럼 문자열 변경은 어떻게 이루어질까?
+
+문자열 자체를 바꾸는 것이 아니라, **새로운 문자열을 만들어 변수에 다시 할당**한다.
+
+```js
+const text = "hello";
+
+const newText = "H" + text.slice(1);
+
+console.log(newText); // "Hello"
+```
+
+여기서 기존 문자열 `"hello"`가 직접 수정된 것이 아니다.
+`"H" + text.slice(1)`의 결과로 `"Hello"`라는 새로운 문자열이 만들어지고, `newText`에 새로운 값을 할당해야 한다.
+
+### `slice`와 `substring`
+
+`slice`와 `substring`은 문자열의 일부를 가져오는 메서드이다.
+이 메서드들도 원본 문자열을 변경하지 않고, **잘라낸 결과를 새로운 문자열로 반환**한다.
+
+```js
+const text = "JavaScript";
+
+const result1 = text.slice(0, 4);
+const result2 = text.substring(4, 10);
+
+console.log(result1); // "Java"
+console.log(result2); // "Script"
+console.log(text); // "JavaScript"
+```
+
+### 참고 자료
+
+- [MDN - String.prototype.substring](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String/substring)
+- [문자열에서 특정 위치의 문자를 변경하고 싶은 경우](https://velog.io/@jhsung23/JS-%EB%AC%B8%EC%9E%90%EC%97%B4%EC%97%90%EC%84%9C-%ED%8A%B9%EC%A0%95-%EC%9C%84%EC%B9%98%EC%9D%98-%EB%AC%B8%EC%9E%90%EB%A5%BC-%EB%B3%80%EA%B2%BD%ED%95%98%EA%B3%A0-%EC%8B%B6%EC%9D%80-%EA%B2%BD%EC%9A%B0)
+
+---
+
+## 3. `Object.is`
+
+`Object.is`는 두 값이 같은 값인지 비교하는 메서드이다.
+일반적으로 `===`와 비슷하게 동작하지만, 몇 가지 차이가 있다.
+
+```js
+NaN === NaN; // false
+Object.is(NaN, NaN); // true
+
+-0 === +0; // true
+Object.is(-0, +0); // false
+
+Object.is(1, "1"); // false
+Object.is(1, 1); // true
+```
+
+### `Object.is`의 특징
+
+`Object.is`는 `==`처럼 타입 변환을 하지 않는다.
+그리고 `===`와 달리 다음 두 가지를 더 엄격하게 구분한다.
+
+1. `NaN`과 `NaN`을 같은 값으로 본다.
+2. `-0`과 `+0`을 다른 값으로 본다.
+
+### 이것은 장점일까, 단점일까?
+
+상황에 따라 장점이 될 수도 있고 단점이 될 수도 있다.
+
+`NaN`을 안정적으로 비교해야 하는 상황에서는 장점이다.
+
+```js
+const value = Number("hello");
+
+Object.is(value, NaN); // true
+Number.isNaN(value); // true
+```
+
+반면 대부분의 일반적인 숫자 비교에서는 `-0`과 `+0`을 구분할 필요가 거의 없다.
+이런 상황에서는 `Object.is(-0, +0)`이 `false`라는 점이 오히려 낯설게 느껴질 수 있다.
+
+### 어떤 상황에서 `Object.is`를 사용할까?
+
+직접 서비스 코드에서 자주 사용할 일은 많지 않다.
+다만 다음과 같은 상황에서는 유용한다.
+
+- `NaN`을 정확히 비교해야 할 때
+- `-0`과 `+0`을 구분해야 하는 수학적 계산이 필요할 때
+- React처럼 상태 변경 여부를 내부적으로 정밀하게 판단해야 할 때
+
+---
+
+## 4. React와 `Object.is`
+
+React는 상태 값이 이전 값과 같은지 비교할 때 내부적으로 `Object.is`와 유사한 비교 방식을 사용한다.
+
+```js
+setCount(1);
+setCount(1);
+```
+
+이미 `count`가 `1`인 상태에서 다시 `1`을 넣으면, React는 이전 값과 다음 값이 같다고 판단하여 불필요한 렌더링을 줄일 수 있다.
+
+### React의 얕은 비교
+
+React에서 자주 나오는 개념 중 하나가 **얕은 비교(shallow comparison)**다.
+
+얕은 비교란 객체 내부의 모든 중첩 값을 깊게 비교하는 것이 아니라, **첫 번째 깊이에 존재하는 값만 비교하는 방식**이다.
+
+### React에서 `Object.is`와 얕은 비교의 관계
+
+React가 `Object.is`와 얕은 비교 중 하나만 사용하는 것은 아니다.
+상황에 따라 **값 하나를 비교할 때는 `Object.is`와 유사한 비교 방식을 사용하고, 객체의 props 변경 여부를 판단할 때는 `Object.is`를 기반으로 한 얕은 비교를 사용한다.**
+
+즉, 얕은 비교는 `Object.is`가 동작하지 않을 때 사용하는 대체 방식이 아니다.
+객체의 1단계 key를 순회하면서, 각 key의 값을 `Object.is`로 비교하는 방식에 가깝다.
+
+```js
+function shallowEqual(prevProps, nextProps) {
+ if (Object.is(prevProps, nextProps)) {
+ return true;
+ }
+
+ if (
+ typeof prevProps !== "object" ||
+ prevProps === null ||
+ typeof nextProps !== "object" ||
+ nextProps === null
+ ) {
+ return false;
+ }
+
+ const prevKeys = Object.keys(prevProps);
+ const nextKeys = Object.keys(nextProps);
+
+ if (prevKeys.length !== nextKeys.length) {
+ return false;
+ }
+
+ for (const key of prevKeys) {
+ if (
+ !Object.prototype.hasOwnProperty.call(nextProps, key) ||
+ !Object.is(prevProps[key], nextProps[key])
+ ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+```
+
+위 코드는 React 내부 코드를 그대로 옮긴 것은 아니지만, `Object.is`와 얕은 비교의 관계를 이해하기 좋은 예시다.
+
+React에서 `React.memo`나 `PureComponent`는 props 객체 전체를 깊게 비교하지 않는다.
+대신 이전 props와 다음 props의 key를 비교하고, 각 prop 값이 같은지 `Object.is`와 유사한 방식으로 비교한다.
+
+```txt
+Object.is
+→ 값 하나와 값 하나를 비교한다.
+
+shallowEqual
+→ 객체의 1단계 key를 순회하면서
+ 각 key의 값을 Object.is로 비교한다.
+```
+
+```js
+const prev = {
+ user: {
+ name: "Kim",
+ },
+};
+
+const next = {
+ user: {
+ name: "Kim",
+ },
+};
+
+prev === next; // false
+prev.user === next.user; // false
+```
+
+두 객체의 내용은 같아 보이지만, 각각 새로 만들어진 객체이기 때문에 참조가 다르다.
+
+반대로 다음처럼 내부 객체를 그대로 공유하면 얕은 비교에서 같다고 판단될 수 있다.
+
+```js
+const user = {
+ name: "Kim",
+};
+
+const prev = {
+ user,
+};
+
+const next = {
+ user,
+};
+
+prev === next; // false
+prev.user === next.user; // true
+```
+
+### React에서 중요한 이유
+
+React에서는 상태를 직접 변경하지 않고 새로운 객체를 만들어야 변경을 감지하기 쉽다.
+
+```js
+// 좋지 않은 예시
+const nextUser = user;
+nextUser.name = "Lee";
+setUser(nextUser);
+```
+
+위 코드는 같은 객체 참조를 다시 넣는 형태가 될 수 있다.
+이 경우 React는 이전 상태와 다음 상태가 같다고 판단하여 변경을 감지하지 못할 수 있다.
+
+```js
+// 좋은 예시
+setUser({
+ ...user,
+ name: "Lee",
+});
+```
+
+이렇게 새로운 객체를 만들어 전달하면 React가 이전 상태와 다음 상태의 참조가 달라졌음을 알 수 있다.
+
+다만 새로운 객체를 매번 만들면 `React.memo`로 감싼 컴포넌트에서는 props가 매번 달라졌다고 판단될 수 있다.
+
+```jsx
+const user = {
+ name: "Kim",
+};
+
+return ;
+```
+
+위 코드에서 부모 컴포넌트가 렌더링될 때마다 `user` 객체가 새로 만들어지면, `Profile` 입장에서는 이전 `user`와 다음 `user`의 참조가 다르다고 판단할 수 있다.
+이런 경우에는 객체를 컴포넌트 밖으로 분리하거나, 필요한 상황에서 `useMemo`를 사용할 수 있다.
+
+```jsx
+const user = useMemo(() => {
+ return {
+ name: "Kim",
+ };
+}, []);
+
+return ;
+```
+
+핵심은 상태 업데이트에서는 불변성을 지키기 위해 새 객체를 만들어야 하지만, memo 최적화에서는 불필요하게 새 객체를 계속 만들지 않도록 주의해야 한다는 점이다.
+
+### Polyfill이란?
+
+Polyfill은 최신 JavaScript 기능을 지원하지 않는 구형 환경에서도 해당 기능을 사용할 수 있도록 구현해주는 코드이다.
+
+예를 들어 구형 브라우저가 `Object.is`, `Promise`, `Map` 같은 기능을 지원하지 않는다면, Polyfill을 통해 비슷한 동작을 직접 구현할 수 있다.
+
+```js
+if (!Object.is) {
+ Object.is = function (x, y) {
+ if (x === y) {
+ return x !== 0 || 1 / x === 1 / y;
+ }
+
+ return x !== x && y !== y;
+ };
+}
+```
+
+---
+
+## 5. 즉시 실행 함수 IIFE
+
+IIFE는 Immediately Invoked Function Expression의 약자이다.
+함수를 정의하자마자 즉시 실행하는 함수 표현식이다.
+
+```js
+(function () {
+ console.log("즉시 실행된다.");
+})();
+```
+
+화살표 함수로도 작성할 수 있다.
+
+```js
+(() => {
+ console.log("즉시 실행된다.");
+})();
+```
+
+### IIFE의 특징
+
+IIFE는 정의된 순간 한 번 실행된다.
+일반적인 함수 선언문처럼 이름을 통해 다시 호출하는 용도로 사용하지 않는다.
+
+### 장점
+
+IIFE의 가장 큰 장점은 **독립적인 스코프를 만들 수 있다**는 것이다.
+
+```js
+(() => {
+ const message = "내부에서만 사용된다.";
+ console.log(message);
+})();
+
+console.log(message); // ReferenceError
+```
+
+이처럼 내부 변수는 외부에서 접근할 수 없기 때문에 글로벌 스코프 오염을 줄일 수 있다.
+
+또한 코드를 읽는 사람에게 “이 로직은 한 번만 실행되는 초기화 코드”라는 의도를 전달할 수 있다.
+
+---
+
+## 6. 함수를 만들 때 기억하기 좋은 사항
+
+### 6.1 함수의 부수 효과를 최대한 억제하라
+
+부수 효과란 함수 내부의 실행 결과가 함수 외부에 영향을 주는 것을 의미한다.
+
+```js
+let count = 0;
+
+function increase() {
+ count += 1;
+}
+```
+
+위 함수는 외부 변수 `count`를 변경하므로 부수 효과가 있다.
+
+반대로 순수 함수는 같은 입력에 대해 항상 같은 결과를 반환하고, 외부 상태를 변경하지 않는다.
+
+```js
+function add(a, b) {
+ return a + b;
+}
+```
+
+웹 애플리케이션 개발에서 부수 효과를 완전히 없앨 수는 없다.
+API 요청, localStorage 접근, DOM 조작, 로그 기록 등은 모두 부수 효과이다.
+
+중요한 것은 부수 효과를 없애는 것이 아니라, **부수 효과가 일어나는 위치를 명확히 하고 최소화하는 것**이다.
+
+React 관점에서는 `useEffect`를 남용하지 않고, 렌더링 중 계산 가능한 값은 렌더링 과정에서 계산하는 것이 좋다.
+
+```js
+// 불필요한 useEffect 예시
+const [fullName, setFullName] = useState("");
+
+useEffect(() => {
+ setFullName(`${firstName} ${lastName}`);
+}, [firstName, lastName]);
+```
+
+위 코드는 굳이 상태와 Effect를 만들 필요가 없다.
+
+```js
+// 더 단순한 방식
+const fullName = `${firstName} ${lastName}`;
+```
+
+### 6.2 가능한 함수를 작게 만들어라
+
+함수가 길어질수록 한 함수가 너무 많은 일을 하고 있을 가능성이 높아집니다.
+ESLint에는 `max-lines-per-function`이라는 규칙이 있으며, 함수의 최대 줄 수를 제한할 수 있다.
+
+```js
+// .eslintrc 예시
+{
+ "rules": {
+ "max-lines-per-function": ["warn", 50]
+ }
+}
+```
+
+이 규칙의 목적은 단순히 줄 수를 줄이는 것이 아닙니다.
+핵심은 **하나의 함수가 하나의 책임만 갖도록 만드는 것**이다.
+
+```js
+// 좋지 않은 예시
+function handleSubmit() {
+ // 입력 검증
+ // API 요청
+ // 응답 처리
+ // 토스트 표시
+ // 페이지 이동
+}
+```
+
+위 함수는 너무 많은 일을 하고 있다.
+검증, API 요청, 후처리 등을 별도 함수로 분리하면 읽기 쉽고 테스트하기 쉬워진다.
+
+```js
+function validateForm(form) {
+ // 입력 검증
+}
+
+async function submitForm(form) {
+ // API 요청
+}
+
+function handleSuccess() {
+ // 성공 후 처리
+}
+```
+
+### 6.3 누구나 이해할 수 있는 이름을 붙여라
+
+함수 이름은 함수가 무엇을 하는지 드러내야 한다.
+이름이 명확하면 주석 없이도 코드의 의도를 파악하기 쉬워진다.
+
+---
+
+## 7. 클래스
+
+클래스는 아직 이해가 어려워서 일단 생략합니다..
+
+---
+
+## 8. 클로저
+
+클로저는 **함수와 함수가 선언된 어휘적 환경의 조합**이다.
+
+조금 더 쉽게 말하면, 함수가 생성될 당시의 외부 변수를 기억하고, 함수 실행 이후에도 그 변수에 접근할 수 있는 성질이다.
+
+```js
+function createCounter() {
+ let count = 0;
+
+ return function increase() {
+ count += 1;
+ return count;
+ };
+}
+
+const counter = createCounter();
+
+console.log(counter()); // 1
+console.log(counter()); // 2
+console.log(counter()); // 3
+```
+
+`createCounter` 함수의 실행은 끝났지만, 반환된 `increase` 함수는 여전히 `count`를 기억하고 있다.
+이것이 클로저이다.
+
+### React에서의 클로저 예시
+
+React에서 대표적으로 클로저를 느낄 수 있는 예시는 이벤트 핸들러이다.
+
+```jsx
+function Counter() {
+ const [count, setCount] = useState(0);
+
+ function handleClick() {
+ setCount(count + 1);
+ }
+
+ return ;
+}
+```
+
+`handleClick` 함수는 자신이 만들어질 당시의 `count` 값을 기억한다.
+
+이 특성 때문에 비동기 코드에서는 오래된 값을 참조하는 문제가 생길 수 있다.
+
+```jsx
+function Counter() {
+ const [count, setCount] = useState(0);
+
+ function handleClick() {
+ setTimeout(() => {
+ console.log(count);
+ }, 1000);
+ }
+
+ return (
+ <>
+
+
+ >
+ );
+}
+```
+
+`setTimeout` 안의 콜백은 클릭 당시의 `count`를 기억한다.
+이후 상태가 바뀌더라도 해당 콜백이 기억하는 값은 그대로일 수 있다.
+
+이럴 때는 함수형 업데이트를 사용할 수 있다.
+
+```jsx
+setCount((prev) => prev + 1);
+```
+
+### 클로저와 메모리
+
+클로저는 외부 변수를 기억하기 때문에 메모리를 사용한다.
+필요한 값만 클로저에 남기고, 더 이상 필요 없는 큰 객체나 DOM 참조를 오래 붙잡지 않도록 주의해야 한다.
+
+---
+
+## 9. 이벤트 루프와 비동기 통신의 이해
+
+JavaScript는 기본적으로 싱글 스레드에서 실행된다.
+즉, 한 번에 하나의 작업만 호출 스택에서 처리할 수 있다.
+
+하지만 브라우저 환경에서는 `setTimeout`, 이벤트 처리, 네트워크 요청, Promise 같은 비동기 작업이 자연스럽게 동작한다.
+이것을 이해하려면 이벤트 루프, 호출 스택, 태스크 큐, 마이크로태스크 큐를 알아야 한다.
+
+### 프로세스와 스레드
+
+프로세스는 실행 중인 프로그램의 단위이다.
+스레드는 프로세스 안에서 실제 작업을 수행하는 실행 흐름이다.
+
+하나의 프로세스 안에는 여러 스레드가 존재할 수 있다.
+브라우저는 여러 기능을 처리하기 위해 다양한 스레드를 사용하지만, JavaScript 코드를 실행하는 메인 스레드는 기본적으로 한 번에 하나의 작업을 처리한다.
+
+### 호출 스택
+
+호출 스택은 현재 실행 중인 함수들이 쌓이는 공간이다.
+
+```js
+function bar() {
+ console.log("bar");
+}
+
+function baz() {
+ console.log("baz");
+}
+
+function foo() {
+ console.log("foo");
+ baz();
+ bar();
+}
+
+foo();
+```
+
+실행 결과는 다음과 같다.
+
+```txt
+foo
+baz
+bar
+```
+
+함수가 호출되면 호출 스택에 쌓이고, 실행이 끝나면 스택에서 제거된다.
+
+### `setTimeout` 예시
+
+```js
+console.log(1);
+
+setTimeout(() => {
+ console.log(2);
+}, 0);
+
+setTimeout(() => {
+ console.log(3);
+}, 100);
+
+console.log(4);
+```
+
+실행 결과는 다음과 같다.
+
+```txt
+1
+4
+2
+3
+```
+
+`setTimeout(..., 0)`이라고 해서 즉시 실행되는 것은 아니다.
+콜백 함수가 태스크 큐에 들어가고, 호출 스택이 비었을 때 이벤트 루프에 의해 실행된다.
+
+따라서 `console.log(4)`까지 먼저 실행된 후, 태스크 큐에 있던 `console.log(2)`가 실행된다.
+
+### 올바른 `setTimeout` 사용 예시
+
+아래 코드처럼 콜백 함수를 전달해야 한다.
+
+```js
+function bar() {
+ console.log("bar");
+}
+
+function baz() {
+ console.log("baz");
+}
+
+function foo() {
+ console.log("foo");
+ setTimeout(bar, 0);
+ baz();
+}
+
+foo();
+```
+
+실행 결과는 다음과 같다.
+
+```txt
+foo
+baz
+bar
+```
+
+주의할 점은 `setTimeout(bar(), 0)`처럼 쓰면 `bar` 함수를 나중에 실행하는 것이 아니라, 지금 즉시 실행한 결과를 `setTimeout`에 넘기게 된다.
+
+```js
+setTimeout(bar, 0); // 올바른 형태
+setTimeout(bar(), 0); // bar가 즉시 실행됨
+```
+
+### 태스크 큐와 마이크로태스크 큐
+
+태스크 큐에는 `setTimeout`, `setInterval`, 일부 이벤트 콜백 등이 들어간다.
+마이크로태스크 큐에는 대표적으로 `Promise.then`, `queueMicrotask` 등이 들어간다.
+
+마이크로태스크 큐는 태스크 큐보다 우선순위가 높다.
+
+```js
+console.log("start");
+
+setTimeout(() => {
+ console.log("timeout");
+}, 0);
+
+Promise.resolve().then(() => {
+ console.log("promise");
+});
+
+console.log("end");
+```
+
+실행 결과는 다음과 같다.
+
+```txt
+start
+end
+promise
+timeout
+```
+
+### `setTimeout`의 지연 시간은 최소 대기 시간이다
+
+`setTimeout`에 설정한 시간은 정확한 실행 시간이 아니라 최소 대기 시간이다.
+
+```js
+setTimeout(() => {
+ console.log("실행");
+}, 0);
+```
+
+위 코드는 “0초 뒤에 반드시 실행”이 아니라, “가능한 한 빨리 실행할 수 있도록 태스크 큐에 넣는다”에 가깝다.
+호출 스택이 비어야 실행될 수 있으므로, 메인 스레드가 바쁘면 실제 실행은 더 늦어질 수 있다.
+
+### 렌더링은 언제 실행될까?
+
+브라우저는 보통 하나의 태스크가 끝나고, 마이크로태스크 큐가 모두 비워진 뒤 렌더링할 기회를 얻는다.
+따라서 마이크로태스크가 너무 많이 쌓이면 렌더링이 지연될 수 있다.
+
+```js
+Promise.resolve().then(() => {
+ // 마이크로태스크
+});
+```
+
+마이크로태스크는 태스크보다 먼저 실행되므로, 긴 마이크로태스크 체인은 화면 업데이트를 늦출 수 있다.
+
+### 참고 자료
+
+- [이벤트 루프와 태스크 큐 정리](https://blaxsior-repository.tistory.com/169)
+
+---
+
+## 10. 구조 분해 할당
+
+### 배열 구조 분해 할당
+
+배열 구조 분해 할당은 배열의 값을 순서대로 꺼내 변수에 할당하는 문법이다.
+
+```js
+const numbers = [1, 2];
+
+const [first, second] = numbers;
+
+console.log(first); // 1
+console.log(second); // 2
+```
+
+React의 `useState`도 배열 구조 분해 할당을 자주 사용한다.
+
+```jsx
+const [count, setCount] = useState(0);
+```
+
+`useState`는 2개의 값을 가진 배열을 반환한다.
+
+1. 현재 상태 값
+2. 상태를 변경하는 함수
+
+### `useState`가 객체가 아니라 배열을 반환하는 이유
+
+배열 구조 분해 할당은 사용하는 쪽에서 변수 이름을 자유롭게 정할 수 있다.
+
+```jsx
+const [count, setCount] = useState(0);
+const [name, setName] = useState("");
+const [isOpen, setIsOpen] = useState(false);
+```
+
+만약 객체를 반환했다면 이름을 바꾸기 위해 별칭을 사용해야 한다.
+
+```jsx
+const { value: count, setter: setCount } = useStateLikeObject(0);
+```
+
+배열은 순서만 맞추면 되기 때문에, Hook처럼 정해진 개수의 값을 반환하는 경우에 사용하기 좋다.
+
+### 기본값 설정
+
+배열 구조 분해 할당에서는 기본값을 설정할 수 있다.
+
+```js
+const numbers = [1];
+
+const [first, second = 2] = numbers;
+
+console.log(first); // 1
+console.log(second); // 2
+```
+
+배열에 해당 위치의 값이 없거나 `undefined`라면 기본값이 사용된다.
+
+```js
+const [a = 10] = [undefined];
+
+console.log(a); // 10
+```
+
+### 객체 구조 분해 할당
+
+객체 구조 분해 할당은 프로퍼티 이름을 기준으로 값을 꺼낸다.
+
+```js
+const user = {
+ name: "Kim",
+ age: 20,
+};
+
+const { name, age } = user;
+
+console.log(name); // "Kim"
+console.log(age); // 20
+```
+
+이름을 바꾸고 싶다면 별칭을 사용할 수 있다.
+
+```js
+const { name: userName } = user;
+
+console.log(userName); // "Kim"
+```
+
+### Babel과 트랜스파일
+
+구조 분해 할당은 비교적 최신 JavaScript 문법이다.
+구형 브라우저까지 지원해야 한다면 Babel 같은 도구를 통해 오래된 JavaScript 문법으로 변환할 수 있다.
+
+객체 구조 분해 할당, 전개 구문 등은 트랜스파일 결과가 상대적으로 길어질 수 있다.
+대부분의 현대 프론트엔드 개발에서는 크게 문제 되지 않지만, 라이브러리 개발이나 번들 크기에 민감한 환경에서는 고려할 수 있다.
+
+### 전개 구문에서 순서가 중요한 이유
+
+객체 전개 구문에서는 뒤에 오는 값이 앞의 값을 덮어쓰인다.
+
+```js
+const user = {
+ name: "Kim",
+ age: 20,
+};
+
+const updatedUser = {
+ ...user,
+ age: 21,
+};
+
+console.log(updatedUser); // { name: "Kim", age: 21 }
+```
+
+반대로 순서를 바꾸면 전개 구문의 값이 다시 덮어쓰인다.
+
+```js
+const updatedUser = {
+ age: 21,
+ ...user,
+};
+
+console.log(updatedUser); // { age: 20, name: "Kim" }
+```
+
+따라서 기존 값을 덮어쓸 것인지, 기존 값을 유지할 것인지에 따라 순서를 신경 써야 한다.
+
+React 상태 업데이트에서도 자주 사용된다.
+
+```jsx
+setUser({
+ ...user,
+ name: "Lee",
+});
+```
+
+---
+
+## 11. `forEach`
+
+`forEach`는 배열의 각 요소를 순회하면서 콜백 함수를 실행하는 메서드이다.
+
+```js
+const numbers = [1, 2, 3];
+
+numbers.forEach((number) => {
+ console.log(number);
+});
+```
+
+실행 결과는 다음과 같다.
+
+```txt
+1
+2
+3
+```
+
+### `forEach`의 반환 값
+
+`forEach`의 반환 값은 항상 `undefined`이다.
+
+```js
+const numbers = [1, 2, 3];
+
+const result = numbers.forEach((number) => {
+ return number * 2;
+});
+
+console.log(result); // undefined
+```
+
+새로운 배열이 필요하다면 `map`을 사용해야 한다.
+
+```js
+const doubled = numbers.map((number) => number * 2);
+
+console.log(doubled); // [2, 4, 6]
+```
+
+### `forEach`는 중간에 멈추기 어렵다
+
+`forEach`는 `break`나 `return`으로 순회를 중단할 수 없다.
+
+```js
+const numbers = [1, 2, 3, 4, 5];
+
+numbers.forEach((number) => {
+ if (number === 3) {
+ return;
+ }
+
+ console.log(number);
+});
+```
+
+위 코드의 `return`은 현재 콜백만 종료한다.
+전체 `forEach` 반복이 멈추는 것은 아니다.
+
+중간에 멈춰야 한다면 `for...of`, `some`, `every`, `find` 등을 사용하는 것이 좋다.
+
+```js
+for (const number of numbers) {
+ if (number === 3) {
+ break;
+ }
+
+ console.log(number);
+}
+```
+
+또는 조건에 맞는 값을 찾고 싶다면 `find`를 사용할 수 있다.
+
+```js
+const target = numbers.find((number) => number === 3);
+
+console.log(target); // 3
+```
+
+---
+
+## 12. JSX에서 삼항 연산자 말고 조건부 렌더링하기
+
+JSX에서는 삼항 연산자 외에도 여러 방식으로 조건부 렌더링을 구현할 수 있다.
+
+### `&&` 연산자 사용
+
+```jsx
+function UserMessage({ isLogin }) {
+ return
{isLogin &&
환영한다.
}
;
+}
+```
+
+조건이 `true`일 때만 오른쪽 JSX가 렌더링된다.
+
+### 함수를 사용한 조건부 렌더링
+
+```jsx
+function renderMessage(status) {
+ if (status === "loading") {
+ return
로딩 중이다.
;
+ }
+
+ if (status === "error") {
+ return
에러가 발생했습니다.
;
+ }
+
+ return
완료되었습니다.
;
+}
+
+function Page({ status }) {
+ return
{renderMessage(status)}
;
+}
+```
+
+조건이 많아질수록 JSX 안에 모든 조건을 넣기보다, 별도 함수나 컴포넌트로 분리하는 것이 더 읽기 좋다.
+
+### 객체 매핑 사용
+
+```jsx
+const statusMessage = {
+ loading:
로딩 중이다.
,
+ error:
에러가 발생했습니다.
,
+ success:
완료되었습니다.
,
+};
+
+function Page({ status }) {
+ return
{statusMessage[status]}
;
+}
+```
+
+가능은 하지만, 조건이 복잡해지면 오히려 가독성이 떨어질 수 있다.
+간단한 조건은 삼항 연산자나 `&&`를 사용하고, 복잡한 조건은 함수나 컴포넌트로 분리하는 것이 좋다.
+
+---
+
+## 13. TypeScript: `any` 대신 `unknown` 사용하기
+
+`unknown`은 TypeScript의 top type이다.
+즉, 어떤 값이든 `unknown` 타입 변수에 할당할 수 있다.
+
+```ts
+let value: unknown;
+
+value = 1;
+value = "hello";
+value = true;
+value = {};
+```
+
+하지만 `unknown` 타입의 값은 바로 사용할 수 없다.
+사용하기 전에 타입을 좁혀야 한다.
+
+### `any`의 문제점
+
+`any`는 타입 검사를 사실상 포기하는 타입이다.
+
+```ts
+function doSomething(callback: any) {
+ callback();
+}
+
+doSomething("hello");
+```
+
+TypeScript는 위 코드를 에러로 판단하지 않는다.
+하지만 실행 시점에는 `"hello"`는 함수가 아니기 때문에 에러가 발생한다.
+
+### `unknown`을 사용하면?
+
+```ts
+function doSomething(callback: unknown) {
+ callback();
+ // Error: 'callback' is of type 'unknown'
+}
+```
+
+`unknown`은 아직 어떤 타입인지 알 수 없기 때문에 바로 호출할 수 없다.
+이 값을 사용하려면 타입 검사를 먼저 해야 한다.
+
+```ts
+function doSomething(callback: unknown) {
+ if (typeof callback === "function") {
+ callback();
+ return;
+ }
+
+ throw new Error("callback은 함수여야 한다.");
+}
+```
+
+이렇게 하면 예상치 못한 타입이 들어와도 안전하게 처리할 수 있다.
+
+### `unknown`을 사용하면 좋은 상황
+
+외부에서 들어오는 값은 타입을 확신하기 어렵다.
+
+- API 응답
+- `JSON.parse` 결과
+- 사용자 입력
+- 외부 라이브러리에서 받은 값
+- `catch`문의 에러 값
+
+이런 값은 처음에는 `unknown`으로 받아두고, 타입을 좁힌 뒤 사용하는 것이 안전한다.
+
+```ts
+try {
+ throw new Error("에러 발생");
+} catch (error: unknown) {
+ if (error instanceof Error) {
+ console.log(error.message);
+ }
+}
+```
+
+### 정리
+
+`any`는 TypeScript의 타입 안정성을 무너뜨릴 수 있다.
+반면 `unknown`은 값을 바로 사용하지 못하게 막고, 타입 검사를 강제한다.
+따라서 타입을 확신할 수 없는 값에는 `any`보다 `unknown`을 사용하는 것이 좋다.
+
+---