<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>frontendDeveloper</title>
    <link>https://cwnsgh.tistory.com/</link>
    <description>Colorless green ideas sleep furiously.</description>
    <language>ko</language>
    <pubDate>Thu, 25 Jun 2026 13:51:21 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>쮸롱이</managingEditor>
    <image>
      <title>frontendDeveloper</title>
      <url>https://tistory1.daumcdn.net/tistory/7790838/attach/b28952c91c4f4c10923235627a886c3d</url>
      <link>https://cwnsgh.tistory.com</link>
    </image>
    <item>
      <title>React Query 파헤치기</title>
      <link>https://cwnsgh.tistory.com/entry/React-Query-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만입니다. 리액트 쿼리 공부좀하고 왔습니다. 제가 이해한걸 설명해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 프로젝트에서 서버 데이터를 가져오는 일은 누구나 합니다.&lt;br /&gt;우리는 주로 axios, useEffect, useState 조합으로 이렇게 짜왔습니다.&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  axios.get('/todos')
    .then(res =&amp;gt; setTodos(res.data))
    .catch(err =&amp;gt; setError(err))
    .finally(() =&amp;gt; setLoading(false));
}, []);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 간단해 보이지만,&lt;br /&gt;화면이 늘어나고 요청이 많아지면 &lt;b&gt;버그, 반복, 복잡도&lt;/b&gt;가 쌓이기 시작합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 등장한 게 바로 &lt;b&gt;React Query&lt;/b&gt;입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;React Query란?&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; font-size: 16px; letter-spacing: 0px;&quot;&gt;서버 상태(Server State)를 자동으로 관리해주는 &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;React 라이브러리입니다.&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요청 &amp;rarr; 로딩 &amp;rarr; 성공/에러 처리 &amp;rarr; 캐시 &amp;rarr; 재요청 &amp;rarr; 공유&lt;/b&gt;&lt;br /&gt;이 모든 과정을 개발자가 직접 구현하지 않아도 되게 도와줍니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  axios만 써도 되지 않나요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 됩니다. 실제로 비교해보면 이렇게 차이가 납니다:&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;axios만 사용 시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 상태 관리(loading, error, data)를 직접 구현해야 함&lt;/li&gt;
&lt;li&gt;요청이 중복되면 반복 코드 발생&lt;/li&gt;
&lt;li&gt;캐시, 포커스 리패치, 공유 같은 고급 기능은 직접 짜야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;React Query 사용 시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;10줄 이내&lt;/b&gt;로 모든 기능 자동화&lt;/li&gt;
&lt;li&gt;상태 자동 관리 (isLoading, error, refetch 등 제공)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;캐싱&lt;/b&gt;, &lt;b&gt;재요청&lt;/b&gt;, &lt;b&gt;데이터 공유&lt;/b&gt;, &lt;b&gt;조건부 요청&lt;/b&gt; 자동 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 차이점 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목 axios만 사용 시 React Query 사용 시&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;개발 시간&lt;/td&gt;
&lt;td&gt;모든 로직 직접 구현 (수십~수백 줄)&lt;/td&gt;
&lt;td&gt;한 줄로 자동화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;버그 가능성&lt;/td&gt;
&lt;td&gt;높음 (상태 누락, 중복 등)&lt;/td&gt;
&lt;td&gt;낮음 (검증된 방식)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일관성&lt;/td&gt;
&lt;td&gt;팀마다 다른 스타일&lt;/td&gt;
&lt;td&gt;통일된 패턴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;유지보수&lt;/td&gt;
&lt;td&gt;변경 시 전체 수정&lt;/td&gt;
&lt;td&gt;설정만 바꾸면 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;고급 기능&lt;/td&gt;
&lt;td&gt;수동 구현&lt;/td&gt;
&lt;td&gt;기본 제공 (캐시, 포커스 리패치 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;❗ React Query는 마치 &lt;b&gt;자전거 대신 자동차를 쓰는 것과 같다.&lt;/b&gt;&lt;br /&gt;이동은 둘 다 가능하지만, &lt;b&gt;속도와 효율, 편안함은 비교 불가&lt;/b&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기본 사용법&lt;/h2&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;const { data, isLoading, error, refetch } = useQuery({
  queryKey: ['todos'],              // 고유 키
  queryFn: fetchTodos,             // 요청 함수
  enabled: true,                   // 기본값: true
  staleTime: 0,                    // 기본값: 0ms (즉시 stale)
  cacheTime: 300000,               // 기본값: 5분
  refetchOnWindowFocus: true,      // 기본값: true
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;staleTime이 0이면 그냥 axios랑 똑같은 거 아님?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;아닙니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;staleTime: 0이면 받아온 데이터를 &lt;b&gt;바로 stale(구식)&lt;/b&gt; 처리하지만,&lt;br /&gt;그럼에도 불구하고 다음 기능들은 &lt;b&gt;axios에는 없는 장점&lt;/b&gt;입니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동 상태관리 (isLoading, error, isFetching)&lt;/li&gt;
&lt;li&gt;캐시 유지 (cacheTime 동안)&lt;/li&gt;
&lt;li&gt;포커스 복귀 시 자동 재요청&lt;/li&gt;
&lt;li&gt;쿼리 키 기반 공유 (다른 컴포넌트에서도 같은 데이터 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론:&lt;/b&gt; staleTime: 0이라도 React Query는 여전히 똑똑합니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;리액트 쿼리없이 리액트 쿼리의 동작을 axios로 만드려면 코드가&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751445216378&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function TodoList() {
  const [todos, setTodos] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [isFetching, setIsFetching] = useState(false);

  const fetchTodos = async (isBackground = false) =&amp;gt; {
    if (isBackground) {
      setIsFetching(true);
    } else {
      setLoading(true);
    }
    
    try {
      const response = await axios.get('/api/todos');
      setTodos(response.data);
      setError(null);
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
      setIsFetching(false);
    }
  };

  // 재시도 로직
  const fetchWithRetry = async (retries = 3) =&amp;gt; {
    for (let i = 0; i &amp;lt; retries; i++) {
      try {
        await fetchTodos();
        break;
      } catch (err) {
        if (i === retries - 1) throw err;
        await new Promise(resolve =&amp;gt; setTimeout(resolve, 1000 * (i + 1)));
      }
    }
  };

  // 포커스 시 백그라운드 업데이트
  useEffect(() =&amp;gt; {
    const handleFocus = () =&amp;gt; {
      fetchTodos(true); // 백그라운드 업데이트
    };
    
    window.addEventListener('focus', handleFocus);
    return () =&amp;gt; window.removeEventListener('focus', handleFocus);
  }, []);

  // 네트워크 재연결 시 업데이트
  useEffect(() =&amp;gt; {
    const handleOnline = () =&amp;gt; {
      fetchTodos(true);
    };
    
    window.addEventListener('online', handleOnline);
    return () =&amp;gt; window.removeEventListener('online', handleOnline);
  }, []);

  useEffect(() =&amp;gt; {
    fetchWithRetry();
  }, []);

  if (loading) return &amp;lt;div&amp;gt;로딩 중...&amp;lt;/div&amp;gt;;
  if (error) return &amp;lt;div&amp;gt;에러: {error.message}&amp;lt;/div&amp;gt;;
  
  return (
    &amp;lt;div&amp;gt;
      {isFetching &amp;amp;&amp;amp; &amp;lt;div&amp;gt;업데이트 중...&amp;lt;/div&amp;gt;}
      {todos.map(todo =&amp;gt; &amp;lt;div key={todo.id}&amp;gt;{todo.title}&amp;lt;/div&amp;gt;)}
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 험악해집니다. 하지만 리액트 쿼리를 쓰면 ?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751445265858&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function TodoList() {
  const { data: todos, isLoading, isFetching, error } = useQuery({
    queryKey: ['todos'],
    queryFn: () =&amp;gt; axios.get('/api/todos').then(res =&amp;gt; res.data),
    retry: 3,
    retryDelay: 1000,
  });

  if (isLoading) return &amp;lt;div&amp;gt;로딩 중...&amp;lt;/div&amp;gt;;
  if (error) return &amp;lt;div&amp;gt;에러: {error.message}&amp;lt;/div&amp;gt;;
  
  return (
    &amp;lt;div&amp;gt;
      {isFetching &amp;amp;&amp;amp; &amp;lt;div&amp;gt;업데이트 중...&amp;lt;/div&amp;gt;}
      {todos?.map(todo =&amp;gt; &amp;lt;div key={todo.id}&amp;gt;{todo.title}&amp;lt;/div&amp;gt;)}
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;편--------안 합니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다른 컴포넌트에서도 데이터 공유?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;YES.&lt;br /&gt;React Query는 &lt;b&gt;queryKey가 같으면 동일한 캐시 데이터를 공유&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 A, B 두 컴포넌트가 동시에 아래처럼 선언했다면:&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;useQuery({ queryKey: ['todos'], queryFn: fetchTodos });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A에서 데이터를 불러오면 &amp;rarr; B도 &lt;b&gt;같은 데이터, 같은 상태를 바로 사용&lt;/b&gt;합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실제로 어떻게 구조화할까?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추천 폴더 구조&lt;/h3&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;src/
├── api/
│   └── todos.ts           &amp;larr; axios 요청 정의
├── hooks/
│   └── useTodos.ts        &amp;larr; useQuery 커스텀 훅
├── pages/
│   └── TodosPage.tsx      &amp;larr; 실제 화면
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  api/todos.ts&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import axios from 'axios';

export const fetchTodos = () =&amp;gt; axios.get('/api/todos').then(res =&amp;gt; res.data);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  hooks/useTodos.ts&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { useQuery } from '@tanstack/react-query';
import { fetchTodos } from '../api/todos';

export const useTodos = () =&amp;gt;
  useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodos,
    staleTime: 60000, // 1분 동안 fresh
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  pages/TodosPage.tsx&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { useTodos } from '../hooks/useTodos';

export default function TodosPage() {
  const { data, isLoading, error } = useTodos();

  if (isLoading) return &amp;lt;p&amp;gt;로딩 중...&amp;lt;/p&amp;gt;;
  if (error) return &amp;lt;p&amp;gt;에러 발생!&amp;lt;/p&amp;gt;;

  return (
    &amp;lt;ul&amp;gt;
      {data.map(todo =&amp;gt; &amp;lt;li key={todo.id}&amp;gt;{todo.title}&amp;lt;/li&amp;gt;)}
    &amp;lt;/ul&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;캐시 꺼내 쓰기 &amp;amp; 수동 갱신&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { useQueryClient } from '@tanstack/react-query';

const queryClient = useQueryClient();

// 캐시 데이터 읽기
const todos = queryClient.getQueryData(['todos']);

// 강제로 다시 요청
queryClient.invalidateQueries(['todos']);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;React Query의 기본값 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 쿼리 옵션 기본값 설명을 다시 하자면&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;enabled&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;조건부 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;staleTime&lt;/td&gt;
&lt;td&gt;0ms&lt;/td&gt;
&lt;td&gt;즉시 stale 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cacheTime&lt;/td&gt;
&lt;td&gt;5분&lt;/td&gt;
&lt;td&gt;캐시 유지 시간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;refetchOnWindowFocus&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;포커스 시 자동 재요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;refetchOnMount&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;마운트 시 재요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;retry&lt;/td&gt;
&lt;td&gt;3회&lt;/td&gt;
&lt;td&gt;에러 시 재시도 횟수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론: React Query는 선택이 아닌 필수&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;데이터 요청&lt;/td&gt;
&lt;td&gt;자동화됨 (queryFn)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;로딩/에러 관리&lt;/td&gt;
&lt;td&gt;자동 제공 (isLoading, error)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;캐시 및 공유&lt;/td&gt;
&lt;td&gt;자동 처리 (queryKey 기반)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;서버와 최신 동기화&lt;/td&gt;
&lt;td&gt;staleTime, refetchOnWindowFocus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;개발 생산성&lt;/td&gt;
&lt;td&gt;획기적 향상&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;React Query는 더 빠르고, 안전하고, 일관된 프론트엔드 개발을 가능하게 해줍니다.&lt;/b&gt;&lt;br /&gt;axios만으로도 되긴 하지만, &lt;b&gt;자동차 대신 자전거 타는 것과 같기 때문입니다. &lt;span style=&quot;color: #ee2323;&quot;&gt;자동차를 삽시다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>React</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/31</guid>
      <comments>https://cwnsgh.tistory.com/entry/React-Query-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0#entry31comment</comments>
      <pubDate>Wed, 2 Jul 2025 17:39:21 +0900</pubDate>
    </item>
    <item>
      <title>[컴퓨터구조] CPU와 I/O 장치의 접속</title>
      <link>https://cwnsgh.tistory.com/entry/%EC%BB%B4%ED%93%A8%ED%84%B0%EA%B5%AC%EC%A1%B0-CPU%EC%99%80-IO-%EC%9E%A5%EC%B9%98%EC%9D%98-%EC%A0%91%EC%86%8D</link>
      <description>&lt;div&gt;
&lt;h2 id=&quot;cpu-io&quot; data-ke-size=&quot;size26&quot;&gt;CPU와 I/O 장치의 접속&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터를 이루는 다양한 부품 중, &lt;b&gt;CPU&lt;/b&gt;와 &lt;b&gt;I/O(입출력) 장치&lt;/b&gt;의 연결 구조는 시스템의 효율성과 확장성을 좌우하는 핵심 요소입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키보드, 마우스, 프린터, 하드디스크, SSD 등 모든 주변장치는 CPU와 직접 연결되지 않고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 장치별 제어기(컨트롤러)를 통해 접속됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 CPU와 I/O 장치, 그리고 보조저장장치가 어떻게 연결되어 데이터를 주고받는지, 실제 예시를 곁들여 쉽게 설명해봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3899&quot; data-origin-height=&quot;2788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ULwWf/btsNCoyrqOt/dtqZ5iiV2qxQ5eZERq6ok0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ULwWf/btsNCoyrqOt/dtqZ5iiV2qxQ5eZERq6ok0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ULwWf/btsNCoyrqOt/dtqZ5iiV2qxQ5eZERq6ok0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FULwWf%2FbtsNCoyrqOt%2FdtqZ5iiV2qxQ5eZERq6ok0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;652&quot; height=&quot;466&quot; data-origin-width=&quot;3899&quot; data-origin-height=&quot;2788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 키보드 입력: 데이터의 첫걸음&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;키보드&lt;/b&gt;에서 키를 누르면 그 신호는 바로 CPU로 가지 않습니다.&lt;br /&gt;먼저, 키보드 내부의 제어기(컨트롤러)가 눌린 키에 해당하는 &lt;b&gt;8비트 데이터&lt;/b&gt;(예: 'A' 키는 01000001)를 &lt;b&gt;데이터 레지스터&lt;/b&gt;에 저장합니다.&lt;br /&gt;동시에, &lt;b&gt;상태 레지스터&lt;/b&gt;의 특정 비트(여기서는 In_RDY 비트)가 1로 세트됩니다.&lt;br /&gt;이 비트가 1이 된다는 것은 &quot;입력 데이터가 준비되었다&quot;는 신호입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CPU의 역할은?&lt;/b&gt;&lt;br /&gt;CPU는 키보드로부터 데이터를 읽고 싶을 때, 먼저 &lt;b&gt;상태 레지스터&lt;/b&gt;의 In_RDY 비트를 읽어봅니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 In_RDY가 1이면, CPU는 즉시 &lt;b&gt;데이터 레지스터&lt;/b&gt;의 값을 읽어와 처리합니다.&lt;/li&gt;
&lt;li&gt;만약 In_RDY가 0이면, CPU는 계속해서 상태 레지스터를 읽고 검사하는 과정을 반복합니다(이 과정을 &lt;b&gt;폴링&lt;/b&gt;이라고 부릅니다).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 'A' 키를 누름 &amp;rarr; 키보드 제어기 데이터 레지스터에 01000001 저장, In_RDY=1&lt;/li&gt;
&lt;li&gt;CPU가 In_RDY=1을 확인 &amp;rarr; 데이터 레지스터에서 01000001을 읽어옴&lt;/li&gt;
&lt;li&gt;CPU가 데이터를 읽으면 In_RDY는 다시 0으로 리셋됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 프린터 출력: 준비된 만큼만 보낸다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프린터&lt;/b&gt;의 경우도 비슷합니다.&lt;br /&gt;CPU는 프린터로 데이터를 보내기 전에, 먼저 &lt;b&gt;프린터 제어기&lt;/b&gt;의 &lt;b&gt;상태 레지스터&lt;/b&gt;에서 Out_RDY 비트를 확인합니다.&lt;br /&gt;이 비트가 1이면 프린터가 새로운 데이터를 받을 준비가 된 상태입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Out_RDY가 1이면, CPU는 &lt;b&gt;프린터 제어기&lt;/b&gt;의 &lt;b&gt;데이터 레지스터&lt;/b&gt;에 출력할 데이터를 씁니다.&lt;/li&gt;
&lt;li&gt;그 후, 프린터 제어기가 프린터 하드웨어를 작동시켜 인쇄를 시작합니다.&lt;/li&gt;
&lt;li&gt;만약 Out_RDY가 0이라면, CPU는 다시 준비될 때까지 상태 레지스터를 반복적으로 검사합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프린터가 &quot;Hello&quot;를 출력할 때, 한 글자씩 Out_RDY 비트가 1인지 확인하고, 1일 때만 데이터를 보냅니다.&lt;/li&gt;
&lt;li&gt;만약 프린터가 인쇄 중이거나 종이가 걸렸다면 Out_RDY=0, CPU는 대기&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3329&quot; data-origin-height=&quot;1925&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/31qnd/btsNBDbKPj1/GTdIKo2N4GBdfoXjAfbMJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/31qnd/btsNBDbKPj1/GTdIKo2N4GBdfoXjAfbMJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/31qnd/btsNBDbKPj1/GTdIKo2N4GBdfoXjAfbMJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F31qnd%2FbtsNBDbKPj1%2FGTdIKo2N4GBdfoXjAfbMJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;628&quot; height=&quot;363&quot; data-origin-width=&quot;3329&quot; data-origin-height=&quot;1925&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 데이터 레지스터와 버퍼: 임시 저장소의 힘&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 레지스터&lt;/b&gt;는 CPU와 I/O 장치 사이에서 데이터를 잠깐 저장하는 &lt;b&gt;임시 저장소(버퍼)&lt;/b&gt; 역할을 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키보드나 프린터처럼 데이터가 적은 장치는 1바이트~몇 바이트의 버퍼만 있어도 충분합니다.&lt;/li&gt;
&lt;li&gt;하지만 프린터에서 한 번에 수십 MB의 데이터를 인쇄할 때, 버퍼(프린터 메모리)를 크게 하면 CPU가 자주 개입하지 않아도 되어 전체 시스템 효율이 높아집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 보조저장장치(하드디스크, SSD): 블록 단위 전송&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하드디스크&lt;/b&gt;나 &lt;b&gt;SSD&lt;/b&gt; 같은 보조저장장치는 키보드와 달리 &lt;b&gt;블록 단위&lt;/b&gt;(예: 512, 1024, 4096바이트)로 데이터를 전송합니다.&lt;br /&gt;이 때문에 제어기 내부에는 한 블록 이상을 저장할 수 있는 &lt;b&gt;데이터 버퍼&lt;/b&gt;가 필요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 디스크 제어기는 한 트랙 전체(수십 KB~수백 KB)를 저장할 수 있는 &lt;b&gt;트랙 버퍼&lt;/b&gt;나, 그보다 더 큰 &lt;b&gt;디스크 버퍼&lt;/b&gt;를 갖추고 있습니다.&lt;/li&gt;
&lt;li&gt;이렇게 하면 디스크에서 데이터를 읽어올 때 한 번에 많은 데이터를 버퍼에 담아두고, CPU는 필요한 만큼만 가져다 쓸 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. CPU와 I/O 제어기 간의 통신: 주소로 구분한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU는 직접 I/O 장치를 제어하지 않고, **각 장치의 제어기(컨트롤러)**에 명령을 보냅니다.&lt;br /&gt;이를 위해 &lt;b&gt;제어기 내부의 상태 레지스터와 데이터 레지스터&lt;/b&gt;를 메모리처럼 한 단어(4바이트 등) 크기의 저장소로 간주하고, 각각에 &lt;b&gt;고유한 주소&lt;/b&gt;를 부여합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 키보드 제어기의 데이터 레지스터는 0xFFD20000, 상태 레지스터는 0xFFD20004와 같이 주소가 할당될 수 있습니다.&lt;/li&gt;
&lt;li&gt;CPU는 이 주소로 데이터를 읽거나 쓸 수 있습니다. (이 방식을 &lt;b&gt;메모리 매핑 I/O&lt;/b&gt;라고 합니다)&lt;/li&gt;
&lt;li&gt;CPU의 주소버스와 제어신호가 I/O 제어기로 연결되는 이유가 바로 여기에 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU와 I/O 장치는 직접 연결되지 않고, 각 장치별 제어기를 통해 접속된다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태 레지스터&lt;/b&gt;와 &lt;b&gt;데이터 레지스터&lt;/b&gt;를 통해 데이터 준비 여부와 실제 데이터를 주고받는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;버퍼&lt;/b&gt;(데이터 레지스터)는 임시 저장소 역할을 하며, 크기가 클수록 CPU 개입이 줄어든다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보조저장장치는 블록 단위로 데이터를 전송&lt;/b&gt;하며, 큰 버퍼를 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;각 제어기 레지스터에 주소를 할당&lt;/b&gt;하여 CPU가 메모리처럼 쉽게 접근할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 CPU와 I/O 장치, 그리고 보조저장장치 사이의 접속 구조는 컴퓨터가 다양한 장치와 효율적으로 소통할 수 있게 해주는 핵심 원리입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;요약&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;I/O 장치와 보조저장장치 모두 CPU와 직접 연결되지 않고, 각 장치별 컨트롤러(제어기)를 통해 접속된다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;키보드 입력 과정&lt;/b&gt;: 키가 눌리면 8비트 데이터가 키보드 제어기의 데이터 레지스터에 저장되고, 상태 레지스터의 In_RDY 비트가 세트된다. CPU는 In_RDY 비트를 반복적으로 검사(폴링)하여 데이터가 준비되면 읽어들인다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프린터 출력 과정&lt;/b&gt;: CPU가 프린터 제어기의 Out_RDY 비트를 검사해 출력 준비가 되었는지 확인하고, 준비되면 데이터를 데이터 레지스터에 써서 프린터로 전송한다. Out_RDY가 세트되지 않았으면 반복 검사한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 레지스터는 CPU와 I/O 장치 사이의 임시 저장소(버퍼) 역할을 한다.&lt;/b&gt;&amp;nbsp;버퍼 크기를 늘리면 CPU 개입을 줄일 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보조저장장치는 블록 단위로 데이터가 전송되며, 제어기 내에 블록 또는 트랙 단위의 데이터 버퍼가 존재한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU는 각 I/O 제어기의 레지스터에 주소를 할당해, 메모리처럼 읽고 쓸 수 있다.&lt;/b&gt;&amp;nbsp;주소버스와 제어신호가 I/O 제어기와 연결된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;단어 정리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;- 데이터 레지스터 : CPU와 I/O 장치간의 임시 데이터 기억장치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;- 상태 레지스터 : I/O 장치의 상태를 나타내는 비트들을 저장하는 레지스터&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;- 데이터 버퍼 : CPU와 I/O 장치간의 데이터 임시 기억장치인 데이터 레지스터의 다른 명칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/컴퓨터구조</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/19</guid>
      <comments>https://cwnsgh.tistory.com/entry/%EC%BB%B4%ED%93%A8%ED%84%B0%EA%B5%AC%EC%A1%B0-CPU%EC%99%80-IO-%EC%9E%A5%EC%B9%98%EC%9D%98-%EC%A0%91%EC%86%8D#entry19comment</comments>
      <pubDate>Sun, 27 Apr 2025 22:41:51 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 가지는 치지만 분할은 어려운 사람.</title>
      <link>https://cwnsgh.tistory.com/entry/%EA%B0%80%EC%A7%80%EB%A5%BC-%EC%B9%98%EC%A7%80-%EB%AA%BB%ED%95%98%EB%8A%94-%EC%82%AC%EB%9E%8C</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5iOKQ/btsNwS80WRy/IUyO3DJKp6llKN5uli0oR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5iOKQ/btsNwS80WRy/IUyO3DJKp6llKN5uli0oR1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;832&quot; data-filename=&quot;kakao_screenshot1745471604900.png&quot; width=&quot;340&quot; height=&quot;556&quot; data-widthpercent=&quot;41.49&quot; style=&quot;width: 41.0084%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5iOKQ/btsNwS80WRy/IUyO3DJKp6llKN5uli0oR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5iOKQ%2FbtsNwS80WRy%2FIUyO3DJKp6llKN5uli0oR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;509&quot; height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qWhOR/btsNyGFyJtx/XW9a9thySP1kXYfxKFeLqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qWhOR/btsNyGFyJtx/XW9a9thySP1kXYfxKFeLqk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;590&quot; data-filename=&quot;kakao_screenshot1745471622700.png&quot; width=&quot;428&quot; height=&quot;496&quot; style=&quot;width: 57.8288%;&quot; data-widthpercent=&quot;58.51&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qWhOR/btsNyGFyJtx/XW9a9thySP1kXYfxKFeLqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqWhOR%2FbtsNyGFyJtx%2FXW9a9thySP1kXYfxKFeLqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;509&quot; height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;moo..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;moo게임을 풀어보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이문제는 재귀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745471907458&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const input = require(&quot;fs&quot;)
  .readFileSync(process.platform === &quot;linux&quot; ? &quot;/dev/stdin&quot; : &quot;./input.txt&quot;)
  .toString()
  .trim();

const N = Number(input);

function makeMoo(n) {
  if (n === 1) return &quot;moo&quot;;
  const prev = makeMoo(n - 1);
  return prev + &quot;m&quot; + &quot;o&quot;.repeat(n + 2) + prev;
}
const str = makeMoo(N);
console.log(str[N]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀를 위풍당당 야무지게 돌렸지만&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;87&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FGmuw/btsNw1j1K0c/thbznY55DNFLHuDX6W1NA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FGmuw/btsNw1j1K0c/thbznY55DNFLHuDX6W1NA0/img.png&quot; data-alt=&quot;재귀는 조심해야해..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FGmuw/btsNw1j1K0c/thbznY55DNFLHuDX6W1NA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFGmuw%2FbtsNw1j1K0c%2FthbznY55DNFLHuDX6W1NA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;711&quot; height=&quot;87&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;87&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;재귀는 조심해야해..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  하지만 재귀에는 함정이 있어요!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는... S(n)의 길이가 &lt;b&gt;기하급수적으로 커진다&lt;/b&gt;는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 S(10)을 만들면 거의 &lt;b&gt;수십억 글자&lt;/b&gt;가 되기 때문에, 이 코드는 메모리도 터지고 시간도 오래 걸립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;❓그럼 어떻게 하면 좋을까요?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;바로바로 &lt;b&gt;분할정복&lt;/b&gt;입니다!&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  분할정복이란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 &lt;b&gt;작은 문제로 나누고(Divide)&lt;/b&gt;,&lt;br /&gt;각각 해결한 뒤 정복(Conquer) 하여 전체 문제를 푸는 방법입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Moo 게임에서는 S(n)이 항상&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;S(n) = S(n - 1) + &quot;m&quot; + &quot;o&quot;.repeat(n + 2) + S(n - 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처럼 &lt;b&gt;좌-중앙-우 구조&lt;/b&gt;로 반복되니까,&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;내가 찾는 글자가 어느 쪽에 있는지&quot;만 판단하면&lt;/b&gt;&lt;br /&gt;&lt;b&gt;실제로 문자열을 만들 필요가 없습니다!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  문자열의 길이를 먼저 계산해보자&lt;/h2&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;function getLength(k) {
  if (k === 0) return 3; // S(0) = &quot;moo&quot;
  return 2 * getLength(k - 1) + k + 3;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getLength(k)는 S(k)의 총 길이를 구해줍니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  위치만 추적해서 찾기!&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;function findMoo(k, n) {
  if (k === 0) return &quot;moo&quot;[n - 1];

  const left = getLength(k - 1);
  const middle = k + 3;

  if (n &amp;lt;= left) {
    return findMoo(k - 1, n); // 왼쪽
  } else if (n &amp;lt;= left + middle) {
    return n === left + 1 ? &quot;m&quot; : &quot;o&quot;; // 가운데
  } else {
    return findMoo(k - 1, n - left - middle); // 오른쪽
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 어디에 속하는지만 판단해서 &lt;b&gt;필요한 부분만 재귀&lt;/b&gt;!&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  전체 코드 (최적화 버전)&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const input = require(&quot;fs&quot;)
  .readFileSync(process.platform === &quot;linux&quot; ? &quot;/dev/stdin&quot; : &quot;./input.txt&quot;)
  .toString()
  .trim();

const N = Number(input);

function getLength(k) {
  if (k === 0) return 3;
  return 2 * getLength(k - 1) + k + 3;
}

function findMoo(k, n) {
  if (k === 0) return &quot;moo&quot;[n - 1];

  const left = getLength(k - 1);
  const middle = k + 3;

  if (n &amp;lt;= left) return findMoo(k - 1, n);
  else if (n &amp;lt;= left + middle) return n === left + 1 ? &quot;m&quot; : &quot;o&quot;;
  else return findMoo(k - 1, n - left - middle);
}

// 최소한의 k 찾기
let k = 0;
while (getLength(k) &amp;lt; N) k++;

console.log(findMoo(k, N));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정리!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 특징 결과&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;재귀로 문자열 생성&lt;/td&gt;
&lt;td&gt;실제 문자열을 만들어버림&lt;/td&gt;
&lt;td&gt;❌ 비효율적, 메모리 초과&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;분할정복&lt;/td&gt;
&lt;td&gt;위치만 추적해서 해결&lt;/td&gt;
&lt;td&gt;✅ 효율적, 깔끔함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;157&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q8uW7/btsNzgmkPOd/KpEzLArRamGedL9OsDl76k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q8uW7/btsNzgmkPOd/KpEzLArRamGedL9OsDl76k/img.png&quot; data-alt=&quot;moo !&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q8uW7/btsNzgmkPOd/KpEzLArRamGedL9OsDl76k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq8uW7%2FbtsNzgmkPOd%2FKpEzLArRamGedL9OsDl76k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;939&quot; height=&quot;157&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;157&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;moo !&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JavaScript/알고리즘</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/18</guid>
      <comments>https://cwnsgh.tistory.com/entry/%EA%B0%80%EC%A7%80%EB%A5%BC-%EC%B9%98%EC%A7%80-%EB%AA%BB%ED%95%98%EB%8A%94-%EC%82%AC%EB%9E%8C#entry18comment</comments>
      <pubDate>Thu, 24 Apr 2025 14:12:33 +0900</pubDate>
    </item>
    <item>
      <title>[컴퓨터구조] CPU와 기억장치의 접속</title>
      <link>https://cwnsgh.tistory.com/entry/%EC%BB%B4%ED%93%A8%ED%84%B0%EA%B5%AC%EC%A1%B0-CPU%EC%99%80-%EA%B8%B0%EC%96%B5%EC%9E%A5%EC%B9%98%EC%9D%98-%EC%A0%91%EC%86%8D</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;CPU와 기억장치의 접속&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2264&quot; data-origin-height=&quot;1576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oYSAd/btsNvecShT1/y3qWKqgKyDl0uLIHTkSNWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oYSAd/btsNvecShT1/y3qWKqgKyDl0uLIHTkSNWK/img.png&quot; data-alt=&quot;cpu와 시스템버스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oYSAd/btsNvecShT1/y3qWKqgKyDl0uLIHTkSNWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoYSAd%2FbtsNvecShT1%2Fy3qWKqgKyDl0uLIHTkSNWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;566&quot; height=&quot;394&quot; data-origin-width=&quot;2264&quot; data-origin-height=&quot;1576&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;cpu와 시스템버스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림은 CPU와 시스템 내의 다른 요소들 사이에 정보를 교환하는 통로가 되는 &lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;시스템 버스&lt;/span&gt;&lt;/b&gt;를 보여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;주소 버스(adress bus)&lt;/b&gt;&lt;/span&gt;는 CPU가 외부로 발생하는 주소 정보를 전송하는 신호 선들의 집합입니다. 각 주소 선은 하나의 주소 비트를 전송하는 데 사용되며, 전체 주소 선들의 개수가 CPU와 접속될 수 있는 최대 기억장치 용량을 결정해준다. CPU가 발생하는 주소 비트들의 수를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주소 버스의 폭(width)라고 하는데, 그 폭이 16비트라면 최대 65,536개 (즉 64K개) 기억 장소들의 주소를 지정해줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;데이터 버스(data bus)&lt;/span&gt;&lt;/b&gt;는 CPU가 기억장치 혹은 I/O 장치와의 사이에 데이터를 전송하기 위한 신호 선들의 집합입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 버스의 폭은 한 번에 전송될 수 있는 데이터 비트의 수를 결정해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;제어 버스(control bus)&lt;/b&gt;&lt;/span&gt;는 CPU가 시스템 내의 각종 요소들의 동작을 제어하는데 필요한 신호 선들의 집합입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 제어 신호들로는 기억장치 읽기/쓰기 신호와 I/O 읽기/쓰기 신호가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSflzf/btsNwKJrzxl/6hJxneJ4yEExYkYxvTAks1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSflzf/btsNwKJrzxl/6hJxneJ4yEExYkYxvTAks1/img.png&quot; data-alt=&quot;시스템버스 삼총사&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSflzf/btsNwKJrzxl/6hJxneJ4yEExYkYxvTAks1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSflzf%2FbtsNwKJrzxl%2F6hJxneJ4yEExYkYxvTAks1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;457&quot; height=&quot;513&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;시스템버스 삼총사&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;주소는 CPU에 의해 발생되어 기억장치와 I/O 장치로 보내지는 정보이기 때문에, 주소 버스는 단방향성입니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;데이터 버스는 읽기와 쓰기 동작을 모두 지원해야 하므로 양방향 전송이 가능해야합니다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU가 데이터를 기억장치의 특정 장소에 저장하거나 이미 저장되어 있는 내용을 읽는 동작을&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;엑세스(access)한다&lt;/b&gt;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;라고 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU가 특정 기억 장소로부터 데이터를 읽고자 할 때 기억장치로 보내줘야 하는 정보는 주소와 읽기 신호입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고는 데이터를 저장하려고하면 해당 기억 장소의 주소와 데이터 및 쓰기 신호를 보내주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 CPU와 기억장치 사이에는 그러한 정보들의 전송 통로인 주소버스, 데이터 버스 및 제어 신호 선들이 접속되어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;흐름을 알아봅시다&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU는 데이터를 저장할 기억 장소의 주소와 저장할 데이터를 각각 주소 버스와 데이터 버스를 통하여 보내면서 동시에 쓰기 신호를 활성화 시킵니다. 이때 CPU가 기억장치로 주소와 데이터를 보낸 순간부터 저장이 완료될 때까지의 시간을&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;기억장치 쓰기 시간&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;이라고 합니다.&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰기가있다면 읽기도있겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU가 기억장치로부터 데이터를 읽는 동작은, CPU가 데이터가 저장되어 있는 기억 장소의 주소를 주소 버스를 통하여 기억장치로 보내면서 동시에 읽기 신호를 활성화 시킵니다. 그러면 일정 지연 시간이 경과된 후에 기억장치로부터 읽혀진 데이터가 데이터 버스 상에 실리며, CPU는 그 데이터를 버스 인터페이스 회로를 통하여 읽어 들이게 됩니다. 여기서 지연 시간은 주소를 해독하는데 걸리는 시간과 기억장치 내부에서 데이터를 인출하는데 걸리는 시간을 합한 시간을 말합니다. 똑같이 CPU가 주소를 발생한 시간부터 읽기 동작이 완료될 때까지의 시간을&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;기억장치 읽기 시간&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하자면&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;90&quot; data-start=&quot;78&quot; data-ke-size=&quot;size23&quot;&gt;  쓰기 동작&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;320&quot; data-start=&quot;91&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;121&quot; data-start=&quot;91&quot;&gt;&lt;b&gt;CPU &amp;rarr; 메모리&lt;/b&gt;: 데이터를 저장하려는 동작&lt;/li&gt;
&lt;li data-end=&quot;275&quot; data-start=&quot;122&quot;&gt;&lt;b&gt;과정&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;275&quot; data-start=&quot;134&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;167&quot; data-start=&quot;134&quot;&gt;CPU가 저장할 &lt;b&gt;주소&lt;/b&gt;를 주소 버스를 통해 보냄.&lt;/li&gt;
&lt;li data-end=&quot;205&quot; data-start=&quot;170&quot;&gt;CPU가 &lt;b&gt;저장할 데이터&lt;/b&gt;를 데이터 버스를 통해 보냄.&lt;/li&gt;
&lt;li data-end=&quot;247&quot; data-start=&quot;208&quot;&gt;동시에 쓰기 제어 신호를 활성화.&lt;/li&gt;
&lt;li data-end=&quot;275&quot; data-start=&quot;250&quot;&gt;메모리는 해당 주소에 데이터를 저장.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li data-end=&quot;320&quot; data-start=&quot;276&quot;&gt;&lt;b&gt;소요 시간&lt;/b&gt;: 이 전체 과정에 걸리는 시간을 &lt;b&gt;쓰기 시간&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;325&quot; data-start=&quot;322&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;339&quot; data-start=&quot;327&quot; data-ke-size=&quot;size23&quot;&gt;  읽기 동작&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;630&quot; data-start=&quot;340&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;369&quot; data-start=&quot;340&quot;&gt;&lt;b&gt;메모리 &amp;rarr; CPU&lt;/b&gt;: 데이터를 불러오는 동작&lt;/li&gt;
&lt;li data-end=&quot;538&quot; data-start=&quot;370&quot;&gt;&lt;b&gt;과정&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;538&quot; data-start=&quot;382&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;417&quot; data-start=&quot;382&quot;&gt;CPU가 읽고 싶은 &lt;b&gt;주소&lt;/b&gt;를 주소 버스를 통해 보냄.&lt;/li&gt;
&lt;li data-end=&quot;458&quot; data-start=&quot;420&quot;&gt;동시에 읽기 제어 신호를 활성화.&lt;/li&gt;
&lt;li data-end=&quot;510&quot; data-start=&quot;461&quot;&gt;메모리는 해당 주소를 &lt;b&gt;해독&lt;/b&gt;하고, 데이터를 찾아서 &lt;b&gt;데이터 버스에 실음&lt;/b&gt;.&lt;/li&gt;
&lt;li data-end=&quot;538&quot; data-start=&quot;513&quot;&gt;CPU는 데이터 버스에서 그 값을 읽음.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li data-end=&quot;572&quot; data-start=&quot;539&quot;&gt;&lt;b&gt;지연 시간&lt;/b&gt;: 주소 해독 시간 + 데이터 인출 시간&lt;/li&gt;
&lt;li data-end=&quot;630&quot; data-start=&quot;573&quot;&gt;&lt;b&gt;소요 시간&lt;/b&gt;: CPU가 주소를 보낸 순간부터 읽기가 완료될 때까지의 시간 = &lt;b&gt;읽기 시간&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;여기서 궁금한게 읽기에는 지연시간이 있는데 왜 쓰기에는없지 ? 라는 궁금증이였다 (당연한건가..)&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;237&quot; data-start=&quot;201&quot; data-ke-size=&quot;size23&quot;&gt;  왜 읽기 지연은 강조되고, 쓰기 지연은 덜 강조될까?&lt;/h3&gt;
&lt;h4 data-end=&quot;273&quot; data-start=&quot;239&quot; data-ke-size=&quot;size20&quot;&gt;  읽기(Read) &amp;rarr; CPU가 &lt;b&gt;기다려야 함&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;399&quot; data-start=&quot;274&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;316&quot; data-start=&quot;274&quot;&gt;CPU가 메모리에서 데이터를 읽어야 &lt;b&gt;그 다음 연산을 할 수 있음&lt;/b&gt;.&lt;/li&gt;
&lt;li data-end=&quot;349&quot; data-start=&quot;317&quot;&gt;즉, 읽기 지연 시간은 CPU의 성능과 &lt;b&gt;직결됨&lt;/b&gt;.&lt;/li&gt;
&lt;li data-end=&quot;399&quot; data-start=&quot;350&quot;&gt;예: x = mem[0x1000] &amp;rarr; CPU는 mem에서 값이 올 때까지 기다림.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;440&quot; data-start=&quot;401&quot; data-ke-size=&quot;size20&quot;&gt;  쓰기(Write) &amp;rarr; CPU는 &lt;b&gt;기다리지 않아도 됨&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;617&quot; data-start=&quot;441&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;504&quot; data-start=&quot;441&quot;&gt;대부분의 시스템에서는, 쓰기 동작을 메모리에 요청한 뒤에 CPU는 &lt;b&gt;바로 다음 명령어를 수행&lt;/b&gt;할 수 있어.&lt;/li&gt;
&lt;li data-end=&quot;563&quot; data-start=&quot;505&quot;&gt;이건 &lt;b&gt;비동기적 쓰기 방식&lt;/b&gt; 또는 &lt;b&gt;쓰기 버퍼(write buffer)&lt;/b&gt; 같은 기술 때문임.&lt;/li&gt;
&lt;li data-end=&quot;617&quot; data-start=&quot;564&quot;&gt;예: mem[0x1000] = x &amp;rarr; CPU는 그냥 저장하라고만 지시하고, 자기 일 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 비동기 처리 느낌이였던것이다.&lt;/p&gt;</description>
      <category>CS/컴퓨터구조</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/17</guid>
      <comments>https://cwnsgh.tistory.com/entry/%EC%BB%B4%ED%93%A8%ED%84%B0%EA%B5%AC%EC%A1%B0-CPU%EC%99%80-%EA%B8%B0%EC%96%B5%EC%9E%A5%EC%B9%98%EC%9D%98-%EC%A0%91%EC%86%8D#entry17comment</comments>
      <pubDate>Thu, 24 Apr 2025 03:01:00 +0900</pubDate>
    </item>
    <item>
      <title>[컴퓨터구조] 정보의 표현과 저장</title>
      <link>https://cwnsgh.tistory.com/entry/1-%EC%BB%B4%ED%93%A8%ED%84%B0-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B0%9C%EC%9A%94-2</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 정보의 표현과 저장&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터가 받아들이고 처리하는 정보의 종류로는 &lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;프로그램 코드&lt;/span&gt;&lt;/b&gt;와 &lt;b&gt;&lt;span style=&quot;color: #a6bc00;&quot;&gt;데이터&lt;/span&gt;&lt;/b&gt;가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디지털 컴퓨터에서 그러한 정보들은 모두 2진수를 나타내는 비트들의 조합으로 표현된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 프로그램은 우리가 흔히 쓰는 C/C++,Python 같은 고급언어를 이용하여 작성하는데 우리는 이해하지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디지털 회로들로 이루어진 컴퓨터 하드웨어는 전혀 이해하지 못한다. 그래서 이 프로그램은 컴파일러 라고 부르는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어에 의해 하드웨어가 이해할 수 있는 언어로 번역된다. 이 때 번역된 언어를 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;기계어&lt;/b&gt;&lt;/span&gt; 혹은 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;기계코드&lt;/b&gt;&lt;/span&gt; 라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고급언어들은 어느 컴퓨터에서 사용되든 거의 동일하지만, 기계어는 CPU마다 서로 다르다.&lt;br /&gt;즉, CPU내부 구조에 따라 그 하드웨어가 이해할 수 있는 언어도 달라지는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러한 언어상의 차이를 해결하기 위하여 고급언어와 기계어 사이에는 각 CPU 고유의 중간언어가 존재하는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 언어를 어셈블리 언어 혹은 어셈블리 명령어 라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 이러한 언어로 작성된 프로그램을 어셈블리 프로그램이라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1413&quot; data-origin-height=&quot;931&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MsANP/btsNuYNZ4gy/aP3hwxA7tmp1MCmBzKiBsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MsANP/btsNuYNZ4gy/aP3hwxA7tmp1MCmBzKiBsk/img.png&quot; data-alt=&quot;고급-언어 프로그램이 기계어 프로그램으로 번역되는 과정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MsANP/btsNuYNZ4gy/aP3hwxA7tmp1MCmBzKiBsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMsANP%2FbtsNuYNZ4gy%2FaP3hwxA7tmp1MCmBzKiBsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1413&quot; height=&quot;931&quot; data-origin-width=&quot;1413&quot; data-origin-height=&quot;931&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;고급-언어 프로그램이 기계어 프로그램으로 번역되는 과정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 각 어셈블리 명령어가 지정하는 동작을 개략적으로 나타내는 기호인 'LOAD', 'ADD' 및 'STOR'을 니모닉스 라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어셈블리 언어로 작성된 프로그램은 어셈블러 라는 소프트웨어가 기계어 프로그램으로 번역해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일의 마지막 경과인 기계어 프로그램은 2진수로 이루어져있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 위의 LOAD A,X 명령어에 대한 기계어의 예를 들어보면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 56.3953%; height: 73px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 27.2164%; height: 38px;&quot;&gt;연산코드&lt;/td&gt;
&lt;td style=&quot;width: 29.179%; height: 38px;&quot;&gt;오퍼랜드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 35px;&quot;&gt;
&lt;td style=&quot;width: 27.2164%; height: 35px;&quot;&gt;001&lt;/td&gt;
&lt;td style=&quot;width: 29.179%; height: 35px;&quot;&gt;00101&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산코드 필드에 저장된 '001'은 '레지스터 A로 적재하라'는 연산을 지정해주는 비트들이며, 오퍼랜드 필드의 '00101'은 적재될 데이터가 저장되어 있는 기억장치 주소를 가리킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 기계어에서는 오퍼랜트가 '5'번지를 가리키고있다. 따라서 이 기계어는 '기억장치 5번지의 내용을 읽어서 레지스터 A에 저장하라'는 명령을 나타내는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령어는 비트들의 개수와 용도 및 주소지정 방식에 따라 다양하게 구성될 수 있다. 만약 위의 예와 같이 연산코드가 3비트로 이루어진다면 2의3승인 8가지의 연산들을 지정할 수 있다. 또한 오퍼랜드 비트등릐 수가 5개이므로 동일하게 기억 장소들의 최대수는 2의5승 32개이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 각 명령어에 들어갈 필드의 종류와 각 필드의 비트 수에 대한 구성을 &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;명령어 형식&lt;/b&gt;&lt;/span&gt; 이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;번역된 기계어들은 순서대로 기억장치에 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU에 의해 한 번에 처리될 수 있는 비트들의 그룹을 단어라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어의 길이는 CPU의 하드웨어 구조에 따라 8비트,16비트,32비트,64비트 등으로 다양하지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예에서는 단어가 8비트, 즉 한 바이트인 것으로 가정하고있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccOazK/btsNt9pycl4/SUS9WCGcr9pt5hm3eb7Hd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccOazK/btsNt9pycl4/SUS9WCGcr9pt5hm3eb7Hd1/img.png&quot; data-alt=&quot;한 바이트(byte)는 8비트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccOazK/btsNt9pycl4/SUS9WCGcr9pt5hm3eb7Hd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccOazK%2FbtsNt9pycl4%2FSUS9WCGcr9pt5hm3eb7Hd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;191&quot; height=&quot;232&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;한 바이트(byte)는 8비트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 명령어 형식 - 명령어의 비트 수와 용도 및 필드 구성 방법을 지정해주는 형식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 단어 - CPU에 의해 한 번에 처리될 수 있는 비트들의 그룹&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 명령어(instruction) - 어셈블리 명령어의 약칭&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 니모닉스(mnemonics) - 명령어가 지정하는 동작을 나타내는 간략화된 기호&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 어셈블러 - 어셈블리 프로그램을 기계어로 번역해주는 소프트웨어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 어셈블리 프로그램 - 고급 언어와 기계어 사이의 중간 언어인 어셈블리 언어로 작성된 프로그램&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 컴파일러 - 고급언어 프로그램을 기계어로 변환해주는 소프트웨어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 기계어 - 컴퓨터 하드웨어가 이해할 수 있는 언어&lt;/p&gt;</description>
      <category>CS/컴퓨터구조</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/16</guid>
      <comments>https://cwnsgh.tistory.com/entry/1-%EC%BB%B4%ED%93%A8%ED%84%B0-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B0%9C%EC%9A%94-2#entry16comment</comments>
      <pubDate>Thu, 24 Apr 2025 01:33:38 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 가지를 치지 않는다면, 시간은 당신을 칠 것입니다.</title>
      <link>https://cwnsgh.tistory.com/entry/%EA%B0%80%EC%A7%80%EB%A5%BC-%EC%B9%98%EC%A7%80-%EC%95%8A%EB%8A%94%EB%8B%A4%EB%A9%B4-%EC%8B%9C%EA%B0%84%EC%9D%80-%EB%8B%B9%EC%8B%A0%EC%9D%84-%EC%B9%A0-%EA%B2%83%EC%9E%85%EB%8B%88%EB%8B%A4</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;175&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wyUs2/btsNwORswpi/JzRN4TNYWI0NDX41T22WrK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wyUs2/btsNwORswpi/JzRN4TNYWI0NDX41T22WrK/img.jpg&quot; data-alt=&quot;이 가지 아닙니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wyUs2/btsNwORswpi/JzRN4TNYWI0NDX41T22WrK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwyUs2%2FbtsNwORswpi%2FJzRN4TNYWI0NDX41T22WrK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;288&quot; height=&quot;175&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;175&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이 가지 아닙니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 문제 링크입니다.&lt;br /&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/28075&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/28075&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자는 &lt;b&gt;&quot;시간 초과&quot;&lt;/b&gt; 라는 글자를 보면 손이 떨립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;내가 어떻게 풀었는데...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 줄 한 줄 코드를 써 내려가며 스스로에게 말하죠.&lt;br /&gt;&amp;ldquo;괜찮아. 현대 컴퓨터는 빠르니까.&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그렇게 자신을 속이며 제출 버튼을 누른 그 순간&amp;mdash;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[시간 초과]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;hellip;잠시 정적이 흐르고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간초과는 저에게 말을겁니다.&lt;br /&gt;&amp;ldquo;너 진짜 탐색 다 돌릴 생각이었어?&amp;rdquo;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  완전탐색은 당신을 배려하지 않는다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 조건은 이랬습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;총 N일 동안 일을 합니다.&lt;/li&gt;
&lt;li&gt;매일 2개의 업무(task) 중 하나를 선택하고, 그 업무는 3개의 장소(place) 중 하나에서 수행됩니다.&lt;/li&gt;
&lt;li&gt;같은 장소에서 연속으로 일하면 &lt;b&gt;점수가 절반&lt;/b&gt;이 됩니다.&lt;/li&gt;
&lt;li&gt;M점 이상을 달성하는 모든 가능한 경우의 수를 구해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 어떻게 풀까?&lt;br /&gt;자연스럽게 &lt;b&gt;DFS + 완전탐색&lt;/b&gt;을 떠올렸습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업무 2개, 장소 3개. 하루당 6가지 선택지.&lt;br /&gt;즉, 총 경우의 수는 6^N.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;사실 이건 시간초과가 나지않는 수준입니다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;하지만 문신처럼 박힌 저희 뇌는 아 이거.. 가지쳐야해.. 라고 떠오르게해주고 가지를 칩니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;&quot;가망없는 시도는 하지않는다 라는 비장함과 함께&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  가지치기 전략 요약&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;희망고문 차단&lt;/b&gt;: 아무리 잘해도 점수 못 넘긴다면 &amp;rarr; 바로 종료&lt;/li&gt;
&lt;li&gt;&lt;b&gt;목표 이미 달성&lt;/b&gt;: 남은 선택 다 유효하니 경우의 수 계산해서 바로 리턴&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장소 반복 감점&lt;/b&gt;: 전날과 같은 장소면 점수 절반&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✨ 풀이 코드&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const input = require(&quot;fs&quot;)
  .readFileSync(process.platform === &quot;linux&quot; ? &quot;/dev/stdin&quot; : &quot;./input.txt&quot;)
  .toString()
  .trim()
  .split(&quot;\n&quot;);

console.log(input);

const [N, M] = input[0].split(&quot; &quot;).map(Number);

//일하는 배열만듬
const work = input.slice(1).map((line) =&amp;gt; line.trim().split(&quot; &quot;).map(Number));

//업무에서 받을수있는 최댓값
const maxSingle = Math.max(...work.flat());

//남은날에 대해 이론상 최댓값(같은곳 방문했을떄 /2 되는거)을 설정해줍니다.
//남은날이 3일인데 이론상 최댓값을 더해도 안되는거면 불가능한것.
const maxScore = Array(N).fill(0);
maxScore[N - 1] = maxSingle;

for (let i = N - 2; i &amp;gt;= 0; i--) {
  maxScore[i] = maxScore[i + 1] + maxSingle;
}
console.log(&quot;maxscore = &quot;, maxScore);

function dfs(day, currentScore, prevPlace) {
  if (day === N) return currentScore &amp;gt;= M ? 1 : 0;
  if (currentScore + maxScore[day] &amp;lt; M) return 0;
  if (currentScore &amp;gt;= M) return 6 ** (N - day);

  let cnt = 0;
  for (let task = 0; task &amp;lt; 2; task++) {
    for (let place = 0; place &amp;lt; 3; place++) {
      let point = work[task][place];
      if (place === prevPlace) point = Math.floor(point / 2);
      cnt += dfs(day + 1, currentScore + point, place);
    }
  }
  return cnt;
}

console.log(dfs(0, 0, -1));&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  maxScore 배열로 희망을 계산하다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS에서 &quot;남은 날 동안 최대로 벌 수 있는 점수&quot;를 미리 계산해서,&lt;br /&gt;&lt;b&gt;그 이상이 되지 않으면 아예 탐색하지 않는 방식&lt;/b&gt;을 썼습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;const maxScore = Array(N).fill(0);
maxScore[N - 1] = maxSingle;

for (let i = N - 2; i &amp;gt;= 0; i--) {
  maxScore[i] = maxScore[i + 1] + maxSingle * 2;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 maxSingle은 업무 중 받을 수 있는 가장 큰 점수고,&lt;br /&gt;매일 두 번 반복해서 받을 수 있다고 가정합니다.&lt;br /&gt;말하자면&amp;hellip; &lt;b&gt;최대치 희망고문 시뮬레이션&lt;/b&gt;이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 덕분에 DFS는 비효율적인 경로를 &lt;b&gt;미리 차단&lt;/b&gt;하고,&lt;br /&gt;필요한 경로만 똑똑하게 탐색하게 됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;습관적으로 가지를 치자&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;DFS는 탐색의 정석이지만,&lt;br /&gt;조건 기반 가지치기 없이 쓰면 순수한 폭탄이다.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 지금 여러분이&lt;br /&gt;&amp;ldquo;이 정도면 되지 않을까?&amp;rdquo;&lt;br /&gt;라고 생각하고 있다면,&lt;br /&gt;한 번쯤 자신에게 질문해보세요.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;&lt;b&gt;이 경로, 진짜로 볼 가치가 있나?&lt;/b&gt;&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 가지가 &lt;b&gt;불필요하다면 과감히 쳐버리세요.&lt;/b&gt;&lt;br /&gt;그 한 줄이 당신을 시간의 압박에서 살릴 수도 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자처럼 손 떠는 분들이 더는 생기지 않길 바라며,&lt;br /&gt;이만 가지치기 된 글을 마칩니다.&lt;/p&gt;</description>
      <category>JavaScript/알고리즘</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/15</guid>
      <comments>https://cwnsgh.tistory.com/entry/%EA%B0%80%EC%A7%80%EB%A5%BC-%EC%B9%98%EC%A7%80-%EC%95%8A%EB%8A%94%EB%8B%A4%EB%A9%B4-%EC%8B%9C%EA%B0%84%EC%9D%80-%EB%8B%B9%EC%8B%A0%EC%9D%84-%EC%B9%A0-%EA%B2%83%EC%9E%85%EB%8B%88%EB%8B%A4#entry15comment</comments>
      <pubDate>Wed, 23 Apr 2025 16:31:51 +0900</pubDate>
    </item>
    <item>
      <title>JavaScript Array 메서드 정복 하기</title>
      <link>https://cwnsgh.tistory.com/entry/JavaScript-Array-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%A0%95%EB%B3%B5-%ED%95%98%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;javascript로 코딩테스트를 준비하려는데 Array를 모르면 절대절대 안됩니다.&lt;br /&gt;알고리즘 문제를 풀 때 정말 유용하게 사용되는 &lt;b&gt;배열(Array) 메서드&lt;/b&gt;들을 총정리하는 시간을 가져보겠습니다.&lt;br /&gt;배열 메서드를 잘 활용하면 코드를 훨씬 간결하고 효율적으로 작성할 수 있으며, 문제 해결 능력도 크게 향상될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;배열메서드를 다루면서 가장 중요한 포인트중 하나는 원본배열에 영향을 미치냐 안미치냐입니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 배열 순회 및 탐색 메서드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 각 요소를 순회하거나 특정 조건을 만족하는 요소를 찾는 메서드들입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1 &lt;code&gt;forEach()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 각 요소에 대해 주어진 함수를 실행합니다.&lt;/li&gt;
&lt;li&gt;반환값: &lt;code&gt;undefined&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주의:&lt;/b&gt; 원본 배열을 변경하지는 않지만, 콜백 함수 내에서 원본 배열을 변경하는 작업은 가능합니다. &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;와 달리 새로운 배열을 반환하지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];
let sum = 0;

numbers.forEach(item =&amp;gt; {
  console.log(item); // 1, 2, 3, 4, 5 순서대로 출력
  sum += item;
});

console.log(sum); // 결과: 15
// forEach 자체의 반환값은 undefined 입니다.
const result = numbers.forEach(item =&amp;gt; item * 2);
console.log(result); // 결과: undefined&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2 &lt;code&gt;map()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 각 요소에 대해 주어진 함수를 실행하고, 그 결과를 모아 &lt;b&gt;새로운 배열&lt;/b&gt;을 반환합니다.&lt;/li&gt;
&lt;li&gt;원본 배열은 변경되지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(item =&amp;gt; item * 2);

console.log(doubledNumbers); // 결과: [2, 4, 6, 8, 10]
console.log(numbers);      // 결과: [1, 2, 3, 4, 5] (원본 배열은 그대로)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3 &lt;code&gt;filter()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 각 요소에 대해 주어진 함수의 조건을 만족하는(true를 반환하는) 요소들만 모아 &lt;b&gt;새로운 배열&lt;/b&gt;을 반환합니다.&lt;/li&gt;
&lt;li&gt;원본 배열은 변경되지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(item =&amp;gt; item % 2 === 0);

console.log(evenNumbers); // 결과: [2, 4]
console.log(numbers);   // 결과: [1, 2, 3, 4, 5] (원본 배열은 그대로)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4 &lt;code&gt;reduce()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 각 요소에 대해 주어진 리듀서(reducer) 함수를 실행하여 &lt;b&gt;하나의 결과값&lt;/b&gt;을 반환합니다. (누산기)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;accumulator&lt;/code&gt;: 누적값, &lt;code&gt;currentValue&lt;/code&gt;: 현재 요소, &lt;code&gt;currentIndex&lt;/code&gt;(옵션): 현재 인덱스, &lt;code&gt;array&lt;/code&gt;(옵션): 원본 배열&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initialValue&lt;/code&gt;(옵션): 초기 누적값&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];

// 합계 구하기
const sum = numbers.reduce((accumulator, currentValue) =&amp;gt; {
  return accumulator + currentValue;
}, 0); // 초기값 0
console.log(sum); // 결과: 15

// 최대값 구하기
const max = numbers.reduce((acc, cur) =&amp;gt; (cur &amp;gt; acc ? cur : acc), numbers[0]);
console.log(max); // 결과: 5&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.5 &lt;code&gt;reduceRight()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;reduce()&lt;/code&gt;와 동일한 기능을 하지만, 배열의 &lt;b&gt;오른쪽부터 왼쪽으로&lt;/b&gt; 함수를 실행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const strings = ['world', ' ', 'hello'];
const combinedString = strings.reduceRight((acc, cur) =&amp;gt; acc + cur);

console.log(combinedString); // 결과: &quot;hello world&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.6 &lt;code&gt;find()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열에서 주어진 판별 함수를 만족하는 &lt;b&gt;첫 번째 요소의 값&lt;/b&gt;을 반환합니다. 만족하는 요소가 없으면 &lt;code&gt;undefined&lt;/code&gt;를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 3, 5, 4, 7];
const firstEven = numbers.find(item =&amp;gt; item % 2 === 0);

console.log(firstEven); // 결과: 4

const notFound = numbers.find(item =&amp;gt; item &amp;gt; 10);
console.log(notFound); // 결과: undefined&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.7 &lt;code&gt;findIndex()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열에서 주어진 판별 함수를 만족하는 &lt;b&gt;첫 번째 요소의 인덱스&lt;/b&gt;를 반환합니다. 만족하는 요소가 없으면 &lt;code&gt;-1&lt;/code&gt;을 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 3, 5, 4, 7];
const firstEvenIndex = numbers.findIndex(item =&amp;gt; item % 2 === 0);

console.log(firstEvenIndex); // 결과: 3

const notFoundIndex = numbers.findIndex(item =&amp;gt; item &amp;gt; 10);
console.log(notFoundIndex); // 결과: -1&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.8 &lt;code&gt;some()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 요소 중 &lt;b&gt;하나라도&lt;/b&gt; 주어진 판별 함수를 만족하면 &lt;code&gt;true&lt;/code&gt;를 반환하고, 그렇지 않으면 &lt;code&gt;false&lt;/code&gt;를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 3, 5, 4, 7];
const hasEvenNumber = numbers.some(item =&amp;gt; item % 2 === 0);

console.log(hasEvenNumber); // 결과: true

const hasNumberGreaterThan10 = numbers.some(item =&amp;gt; item &amp;gt; 10);
console.log(hasNumberGreaterThan10); // 결과: false&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.9 &lt;code&gt;every()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 &lt;b&gt;모든 요소&lt;/b&gt;가 주어진 판별 함수를 만족하면 &lt;code&gt;true&lt;/code&gt;를 반환하고, 그렇지 않으면 &lt;code&gt;false&lt;/code&gt;를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [2, 4, 6, 8];
const allEven = numbers.every(item =&amp;gt; item % 2 === 0);

console.log(allEven); // 결과: true

const numbers2 = [2, 4, 7, 8];
const allEven2 = numbers2.every(item =&amp;gt; item % 2 === 0);

console.log(allEven2); // 결과: false&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.10 &lt;code&gt;includes()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열이 특정 요소를 포함하고 있는지 판별하여 &lt;code&gt;true&lt;/code&gt; 또는 &lt;code&gt;false&lt;/code&gt;를 반환합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fromIndex&lt;/code&gt;(옵션): 검색을 시작할 인덱스&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const fruits = ['apple', 'banana', 'mango'];

console.log(fruits.includes('banana')); // 결과: true
console.log(fruits.includes('grape'));  // 결과: false
console.log(fruits.includes('apple', 1)); // 결과: false (인덱스 1부터 검색)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.11 &lt;code&gt;indexOf()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열에서 지정된 요소를 찾을 수 있는 &lt;b&gt;첫 번째 인덱스&lt;/b&gt;를 반환합니다. 요소가 없으면 &lt;code&gt;-1&lt;/code&gt;을 반환합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fromIndex&lt;/code&gt;(옵션): 검색을 시작할 인덱스&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const fruits = ['apple', 'banana', 'mango', 'banana'];

console.log(fruits.indexOf('banana'));      // 결과: 1
console.log(fruits.indexOf('grape'));       // 결과: -1
console.log(fruits.indexOf('banana', 2)); // 결과: 3 (인덱스 2부터 검색)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.12 &lt;code&gt;lastIndexOf()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열에서 지정된 요소를 찾을 수 있는 &lt;b&gt;마지막 인덱스&lt;/b&gt;를 반환합니다. 요소가 없으면 &lt;code&gt;-1&lt;/code&gt;을 반환합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fromIndex&lt;/code&gt;(옵션): 검색을 시작할 인덱스 (역방향으로 검색)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const fruits = ['apple', 'banana', 'mango', 'banana'];

console.log(fruits.lastIndexOf('banana'));      // 결과: 3
console.log(fruits.lastIndexOf('grape'));       // 결과: -1
console.log(fruits.lastIndexOf('banana', 2)); // 결과: 1 (인덱스 2부터 역방향 검색)&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 배열 수정 메서드 (원본 배열 변경)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 메서드들은 원본 배열 자체를 변경합니다. 그러므로 사용 시 &lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;주의&lt;/span&gt;&lt;/b&gt;가 필요합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1 &lt;code&gt;push()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 &lt;b&gt;끝&lt;/b&gt;에 하나 이상의 요소를 추가하고, 배열의 &lt;b&gt;새로운 길이&lt;/b&gt;를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3];
const newLength = numbers.push(4, 5);

console.log(newLength); // 결과: 5
console.log(numbers);   // 결과: [1, 2, 3, 4, 5] (원본 배열 변경)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2 &lt;code&gt;pop()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 &lt;b&gt;마지막&lt;/b&gt; 요소를 제거하고, 그 &lt;b&gt;제거된 요소&lt;/b&gt;를 반환합니다. 배열이 비어있으면 &lt;code&gt;undefined&lt;/code&gt;를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];
const lastElement = numbers.pop();

console.log(lastElement); // 결과: 5
console.log(numbers);     // 결과: [1, 2, 3, 4] (원본 배열 변경)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3 &lt;code&gt;shift()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 &lt;b&gt;첫 번째&lt;/b&gt; 요소를 제거하고, 그 &lt;b&gt;제거된 요소&lt;/b&gt;를 반환합니다. 배열이 비어있으면 &lt;code&gt;undefined&lt;/code&gt;를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];
const firstElement = numbers.shift();

console.log(firstElement); // 결과: 1
console.log(numbers);      // 결과: [2, 3, 4, 5] (원본 배열 변경)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4 &lt;code&gt;unshift()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 &lt;b&gt;앞&lt;/b&gt;에 하나 이상의 요소를 추가하고, 배열의 &lt;b&gt;새로운 길이&lt;/b&gt;를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [3, 4, 5];
const newLength = numbers.unshift(1, 2);

console.log(newLength); // 결과: 5
console.log(numbers);   // 결과: [1, 2, 3, 4, 5] (원본 배열 변경)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.5 &lt;code&gt;splice()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가하여 배열의 내용을 변경합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt;: 변경을 시작할 인덱스&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deleteCount&lt;/code&gt;(옵션): 제거할 요소의 수&lt;/li&gt;
&lt;li&gt;&lt;code&gt;item1, item2, ...&lt;/code&gt;(옵션): 배열에 추가할 요소&lt;/li&gt;
&lt;li&gt;반환값: &lt;b&gt;제거된 요소들의 배열&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const months = ['Jan', 'March', 'April', 'June'];

// 요소 삽입 (인덱스 1에 'Feb' 삽입)
let removed = months.splice(1, 0, 'Feb');
console.log(months);   // 결과: ['Jan', 'Feb', 'March', 'April', 'June']
console.log(removed); // 결과: [] (제거된 요소 없음)

// 요소 교체 (인덱스 4의 'June'을 'May'로 교체)
removed = months.splice(4, 1, 'May');
console.log(months);   // 결과: ['Jan', 'Feb', 'March', 'April', 'May']
console.log(removed); // 결과: ['June'] (제거된 요소)

// 요소 제거 (인덱스 1부터 2개 요소 제거)
removed = months.splice(1, 2);
console.log(months);   // 결과: ['Jan', 'April', 'May']
console.log(removed); // 결과: ['Feb', 'March'] (제거된 요소)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.6 &lt;code&gt;sort()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 요소를 &lt;b&gt;정렬&lt;/b&gt;합니다. 기본 정렬 순서는 문자열 유니코드 코드 포인트를 따릅니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주의:&lt;/b&gt; 숫자 정렬 시에는 비교 함수를 제공해야 합니다.&lt;/li&gt;
&lt;li&gt;반환값: &lt;b&gt;정렬된 배열&lt;/b&gt; (원본 배열 자체가 변경됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const fruits = ['banana', 'apple', 'mango'];
fruits.sort();
console.log(fruits); // 결과: ['apple', 'banana', 'mango'] (문자열 정렬)

const numbers = [10, 5, 100, 1];
// 기본 정렬 (문자열 기준으로 정렬되어 의도와 다를 수 있음)
// numbers.sort();
// console.log(numbers); // 결과: [1, 10, 100, 5]

// 숫자 오름차순 정렬
numbers.sort((a, b) =&amp;gt; a - b);
console.log(numbers); // 결과: [1, 5, 10, 100]

// 숫자 내림차순 정렬
numbers.sort((a, b) =&amp;gt; b - a);
console.log(numbers); // 결과: [100, 10, 5, 1]&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.7 &lt;code&gt;reverse()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 요소 순서를 &lt;b&gt;반대로&lt;/b&gt; 뒤집습니다.&lt;/li&gt;
&lt;li&gt;반환값: &lt;b&gt;순서가 뒤집힌 배열&lt;/b&gt; (원본 배열 자체가 변경됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];
numbers.reverse();

console.log(numbers); // 결과: [5, 4, 3, 2, 1] (원본 배열 변경)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.8 &lt;code&gt;fill()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 시작 인덱스부터 끝 인덱스 이전까지의 모든 요소를 정적인 값으로 채웁니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt;: 채울 값&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt;(옵션): 시작 인덱스 (기본값 0)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt;(옵션): 끝 인덱스 (기본값 &lt;code&gt;array.length&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;반환값: &lt;b&gt;변경된 배열&lt;/b&gt; (원본 배열 자체가 변경됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];

// 모든 요소를 0으로 채우기
numbers.fill(0);
console.log(numbers); // 결과: [0, 0, 0, 0, 0]

const numbers2 = [1, 2, 3, 4, 5];
// 인덱스 2부터 4 이전까지 9로 채우기
numbers2.fill(9, 2, 4);
console.log(numbers2); // 결과: [1, 2, 9, 9, 5]&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.9 &lt;code&gt;copyWithin()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 일부를 복사하여 동일한 배열의 다른 위치에 덮어쓰고, 길이를 수정하지 않고 반환합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;target&lt;/code&gt;: 복사한 시퀀스를 붙여넣을 인덱스&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt;(옵션): 복사를 시작할 인덱스 (기본값 0)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt;(옵션): 복사를 끝낼 인덱스 (기본값 &lt;code&gt;array.length&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;반환값: &lt;b&gt;변경된 배열&lt;/b&gt; (원본 배열 자체가 변경됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const array = ['a', 'b', 'c', 'd', 'e'];

// 인덱스 0부터 2개 요소('a', 'b')를 복사해서 인덱스 3 위치부터 붙여넣기
array.copyWithin(3, 0, 2);
console.log(array); // 결과: ['a', 'b', 'c', 'a', 'b']

const array2 = [1, 2, 3, 4, 5];
// 인덱스 0부터 끝까지 복사해서 인덱스 2 위치부터 붙여넣기 (기본값 사용)
array2.copyWithin(2);
console.log(array2); // 결과: [1, 2, 1, 2, 3]&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 배열 변환 및 생성 메서드 (주로 새로운 배열 반환)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1 &lt;code&gt;slice()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 &lt;code&gt;begin&lt;/code&gt; 인덱스부터 &lt;code&gt;end&lt;/code&gt; 인덱스 이전까지에 대한 &lt;b&gt;얕은 복사본&lt;/b&gt;을 &lt;b&gt;새로운 배열 객체&lt;/b&gt;로 반환합니다.&lt;/li&gt;
&lt;li&gt;원본 배열은 변경되지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;begin&lt;/code&gt;(옵션): 추출 시작 인덱스 (음수면 끝에서부터의 길이)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt;(옵션): 추출 종료 인덱스 (해당 인덱스 직전까지 추출, 음수면 끝에서부터의 길이)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice(2));      // 결과: ['camel', 'duck', 'elephant']
console.log(animals.slice(2, 4));   // 결과: ['camel', 'duck']
console.log(animals.slice(1, -1));  // 결과: ['bison', 'camel', 'duck']
console.log(animals.slice(-2));     // 결과: ['duck', 'elephant']
console.log(animals.slice());       // 결과: ['ant', 'bison', 'camel', 'duck', 'elephant'] (배열 전체 얕은 복사)

console.log(animals); // 결과: ['ant', 'bison', 'camel', 'duck', 'elephant'] (원본 배열 그대로)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2 &lt;code&gt;concat()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인자로 주어진 배열이나 값들을 기존 배열에 합쳐 &lt;b&gt;새로운 배열&lt;/b&gt;을 반환합니다.&lt;/li&gt;
&lt;li&gt;원본 배열은 변경되지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const arr1 = ['a', 'b', 'c'];
const arr2 = ['d', 'e', 'f'];
const arr3 = arr1.concat(arr2, 'g');

console.log(arr3); // 결과: ['a', 'b', 'c', 'd', 'e', 'f', 'g']
console.log(arr1); // 결과: ['a', 'b', 'c'] (원본 배열 그대로)
console.log(arr2); // 결과: ['d', 'e', 'f'] (원본 배열 그대로)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3 &lt;code&gt;join()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 모든 요소를 연결하여 &lt;b&gt;하나의 문자열&lt;/b&gt;로 만듭니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;separator&lt;/code&gt;(옵션): 각 요소를 구분할 문자열 (기본값은 쉼표 &lt;code&gt;,&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const elements = ['Fire', 'Air', 'Water'];

console.log(elements.join());    // 결과: &quot;Fire,Air,Water&quot;
console.log(elements.join(''));   // 결과: &quot;FireAirWater&quot;
console.log(elements.join('-'));  // 결과: &quot;Fire-Air-Water&quot;
console.log(elements.join(' '));  // 결과: &quot;Fire Air Water&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.4 &lt;code&gt;flat()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 하위 배열 요소를 지정한 깊이까지 재귀적으로 이어붙인 &lt;b&gt;새로운 배열&lt;/b&gt;을 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;depth&lt;/code&gt;(옵션): 중첩 배열 구조를 평탄화할 깊이 (기본값 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const arr1 = [1, 2, [3, 4]];
console.log(arr1.flat()); // 결과: [1, 2, 3, 4] (depth 1)

const arr2 = [1, 2, [3, 4, [5, 6]]];
console.log(arr2.flat()); // 결과: [1, 2, 3, 4, [5, 6]] (depth 1)
console.log(arr2.flat(2)); // 결과: [1, 2, 3, 4, 5, 6] (depth 2)

const arr3 = [1, 2, [3, 4, [5, 6, [7, 8]]]];
console.log(arr3.flat(Infinity)); // 결과: [1, 2, 3, 4, 5, 6, 7, 8] (모든 깊이 평탄화)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.5 &lt;code&gt;flatMap()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 배열의 각 요소에 대해 매핑 함수를 실행한 다음, 결과를 &lt;b&gt;새로운 배열로 평탄화&lt;/b&gt;합니다. (&lt;code&gt;map()&lt;/code&gt; + &lt;code&gt;flat(1)&lt;/code&gt;과 동일)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const arr = [1, 2, 3, 4];

// 각 숫자를 자신과 자신의 제곱으로 매핑 후 평탄화
const result = arr.flatMap(x =&amp;gt; [x, x * 2]);
console.log(result); // 결과: [1, 2, 2, 4, 3, 6, 4, 8]

// map과 flat을 사용한 동일한 결과
const resultMap = arr.map(x =&amp;gt; [x, x * 2]); // [[1, 2], [2, 4], [3, 6], [4, 8]]
const resultFlat = resultMap.flat();        // [1, 2, 2, 4, 3, 6, 4, 8]
console.log(resultFlat); // 결과: [1, 2, 2, 4, 3, 6, 4, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 배열 유틸리티 메서드&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1 &lt;code&gt;Array.isArray()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인자가 배열인지 아닌지 판별합니다. (Array 프로토타입 메서드가 아닌 Array의 정적 메서드)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;console.log(Array.isArray([1, 2, 3]));  // 결과: true
console.log(Array.isArray({foo: 123})); // 결과: false
console.log(Array.isArray('hello'));   // 결과: false
console.log(Array.isArray(undefined)); // 결과: false&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2 &lt;code&gt;Array.from()&lt;/code&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유사 배열 객체(array-like object)나 반복 가능한 객체(iterable object)를 얕게 복사하여 &lt;b&gt;새로운 Array 객체&lt;/b&gt;를 만듭니다. &lt;br /&gt;(Array 프로토타입 메서드가 아닌 Array의 정적 메서드)&lt;/li&gt;
&lt;li&gt;매핑 함수를 인자로 받을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 문자열로부터 배열 생성
const str = 'hello';
const arr1 = Array.from(str);
console.log(arr1); // 결과: ['h', 'e', 'l', 'l', 'o']

// Set 객체로부터 배열 생성
const set = new Set(['a', 'b', 'c']);
const arr2 = Array.from(set);
console.log(arr2); // 결과: ['a', 'b', 'c']

// 매핑 함수 사용
const numbers = [1, 2, 3];
const arr3 = Array.from(numbers, x =&amp;gt; x * x);
console.log(arr3); // 결과: [1, 4, 9]

// 유사 배열 객체 (arguments)
function createArray() {
  return Array.from(arguments);
}
const arr4 = createArray(10, 20, 30);
console.log(arr4); // 결과: [10, 20, 30]&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. (번외) 배열 복사: Spread Syntax (...)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ES6 문법인 전개 구문(...)을 사용하여 배열을 얕게 복사할 수 있습니다. &lt;code&gt;slice()&lt;/code&gt;와 유사하게 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const original = [1, 2, 3];
const copy = [...original];

copy.push(4);

console.log(original); // 결과: [1, 2, 3] (원본은 변경되지 않음)
console.log(copy);     // 결과: [1, 2, 3, 4]&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 알고리즘 문제 풀이에 자주 사용되는 JavaScript 배열 메서드들을 살펴보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 메서드의 특징과 반환값을 정확히 이해하고 상황에 맞게 활용하는 것이 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원본 배열 변경 여부:&lt;/b&gt; &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pop&lt;/code&gt;, &lt;code&gt;shift&lt;/code&gt;, &lt;code&gt;unshift&lt;/code&gt;, &lt;code&gt;splice&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;reverse&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt;, &lt;code&gt;copyWithin&lt;/code&gt; 등은 원본 배열을 직접 수정하므로 주의해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새로운 배열 반환:&lt;/b&gt; &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;slice&lt;/code&gt;, &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;flat&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt; 등은 새로운 배열을 반환하므로 함수형 프로그래밍 스타일에 유용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 배열에서 재미난 문제가 하나있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745335222438&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 배열은 요소를 동적으로 추가할수있습니다. 이때 length의 프로퍼티 값은 자동으로 갱신되는데요.

const arr = [0];

arr[1] = 1;

console.log(arr) // [0,1]
consoel.log(arr.length) // 2

//여기까지는 뭐 이해가됩니다 근데 갑자기

arr[100] = 100;
// 이걸해버린다면 어떻게될까요?

console.log(arr) // [0,1,empty*98,100]
consoel.log(arr.length) // 101
//이렇게 희소배열이 됩니다!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 그냥 배열 공부하다가 생각해보지않았어서 몰랐던 내용이였어요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 배열의 요소가 연속적으로 위치하지않고 일부가 비어있는 배열을 희소배열이라고해요 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열에 대해서 알아보는 포스팅도 올려보겠습니다.&lt;/p&gt;</description>
      <category>JavaScript</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/14</guid>
      <comments>https://cwnsgh.tistory.com/entry/JavaScript-Array-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%A0%95%EB%B3%B5-%ED%95%98%EA%B8%B0#entry14comment</comments>
      <pubDate>Wed, 23 Apr 2025 00:24:59 +0900</pubDate>
    </item>
    <item>
      <title>[컴퓨터구조] 컴퓨터 시스템 개요 및 구조</title>
      <link>https://cwnsgh.tistory.com/entry/1-%EC%BB%B4%ED%93%A8%ED%84%B0-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B0%9C%EC%9A%94-1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터시스템은 기본적으로 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;하드웨어&lt;/b&gt;&lt;/span&gt;와 &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;시스템 소프트웨어&lt;/b&gt;&lt;/span&gt;로 구성되고 그러한 시스템에 &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;각종 응용 소프트웨어&lt;/b&gt;&lt;/span&gt;들이 탑재되어 사용자와 상호작용하면서 프로그램을 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;185&quot; data-start=&quot;174&quot; data-ke-size=&quot;size26&quot;&gt;1.1 컴퓨터의 기본구조&lt;/h2&gt;
&lt;h2 data-end=&quot;185&quot; data-start=&quot;174&quot; data-ke-size=&quot;size26&quot;&gt;✅ 하드웨어란?&lt;/h2&gt;
&lt;p data-end=&quot;243&quot; data-start=&quot;187&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정보를 실제로 처리하는 물리적 실체&lt;/b&gt;로, 컴퓨터의 눈에 보이고 손에 잡히는 모든 부품들을 말함.&lt;/p&gt;
&lt;blockquote data-end=&quot;302&quot; data-start=&quot;245&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;302&quot; data-start=&quot;247&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #666666; text-align: start;&quot;&gt; &lt;/span&gt; 비유&lt;/b&gt;: 컴퓨터가 사람이라면, 하드웨어는 &lt;b&gt;근육과 뼈, 신경계&lt;/b&gt;와 같은 몸 그 자체이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;329&quot; data-start=&quot;309&quot; data-ke-size=&quot;size26&quot;&gt;  하드웨어의 주요 구성 요소&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;885&quot; data-start=&quot;331&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;425&quot; data-start=&quot;331&quot;&gt;&lt;b&gt;메인보드 (Mainboard)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;425&quot; data-start=&quot;360&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;385&quot; data-start=&quot;360&quot;&gt;모든 부품이 연결되는 &lt;b&gt;중앙 기판&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;425&quot; data-start=&quot;389&quot;&gt;CPU, 메모리, 확장 슬롯 등을 포함해 &lt;b&gt;시스템의 중추&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;516&quot; data-start=&quot;427&quot;&gt;&lt;b&gt;CPU &amp;amp; GPU 칩&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;516&quot; data-start=&quot;451&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;478&quot; data-start=&quot;451&quot;&gt;&lt;b&gt;CPU&lt;/b&gt;: 명령어 실행과 데이터 처리&lt;/li&gt;
&lt;li data-end=&quot;516&quot; data-start=&quot;482&quot;&gt;&lt;b&gt;GPU&lt;/b&gt;: 영상, 그래픽, 병렬 연산 전용 처리 장치&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;623&quot; data-start=&quot;518&quot;&gt;&lt;b&gt;주기억장치 모듈 (RAM)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;623&quot; data-start=&quot;545&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;575&quot; data-start=&quot;545&quot;&gt;CPU가 직접 접근하는 &lt;b&gt;고속 임시 메모리&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;596&quot; data-start=&quot;579&quot;&gt;예: DDR5 SDRAM&lt;/li&gt;
&lt;li data-end=&quot;623&quot; data-start=&quot;600&quot;&gt;휘발성이라 전원이 꺼지면 내용이 사라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;674&quot; data-start=&quot;625&quot;&gt;&lt;b&gt;확장 보드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;674&quot; data-start=&quot;643&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;674&quot; data-start=&quot;643&quot;&gt;사운드카드, 네트워크카드 등 &lt;b&gt;기능 추가용 보드&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;720&quot; data-start=&quot;676&quot;&gt;&lt;b&gt;전원공급장치 (PSU)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;720&quot; data-start=&quot;701&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;720&quot; data-start=&quot;701&quot;&gt;각 부품에 안정적으로 전력 공급&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;773&quot; data-start=&quot;722&quot;&gt;&lt;b&gt;보조기억장치&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;773&quot; data-start=&quot;741&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;773&quot; data-start=&quot;741&quot;&gt;하드디스크(HDD), SSD 등 &lt;b&gt;영구 저장 장치&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;885&quot; data-start=&quot;775&quot;&gt;&lt;b&gt;입출력장치 (I/O Devices)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;885&quot; data-start=&quot;807&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;829&quot; data-start=&quot;807&quot;&gt;&lt;b&gt;입력&lt;/b&gt;: 키보드, 마우스 등&lt;/li&gt;
&lt;li data-end=&quot;855&quot; data-start=&quot;833&quot;&gt;&lt;b&gt;출력&lt;/b&gt;: 모니터, 프린터 등&lt;/li&gt;
&lt;li data-end=&quot;885&quot; data-start=&quot;859&quot;&gt;사용자 &amp;harr; 컴퓨터 간 &lt;b&gt;정보 전달 통로&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-end=&quot;1014&quot; data-start=&quot;887&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1014&quot; data-start=&quot;889&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전체 비유&lt;/b&gt;:&lt;br /&gt;하드웨어는 컴퓨터의 &lt;b&gt;몸&lt;/b&gt;이며,&lt;br /&gt;메인보드는 &lt;b&gt;신경망&lt;/b&gt;, CPU는 &lt;b&gt;두뇌&lt;/b&gt;, RAM은 &lt;b&gt;작업 공간&lt;/b&gt;,&lt;br /&gt;저장장치는 &lt;b&gt;기억력&lt;/b&gt;, 입출력장치는 &lt;b&gt;감각 기관&lt;/b&gt;이라 할 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1033&quot; data-start=&quot;1021&quot; data-ke-size=&quot;size26&quot;&gt;✅ 소프트웨어란?&lt;/h2&gt;
&lt;p data-end=&quot;1069&quot; data-start=&quot;1035&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하드웨어를 어떻게 동작시킬지를 지시하는 명령어들의 집합&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1128&quot; data-start=&quot;1071&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1097&quot; data-start=&quot;1071&quot;&gt;정보가 어떻게 처리되고 언제 실행될지 결정함&lt;/li&gt;
&lt;li data-end=&quot;1128&quot; data-start=&quot;1098&quot;&gt;&lt;b&gt;하드웨어 위에서 동작&lt;/b&gt;하며, 그 기능을 활용함&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;1184&quot; data-start=&quot;1130&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1184&quot; data-start=&quot;1132&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비유&lt;/b&gt;: 하드웨어가 &amp;lsquo;몸&amp;rsquo;이라면, 소프트웨어는 &lt;b&gt;두뇌를 움직이는 생각과 명령서&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1213&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size26&quot;&gt;❗ 소프트웨어는 하드웨어에 의존한다&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1265&quot; data-start=&quot;1215&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1238&quot; data-start=&quot;1215&quot;&gt;하드웨어가 &lt;b&gt;기본 능력을 제공&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1265&quot; data-start=&quot;1239&quot;&gt;소프트웨어는 그 위에서 &lt;b&gt;기능을 구성&lt;/b&gt;함&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;1312&quot; data-start=&quot;1267&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1312&quot; data-start=&quot;1269&quot; data-ke-size=&quot;size16&quot;&gt;좋은 게임(소프트웨어)이라도 성능 낮은 PC(하드웨어)에선 잘 안 돌아감&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1335&quot; data-start=&quot;1319&quot; data-ke-size=&quot;size26&quot;&gt;컴퓨터의 기본 기능&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1435&quot; data-start=&quot;1337&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1359&quot; data-start=&quot;1337&quot;&gt;&lt;b&gt;수치적, 논리적 데이터의 처리&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1391&quot; data-start=&quot;1360&quot;&gt;초기에는 릴레이 등 &lt;b&gt;기계 장치&lt;/b&gt;를 사용했지만&lt;/li&gt;
&lt;li data-end=&quot;1435&quot; data-start=&quot;1392&quot;&gt;지금은 속도 향상을 위해 &lt;b&gt;전자 회로 기반의 디지털 시스템&lt;/b&gt;으로 전환됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1488&quot; data-start=&quot;1464&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터는 다음과 같은 순서로 작업을 수행함:&lt;/p&gt;
&lt;blockquote data-end=&quot;1527&quot; data-start=&quot;1490&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1527&quot; data-start=&quot;1492&quot; data-ke-size=&quot;size16&quot;&gt;프로그램 실행 &amp;rarr; 데이터 읽기 &amp;rarr; 데이터 처리 &amp;rarr; 결과 저장&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1553&quot; data-start=&quot;1534&quot; data-ke-size=&quot;size23&quot;&gt;  주요 구성 요소의 역할&lt;/h3&gt;
&lt;h4 data-end=&quot;1574&quot; data-start=&quot;1555&quot; data-ke-size=&quot;size20&quot;&gt;✅ CPU (중앙처리장치)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1684&quot; data-start=&quot;1576&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1610&quot; data-start=&quot;1576&quot;&gt;명령어 해석, 연산, 판단, 제어 등 컴퓨터의 &lt;b&gt;중추&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1640&quot; data-start=&quot;1611&quot;&gt;컴퓨터의 &lt;b&gt;성능과 특성&lt;/b&gt;을 결정짓는 핵심 부품&lt;/li&gt;
&lt;li data-end=&quot;1684&quot; data-start=&quot;1641&quot;&gt;처리 단위(비트 수)에 따라 컴퓨터 종류가 나뉨 (예: 8비트, 64비트)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;1721&quot; data-start=&quot;1686&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1721&quot; data-start=&quot;1688&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비유&lt;/b&gt;: 회사에서 의사결정을 내리는 &lt;b&gt;CEO&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;1726&quot; data-start=&quot;1723&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;1746&quot; data-start=&quot;1728&quot; data-ke-size=&quot;size20&quot;&gt;✅ 주기억장치 (RAM)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1810&quot; data-start=&quot;1748&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1777&quot; data-start=&quot;1748&quot;&gt;CPU가 실시간으로 읽고 쓰는 &lt;b&gt;작업용 공간&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1810&quot; data-start=&quot;1778&quot;&gt;속도는 빠르지만 휘발성이며, 저장 용량에는 한계가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;1871&quot; data-start=&quot;1812&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1871&quot; data-start=&quot;1814&quot; data-ke-size=&quot;size16&quot;&gt;대표 예: DDR5 SDRAM&lt;br /&gt;&lt;b&gt;비유&lt;/b&gt;: 작업 중 참고하는 &lt;b&gt;책상 위 메모장&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;1876&quot; data-start=&quot;1873&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;1902&quot; data-start=&quot;1878&quot; data-ke-size=&quot;size20&quot;&gt;✅ 보조기억장치 (SSD, HDD)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1977&quot; data-start=&quot;1904&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1928&quot; data-start=&quot;1904&quot;&gt;데이터를 &lt;b&gt;영구적으로 저장&lt;/b&gt;하는 장치&lt;/li&gt;
&lt;li data-end=&quot;1957&quot; data-start=&quot;1929&quot;&gt;CPU가 직접 접근 불가 &amp;rarr; &lt;b&gt;제어기 필요&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1977&quot; data-start=&quot;1958&quot;&gt;저장 밀도는 높지만 속도는 느림&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;2015&quot; data-start=&quot;1979&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2015&quot; data-start=&quot;1981&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비유&lt;/b&gt;: 자료를 정리해 넣는 &lt;b&gt;서랍장, 캐비닛&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;2020&quot; data-start=&quot;2017&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;2048&quot; data-start=&quot;2022&quot; data-ke-size=&quot;size20&quot;&gt;✅ 입출력장치 (I/O Devices)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2072&quot; data-start=&quot;2050&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2072&quot; data-start=&quot;2050&quot;&gt;컴퓨터와 사용자 간의 정보 전달 장치&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2190&quot; data-start=&quot;2074&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;2190&quot; data-start=&quot;2114&quot;&gt;
&lt;tr data-end=&quot;2152&quot; data-start=&quot;2114&quot;&gt;
&lt;td data-end=&quot;2121&quot; data-start=&quot;2114&quot;&gt;입력장치&lt;/td&gt;
&lt;td data-end=&quot;2132&quot; data-start=&quot;2121&quot;&gt;키보드, 마우스&lt;/td&gt;
&lt;td data-end=&quot;2152&quot; data-start=&quot;2132&quot;&gt;사용자의 명령을 컴퓨터에 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2190&quot; data-start=&quot;2153&quot;&gt;
&lt;td data-end=&quot;2160&quot; data-start=&quot;2153&quot;&gt;출력장치&lt;/td&gt;
&lt;td data-end=&quot;2171&quot; data-start=&quot;2160&quot;&gt;모니터, 프린터&lt;/td&gt;
&lt;td data-end=&quot;2190&quot; data-start=&quot;2171&quot;&gt;처리 결과를 사용자에게 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;2243&quot; data-start=&quot;2192&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2243&quot; data-start=&quot;2194&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비유&lt;/b&gt;: 입력은 &lt;b&gt;입을 통한 말하기&lt;/b&gt;, 출력은 &lt;b&gt;눈과 귀를 통한 반응&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>CS/컴퓨터구조</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/13</guid>
      <comments>https://cwnsgh.tistory.com/entry/1-%EC%BB%B4%ED%93%A8%ED%84%B0-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B0%9C%EC%9A%94-1#entry13comment</comments>
      <pubDate>Tue, 22 Apr 2025 15:02:43 +0900</pubDate>
    </item>
    <item>
      <title> ️ 자바스크립트 Proxy: 내 객체를 위한 똑똑한 문지기</title>
      <link>https://cwnsgh.tistory.com/entry/%F0%9F%9B%A1%EF%B8%8F-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Proxy-%EB%82%B4-%EA%B0%9D%EC%B2%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%98%91%EB%98%91%ED%95%9C-%EB%AC%B8%EC%A7%80%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅에서는 &lt;code&gt;Object.freeze()&lt;/code&gt;를 사용하여 객체의 불변성을 확보하는 방법에 대해 다루었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cwnsgh.tistory.com/entry/%F0%9F%94%92-Objectfreeze%EB%A1%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%EC%83%81%ED%83%9C%EB%A5%BC-%EB%B3%B4%ED%98%B8%ED%95%98%EB%8A%94-%EB%B2%95-%E2%80%94-%EB%B6%88%EB%B3%80%EC%84%B1immutability%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83&quot;&gt;2025.04.15 - [JavaScript] -   Object.freeze()로 안전하게 상태를 보호하는 법 &amp;mdash; 불변성(immutability)의 모든 것&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1744791730094&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;  Object.freeze()로 안전하게 상태를 보호하는 법 &amp;mdash; 불변성(immutability)의 모든 것&quot; data-og-description=&quot;안녕하세요! 복잡한 웹 애플리케이션을 만들다 보면 '상태 관리'라는 거대한 벽에 부딪히곤 합니다. 데이터가 어디서 어떻게 변하는지 추적하기 어렵고, 예상치 못한 버그 때문에 고생한 경험, &quot; data-og-host=&quot;cwnsgh.tistory.com&quot; data-og-source-url=&quot;https://cwnsgh.tistory.com/entry/%F0%9F%94%92-Objectfreeze%EB%A1%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%EC%83%81%ED%83%9C%EB%A5%BC-%EB%B3%B4%ED%98%B8%ED%95%98%EB%8A%94-%EB%B2%95-%E2%80%94-%EB%B6%88%EB%B3%80%EC%84%B1immutability%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83&quot; data-og-url=&quot;https://cwnsgh.tistory.com/entry/%F0%9F%94%92-Objectfreeze%EB%A1%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%EC%83%81%ED%83%9C%EB%A5%BC-%EB%B3%B4%ED%98%B8%ED%95%98%EB%8A%94-%EB%B2%95-%E2%80%94-%EB%B6%88%EB%B3%80%EC%84%B1immutability%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b9GOVw/hyYG5U7hCv/QjGIrHsFkn0M8klIRfpvB0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/47rWR/hyYH5UzjUk/dasNn2WEgPJufvTzlGMMBK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bbC3Ah/hyYEBBltLd/QaWn9QdZmwQU7jz2JkDPkK/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024&quot;&gt;&lt;a href=&quot;https://cwnsgh.tistory.com/entry/%F0%9F%94%92-Objectfreeze%EB%A1%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%EC%83%81%ED%83%9C%EB%A5%BC-%EB%B3%B4%ED%98%B8%ED%95%98%EB%8A%94-%EB%B2%95-%E2%80%94-%EB%B6%88%EB%B3%80%EC%84%B1immutability%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwnsgh.tistory.com/entry/%F0%9F%94%92-Objectfreeze%EB%A1%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%EC%83%81%ED%83%9C%EB%A5%BC-%EB%B3%B4%ED%98%B8%ED%95%98%EB%8A%94-%EB%B2%95-%E2%80%94-%EB%B6%88%EB%B3%80%EC%84%B1immutability%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b9GOVw/hyYG5U7hCv/QjGIrHsFkn0M8klIRfpvB0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/47rWR/hyYH5UzjUk/dasNn2WEgPJufvTzlGMMBK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bbC3Ah/hyYEBBltLd/QaWn9QdZmwQU7jz2JkDPkK/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;  Object.freeze()로 안전하게 상태를 보호하는 법 &amp;mdash; 불변성(immutability)의 모든 것&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 복잡한 웹 애플리케이션을 만들다 보면 '상태 관리'라는 거대한 벽에 부딪히곤 합니다. 데이터가 어디서 어떻게 변하는지 추적하기 어렵고, 예상치 못한 버그 때문에 고생한 경험,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwnsgh.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;freeze&lt;/code&gt;는 객체 상태 변경을 원천적으로 차단하여 데이터의 안정성을 높이는 효과적인 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 개발 요구사항은 단순히 데이터를 고정하는 것 이상을 필요로 할 때가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;특정 조건 하에서만 속성 변경을 허용하거나, 값 할당 시 자동으로 유효성 검사를 수행하거나, 객체에 대한 접근 자체를 로깅&lt;/span&gt;&lt;/b&gt;하고 싶을 수 있습니다. &lt;code&gt;Object.freeze&lt;/code&gt;만으로는 이러한 세밀한 제어가 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 활용할 수 있는 강력한 자바스크립트 기능이 바로 &lt;b&gt;&lt;code&gt;Proxy&lt;/code&gt;&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;한동훈님 유튜브 proxy강의&quot; href=&quot;https://youtu.be/Vio6njk99Z4?si=6ETwJ_rkHbpR6u-M&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://youtu.be/Vio6njk99Z4?si=6ETwJ_rkHbpR6u-M&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=Vio6njk99Z4&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/IuePA/hyYIgV5yt0/oA6Cgs49gf9Su1CktTXy70/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/niC7O/hyYFypAfsH/WHcQCm57RGkIGDJ6eqjba1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;제발 프록시 객체를 사용해보세요. 제발 한 번만 맛을 봐주세요. 이 맛을 보고 나면 과거로 돌아&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/Vio6njk99Z4&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;한동훈님 유튜브 proxy&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공부에 참고하는 유튜브 채널입니다. 너무 내용이 좋습니다. 여러분들도 얼렁 구독... !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy를 진짜 쉬운 말로 설명하면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;Proxy는 &quot;대리인&quot;&lt;/b&gt;&lt;br /&gt;누군가 대신해서 어떤 행동을 &quot;가로채서&quot; 처리해주는 역할입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어서:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너한테 오는 택배를 네가 직접 받는 게 아니라&lt;br /&gt;&lt;b&gt;대리인(Proxy)&lt;/b&gt;이 먼저 받고, &quot;이거 뭐지?&quot; 하면서 열어보고&lt;br /&gt;&quot;이건 위험한 거 같네?&quot; 하고 거절하거나 바꿔서 전달해주는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 Proxy는 &lt;b&gt;객체의 기본적인 동작(속성 접근, 할당, 열거, 함수 호출 등)에 대한 사용자 정의 행위를 정의&lt;/b&gt;할 수 있게 해주는, 일종의 &lt;b&gt;메타프로그래밍(Metaprogramming)&lt;/b&gt; 기능입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메타프로그래밍이란?&lt;/b&gt; 코드 자체가 다른 코드를 읽거나, 생성하거나, 분석하거나, 수정하는 등의 작업을 수행하는 프로그래밍 기법을 말합니다. Proxy는 객체의 동작 자체를 프로그래밍적으로 제어한다는 점에서 메타프로그래밍의 한 예시로 볼 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유튜브를 보며 배운내용을 복습하며 Proxy의 개념과 활용법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Proxy의 핵심 원리: 가로채기(Intercept)와 핸들러(Handler)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy는 이름 그대로 '대리인' 역할을 합니다. 원본 객체(&lt;code&gt;target&lt;/code&gt;)에 대한 직접적인 접근 대신,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy 객체를 통해 접근하도록 경로를 만드는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Proxy는 중간에서 객체에 가해지는 여러 작업(Operation)을 &lt;b&gt;가로채고(Intercept)&lt;/b&gt;, 미리 정의된 &lt;b&gt;핸들러(Handler)&lt;/b&gt; 객체의 로직을 실행합니다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;[코드 실행] ----&amp;gt; [Proxy 객체] ----&amp;gt; [Handler 객체 (규칙 검사 및 처리)] ----&amp;gt; [원본 Target 객체]&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;target&lt;/code&gt;&lt;/b&gt;: 실제 데이터와 로직을 가지고 있는 원본 객체입니다. Proxy가 감싸게 될 대상입니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;handler&lt;/code&gt;&lt;/b&gt;: 객체의 특정 작업(예: 속성 읽기)이 가로채졌을 때 어떤 동작을 수행할지 정의하는 함수(메서드)들을 담고 있는 객체입니다. 이 함수들을 &lt;b&gt;트랩(Trap)&lt;/b&gt;이라고 부릅니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;Proxy&lt;/code&gt; 객체&lt;/b&gt;: &lt;code&gt;new Proxy(target, handler)&lt;/code&gt; 문법으로 생성됩니다. 이제 이 Proxy 객체를 통해 &lt;code&gt;target&lt;/code&gt;에 접근하면, &lt;code&gt;handler&lt;/code&gt;에 정의된 해당 트랩이 실행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;974&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m39Vl/btsNnMf4ouL/t2u6oT7qKl62XWKzmRpcS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m39Vl/btsNnMf4ouL/t2u6oT7qKl62XWKzmRpcS1/img.png&quot; data-alt=&quot;한동훈님의 프록시를 연습하는 법&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m39Vl/btsNnMf4ouL/t2u6oT7qKl62XWKzmRpcS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm39Vl%2FbtsNnMf4ouL%2Ft2u6oT7qKl62XWKzmRpcS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;797&quot; height=&quot;974&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;974&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;한동훈님의 프록시를 연습하는 법&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용법 예시&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 1. 원본 객체
const target = {
  _id: &quot;user123&quot;, // 내부적으로 사용되는 ID (직접 노출하고 싶지 않음)
  name: &quot;Alice&quot;,
  age: 30
};

// 2. 핸들러 객체 정의
const handler = {
  // 속성 읽기(get) 트랩
  get(targetObj, propName) {
    console.log(`[Proxy Log] Reading property: ${propName}`);
    // '_'로 시작하는 속성은 외부에서 접근 제한
    if (String(propName).startsWith('_')) {
      console.warn(`[Proxy Warn] Access denied for private property: ${propName}`);
      return undefined;
    }
    // 일반 속성은 원본 객체에서 값을 반환 (Reflect 사용 권장)
    return Reflect.get(targetObj, propName);
  },
  // 속성 설정(set) 트랩
  set(targetObj, propName, newValue) {
    console.log(`[Proxy Log] Setting property: ${propName} = ${newValue}`);

    // 나이(age) 유효성 검사: 0 이상 150 이하 정수
    if (propName === 'age') {
      if (!Number.isInteger(newValue) || newValue &amp;lt; 0 || newValue &amp;gt; 150) {
        console.error(`[Proxy Error] Invalid age: ${newValue}. Age must be an integer between 0 and 150.`);
        // 유효하지 않으면 변경을 거부 (false 반환)
        // throw new TypeError('Invalid age'); // 에러를 던지는 방식도 가능
        return false;
      }
    }
    // 이름(name)은 빈 문자열 불가
    if (propName === 'name') {
        if (typeof newValue !== 'string' || newValue.trim() === '') {
            console.error(`[Proxy Error] Name cannot be empty.`);
            return false;
        }
    }

    // 유효성 검사 통과 시 원본 객체에 값 설정 (Reflect 사용 권장)
    const success = Reflect.set(targetObj, propName, newValue);
    if (success) {
      console.log(`[Proxy Log] Property ${propName} set successfully.`);
    }
    return success; // 성공 여부 반환
  }
};

// 3. Proxy 생성
const user = new Proxy(target, handler);

// --- Proxy 객체 사용 ---
console.log(user.name);   // Alice (정상 접근, 로그 출력)
console.log(user.age);    // 30 (정상 접근, 로그 출력)
console.log(user._id);    // undefined (접근 제한, 경고 출력)

user.age = 31;            // 정상 변경 (로그 출력)
console.log(user.age);    // 31

user.age = 200;           // 실패! (유효성 검사 실패, 에러 로그 출력)
console.log(user.age);    // 31 (값 변경 안 됨)

user.name = &quot;  &quot;;         // 실패! (유효성 검사 실패, 에러 로그 출력)
console.log(user.name);   // Alice (값 변경 안 됨)

// 주의: 원본 객체에 직접 접근하면 Proxy가 작동하지 않음!
target.age = -10;
console.log(target.age);  // -10 (Proxy 거치지 않고 직접 변경됨)
console.log(user.age);    // -10 (Proxy로 읽어도 변경된 값이 보임)&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;Reflect&lt;/code&gt;와 함께 사용하는 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예제에서 &lt;code&gt;Reflect.get()&lt;/code&gt;과 &lt;code&gt;Reflect.set()&lt;/code&gt;을 사용했습니다. &lt;code&gt;targetObj[propName]&lt;/code&gt;이나 &lt;code&gt;targetObj[propName] = newValue&lt;/code&gt;를 직접 사용하는 대신 &lt;code&gt;Reflect&lt;/code&gt;를 사용하는 것이 권장되는 이유는 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기본 동작 보장:&lt;/b&gt; &lt;code&gt;Reflect&lt;/code&gt;의 메서드는 해당 작업의 기본적인 내부 동작을 그대로 호출합니다. 직접 속성에 접근하는 것보다 예측 가능하고 일관된 동작을 보장합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과 반환:&lt;/b&gt; &lt;code&gt;Reflect.set()&lt;/code&gt;이나 &lt;code&gt;Reflect.deleteProperty()&lt;/code&gt; 같은 메서드는 작업의 성공 여부를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt; 값으로 반환해줍니다. 이를 통해 핸들러 내에서 후속 처리를 하거나 &lt;code&gt;set&lt;/code&gt; 트랩에서 정확한 값을 반환하기 용이합니다. (직접 할당(&lt;code&gt;=&lt;/code&gt;)은 항상 &lt;code&gt;true&lt;/code&gt;처럼 동작하는 경우가 많아 에러 상황을 놓칠 수 있습니다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;this&lt;/code&gt; 문제 방지:&lt;/b&gt; 복잡한 경우(getter/setter가 있는 객체 등)에 발생할 수 있는 &lt;code&gt;this&lt;/code&gt; 컨텍스트 문제를 피하는 데 도움이 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 말해, &lt;b&gt;Proxy 핸들러 내에서는 &lt;code&gt;Reflect&lt;/code&gt;를 사용하여 원본 객체의 기본 동작을 수행하는 것이 더 안전하고 표준적인 방법&lt;/b&gt;입니다. (한동훈님 유튜브에서 배움)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다양한 활용 사례&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy는 &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt; 외에도 다양한 트랩을 제공하여 폭넓은 활용이 가능합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유효성 검사 (Validation):&lt;/b&gt; 위 예시처럼 데이터 입력/수정 시 규칙을 강제합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;접근 제어 (Access Control):&lt;/b&gt; 사용자 권한에 따라 특정 속성 접근을 제한합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로깅 및 분석 (Logging &amp;amp; Analytics):&lt;/b&gt; 객체 사용 패턴을 추적하거나 디버깅 정보를 남깁니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가상 속성 (Virtual Properties):&lt;/b&gt; 실제로는 존재하지 않지만, 접근 시 특정 계산을 통해 값을 반환하는 속성을 만들 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 바인딩 및 상태 관리:&lt;/b&gt; 객체 변경 시 자동으로 UI를 업데이트하거나 관련 로직을 트리거하는 데 활용될 수 있습니다. (많은 프레임워크/라이브러리가 내부적으로 유사한 원리를 사용합니다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기타 트랩 활용:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;has(target, prop)&lt;/code&gt;: &lt;code&gt;in&lt;/code&gt; 연산자를 가로챕니다. (&lt;code&gt;'name' in user&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deleteProperty(target, prop)&lt;/code&gt;: &lt;code&gt;delete&lt;/code&gt; 연산자를 가로챕니다. (&lt;code&gt;delete user.age&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apply(target, thisArg, args)&lt;/code&gt;: 함수 호출을 가로챕니다. (Proxy 대상이 함수일 경우)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;construct(target, args)&lt;/code&gt;: &lt;code&gt;new&lt;/code&gt; 연산자를 이용한 생성자 호출을 가로챕니다. (Proxy 대상이 생성자 함수일 경우)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Proxy 사용 시 주의사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원본 객체 직접 접근:&lt;/b&gt; Proxy를 생성해도 원본 객체(&lt;code&gt;target&lt;/code&gt;)는 여전히 존재하며, 직접 접근할 수 있습니다. Proxy의 규칙을 적용하려면 반드시 Proxy 객체를 통해 접근해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디버깅:&lt;/b&gt; 개발자 도구에서 Proxy 객체를 보면 내부 구조가 바로 보이지 않아 디버깅이 다소 까다로울 수 있습니다. &lt;code&gt;handler&lt;/code&gt; 내부에 로그를 잘 남기는 것이 중요합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능:&lt;/b&gt; 중간 단계를 거치므로 아주 미미한 성능 오버헤드가 발생할 수 있습니다. 대부분의 애플리케이션에서는 문제가 되지 않지만, 극단적인 성능 최적화가 필요한 경우 고려해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;현대 개발 환경과 Proxy&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 웹 개발에서는 React, Vue, Svelte 같은 프레임워크와 Redux, Zustand 같은 상태 관리 라이브러리가 널리 사용됩니다. 이러한 도구들은 자체적인 반응성 시스템이나 상태 관리 패턴을 통해 데이터 변경 감지 및 제어를 효율적으로 처리하는 경우가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때문에 개발자가 직접 Proxy를 낮은 레벨에서 사용할 필요성은 예전보다 줄어들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 상태 관리 라이브러리는 특정 함수(Reducer, Setter)를 통해서만 상태 변경을 허용하도록 강제하여 Proxy의 &lt;code&gt;set&lt;/code&gt; 트랩과 유사한 효과(변경 경로 제어)를 달성합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론: 언제 Proxy를 고려해야 할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 현대 프레임워크와 라이브러리가 많은 부분을 추상화해주었지만, Proxy는 여전히 자바스크립트의 강력하고 유용한 기능입니다. 특히 다음과 같은 상황에서 Proxy 사용을 고려해볼 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프레임워크/라이브러리 외부:&lt;/b&gt; 순수 자바스크립트 환경에서 객체 동작에 대한 세밀한 제어가 필요할 때.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고급 유효성 검사/접근 제어:&lt;/b&gt; 라이브러리가 제공하는 기능 이상으로 복잡하거나 특수한 규칙을 객체 레벨에서 적용하고 싶을 때.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내부 동작 학습:&lt;/b&gt; 프레임워크나 라이브러리가 어떻게 객체 변화를 감지하고 반응하는지 그 원리를 이해하고 싶을 때 Proxy는 좋은 학습 도구가 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Object.freeze&lt;/code&gt;가 데이터 자체를 보호하는 데 중점을 둔다면, &lt;code&gt;Proxy&lt;/code&gt;는 데이터에 접근하고 상호작용하는 &lt;b&gt;'행위'를 제어하고 관찰&lt;/b&gt;하는 데 더 강력한 기능을 제공합니다. 이 둘의 차이를 이해하고 상황에 맞게 활용한다면 더 견고하고 안정적인 코드를 작성하는 데 큰 도움이 될 것입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 자바스크립트 Proxy에 대해 조금 더 깊이 있게 알아보았습니다. 주니어 프론트엔드개발자로 이러한 고민을 해본적이 최근에는 없었습니다. 하지만 하나하나 알아가며 너무 즐거운 공부를 요즘 하는것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한동훈님 유튜브 정말 추천합니다 꼭 보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;궁금한 점은 언제든 댓글로 남겨주세요!&lt;/p&gt;</description>
      <category>JavaScript</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/11</guid>
      <comments>https://cwnsgh.tistory.com/entry/%F0%9F%9B%A1%EF%B8%8F-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Proxy-%EB%82%B4-%EA%B0%9D%EC%B2%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%98%91%EB%98%91%ED%95%9C-%EB%AC%B8%EC%A7%80%EA%B8%B0#entry11comment</comments>
      <pubDate>Wed, 16 Apr 2025 17:55:38 +0900</pubDate>
    </item>
    <item>
      <title>  Object.freeze()로 안전하게 상태를 보호하는 법 &amp;mdash; 불변성(immutability)의 모든 것</title>
      <link>https://cwnsgh.tistory.com/entry/%F0%9F%94%92-Objectfreeze%EB%A1%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%EC%83%81%ED%83%9C%EB%A5%BC-%EB%B3%B4%ED%98%B8%ED%95%98%EB%8A%94-%EB%B2%95-%E2%80%94-%EB%B6%88%EB%B3%80%EC%84%B1immutability%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 복잡한 웹 애플리케이션을 만들다 보면 '상태 관리'라는 거대한 벽에 부딪히곤 합니다. 데이터가 어디서 어떻게 변하는지 추적하기 어렵고, 예상치 못한 버그 때문에 고생한 경험, 다들 한 번쯤 있으시죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 핵심적인 개념인 &lt;b&gt;불변성(Immutability)&lt;/b&gt;과, 이를 자바스크립트에서 쉽게 구현하도록 도와주는 &lt;b&gt;&lt;code&gt;Object.freeze()&lt;/code&gt;&lt;/b&gt;에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TWLUP/btsNlNfQJXM/sXfHicj3WQOyafKQfpQLb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TWLUP/btsNlNfQJXM/sXfHicj3WQOyafKQfpQLb1/img.png&quot; data-alt=&quot;gpt가 만들어준 썸네일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TWLUP/btsNlNfQJXM/sXfHicj3WQOyafKQfpQLb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTWLUP%2FbtsNlNfQJXM%2FsXfHicj3WQOyafKQfpQLb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;gpt가 만들어준 썸네일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  데이터가 마음대로 바뀌면 왜 위험할까요? (양방향 데이터 바인딩의 함정)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거 또는 일부 프레임워크에서 사용되던 &lt;b&gt;양방향 데이터 바인딩&lt;/b&gt;은 화면과 데이터가 서로를 직접 수정할 수 있어 편리해 보였습니다. 하지만 앱이 복잡해지면 데이터 변경의 원인을 찾기 어려워지고, 이는 예기치 못한 버그와 디버깅 지옥으로 이어지기 쉽습니다. 그래서 &quot;상당히 위험한 패턴&quot;이라고 불리기도 하죠.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✨ 그래서 등장한 단방향 데이터 흐름과 불변성!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해 &lt;b&gt;단방향 데이터 흐름&lt;/b&gt; (Flux 패턴, Redux, React의 &lt;code&gt;useState&lt;/code&gt; 등) 개념이 중요해졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cwnsgh.tistory.com/entry/FLUX-%ED%8C%A8%ED%84%B4%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EB%8B%A8%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%9D%90%EB%A6%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.04.15 - [React] - FLUX 패턴에 대해서 (단방향 데이터 흐름)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1744728508436&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;FLUX 패턴에 대해서 (단방향 데이터 흐름)&quot; data-og-description=&quot;안녕하세요! 복잡한 웹 애플리케이션을 만들다 보면 '상태 관리'라는 거대한 벽에 부딪히곤 하죠. 많은 분들이 Redux 같은 라이브러리를 사용하며 이 문제를 해결하려 하지만, 때로는 라이브러리 &quot; data-og-host=&quot;cwnsgh.tistory.com&quot; data-og-source-url=&quot;https://cwnsgh.tistory.com/entry/FLUX-%ED%8C%A8%ED%84%B4%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EB%8B%A8%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%9D%90%EB%A6%84&quot; data-og-url=&quot;https://cwnsgh.tistory.com/entry/FLUX-%ED%8C%A8%ED%84%B4%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EB%8B%A8%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%9D%90%EB%A6%84&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lo8Iw/hyYIizyvwi/8MZMKQDX6uDRIJl8VhAys0/img.png?width=800&amp;amp;height=431&amp;amp;face=0_0_800_431,https://scrap.kakaocdn.net/dn/jtt4S/hyYB7NQfHE/YEg6H1t4LicGZWAfXVJ9M1/img.png?width=800&amp;amp;height=431&amp;amp;face=0_0_800_431,https://scrap.kakaocdn.net/dn/bsAya0/hyYIdyflmm/XoOVzngrrtySFDVEtma2J1/img.png?width=1280&amp;amp;height=691&amp;amp;face=0_0_1280_691&quot;&gt;&lt;a href=&quot;https://cwnsgh.tistory.com/entry/FLUX-%ED%8C%A8%ED%84%B4%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EB%8B%A8%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%9D%90%EB%A6%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwnsgh.tistory.com/entry/FLUX-%ED%8C%A8%ED%84%B4%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EB%8B%A8%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%9D%90%EB%A6%84&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lo8Iw/hyYIizyvwi/8MZMKQDX6uDRIJl8VhAys0/img.png?width=800&amp;amp;height=431&amp;amp;face=0_0_800_431,https://scrap.kakaocdn.net/dn/jtt4S/hyYB7NQfHE/YEg6H1t4LicGZWAfXVJ9M1/img.png?width=800&amp;amp;height=431&amp;amp;face=0_0_800_431,https://scrap.kakaocdn.net/dn/bsAya0/hyYIdyflmm/XoOVzngrrtySFDVEtma2J1/img.png?width=1280&amp;amp;height=691&amp;amp;face=0_0_1280_691');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;FLUX 패턴에 대해서 (단방향 데이터 흐름)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 복잡한 웹 애플리케이션을 만들다 보면 '상태 관리'라는 거대한 벽에 부딪히곤 하죠. 많은 분들이 Redux 같은 라이브러리를 사용하며 이 문제를 해결하려 하지만, 때로는 라이브러리&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwnsgh.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리한 글입니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 간단히 말해, 데이터는 &lt;code&gt;Action &amp;rarr; Dispatcher &amp;rarr; Store &amp;rarr; View&lt;/code&gt;와 같이 &lt;b&gt;정해진 흐름을 따라 한 방향으로만&lt;/b&gt; 흘러야 합니다. 핵심은 &lt;b&gt;상태(State)를 아무 곳에서나 직접 수정하지 못하도록 제한하는 것&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 구조에서 &lt;b&gt;불변성(Immutability)&lt;/b&gt; 이 중요한 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;불변성이란 &lt;b&gt;데이터(객체, 배열 등)가 생성된 이후에는 그 내용을 직접 수정하지 않고, 변경이 필요할 경우 항상 새로운 복사본을 만들어 사용하는 것&lt;/b&gt;을 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React, Redux, Zustand 등 주요 상태 관리 도구들은 이 개념을 기반으로 설계되어 있습니다. 그리고 이 불변성 개념을 가장 잘 보여주는 도구 중 하나가 바로 &lt;b&gt;&lt;code&gt;Object.freeze()&lt;/code&gt;&lt;/b&gt;입니다. 오늘은 &lt;code&gt;freeze()&lt;/code&gt;를 중심으로, 왜 불변성이 중요한지, 어떻게 활용되는지 쉽게 정리해보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  가변 vs 불변 &amp;mdash; 칠판과 종이 비유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불변성 개념이 처음에는 조금 헷갈릴 수 있습니다. 칠판과 종이 비유로 쉽게 이해해 봅시다!&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;가변적인 방식 (Mutable): 칠판&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;칠판에 &quot;고양이: 1&quot;이라고 적습니다.&lt;/li&gt;
&lt;li&gt;값을 2로 바꾸려면? 지우개로 '1'을 지우고 그 자리에 '2'를 씁니다.&lt;/li&gt;
&lt;li&gt;➡️ &lt;b&gt;원본 칠판 내용 자체가 수정&lt;/b&gt;되었습니다. 일반적인 객체 수정 방식이죠.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불변적인 방식 (Immutable): 코팅된 종이&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;상태 1:&lt;/b&gt; 종이 한 장에 &quot;고양이: 1&quot;이라고 적고, &lt;b&gt;코팅 (&lt;code&gt;Object.freeze&lt;/code&gt;)&lt;/b&gt;을 합니다. 이 종이는 이제 수정할 수 없는 첫 번째 상태가 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;값 변경 필요:&lt;/b&gt; 고양이가 2마리가 되었다고 알려야 합니다. 코팅된 종이는 수정할 수 없으니, &lt;b&gt;완전히 새로운 종이를 꺼냅니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태 2 생성:&lt;/b&gt; 새 종이에 &quot;고양이: 2&quot;라고 적고, 마찬가지로 &lt;b&gt;코팅 (&lt;code&gt;Object.freeze&lt;/code&gt;)&lt;/b&gt;을 합니다. 이것이 두 번째 상태입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참조 변경:&lt;/b&gt; 이제 누군가 &quot;현재 고양이 상태가 뭐야?&quot;라고 물으면, 우리는 첫 번째 종이(&quot;고양이: 1&quot;)가 아닌, &lt;br /&gt;&lt;b&gt;두 번째 종이(&quot;고양이: 2&quot;)를 보여줍니다.&lt;/b&gt; (즉, 상태를 가리키는 변수가 이제 두 번째 종이를 가리킵니다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 비유처럼, 불변성 패턴에서의 &quot;값 변경&quot;은 원본 객체 자체는 절대 건드리지 않고, &lt;br /&gt;변경이 필요할 때마다 새로운 복사본 객체를 만들어 참조(가리키는 대상)를 교체하는 것입니다. &lt;br /&gt;각각의 상태(종이)는 그 자체로 불변하지만, 우리가 '현재 상태'로 바라보는 대상이 바뀌는 것이죠.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;code&gt;Object.freeze()&lt;/code&gt;란? 객체를 얼려버리자!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Object.freeze()&lt;/code&gt;는 이름 그대로 객체를 '동결'시켜 변경할 수 없도록 만드는 자바스크립트 내장 메서드입니다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;const myCat = {
  name: &quot;쮸롱&quot;,
  age: 1
};

// 쮸롱이 정보를 얼려버렷!
Object.freeze(myCat);

// 이제 수정 시도는 모두 무시됩니다. (Strict Mode에서는 TypeError 발생)
myCat.age = 2;          // ❌ 안 바뀜!
console.log(myCat.age); // 1 (그대로)

delete myCat.name;      // ❌ 삭제 안 됨!
console.log(myCat.name);// &quot;쮸롱&quot; (그대로)

myCat.favoriteToy = &quot;츄르&quot;; // ❌ 추가도 안 됨!
console.log(myCat.favoriteToy); // undefined&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;freeze&lt;/code&gt;된 객체는 &lt;b&gt;속성을 추가 / 삭제 / 수정할 수 없습니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;즉, &lt;b&gt;객체를 &quot;읽기 전용(read-only)&quot;으로 만든다&lt;/b&gt;고 생각하면 쉽습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;주의: &lt;code&gt;Object.freeze()&lt;/code&gt;는 얕은 동결(Shallow Freeze)입니다!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Object.freeze()&lt;/code&gt;는 객체의 &lt;b&gt;1단계 깊이&lt;/b&gt;만 동결합니다. 객체 내부에 또 다른 객체(중첩 객체)가 있다면, 그 내부 객체까지 자동으로 얼지는 않습니다. (내부 객체까지 얼리려면 &lt;code&gt;deepFreeze&lt;/code&gt; 함수를 따로 구현해야 합니다.)&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;const gameState = {
  level: 5,
  user: { name: &quot;Hero&quot;, hp: 100 } // 중첩 객체
};
Object.freeze(gameState);
gameState.user.hp = 50; // ✅ 내부 객체는 변경 가능!&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  &quot;값을 바꾼다&quot;는 것의 진짜 의미 (복사하고 교체!)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;얼어붙은 객체는 값을 못 바꾼다면서요? 그럼 상태 업데이트는 어떻게 해요?&quot;&lt;br /&gt;앞서 '종이 비유'에서 봤듯이, &lt;b&gt;원본을 건드리지 않고 새 복사본을 만들어 교체&lt;/b&gt;하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const settings = Object.freeze({ // 초기 설정 (상태 1 - 첫 번째 종이)
  theme: &quot;dark&quot;,
  fontSize: 14
});

// 테마를 'light'로 바꿔야 하는 상황!
// 1. 복사본 만들기 (스프레드 문법 ... 사용)
const newSettings = {
  ...settings,      // 기존 설정 내용을 복사하고
  theme: &quot;light&quot;    // theme 속성만 새 값으로 덮어쓰기
};

// 2. (선택사항) 새 객체도 얼려주기 (상태 2 - 새 종이)
const frozenNewSettings = Object.freeze(newSettings);

console.log(&quot;새 설정:&quot;, frozenNewSettings); // { theme: 'light', fontSize: 14 }
console.log(&quot;원본 설정:&quot;, settings);      // { theme: 'dark', fontSize: 14 } (그대로!)

// --- 여기서 중요한 포인트! ---
let currentSettings = settings; // 처음엔 원본 설정을 가리킴
currentSettings = frozenNewSettings; // 이제 '현재 설정'은 새 객체를 가리킴!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;잠깐! 여기서 &quot;값을 바꾼 게 아닌 거 아니냐?&quot;는 의문이 들 수 있습니다. 아주 정확한 지적입니다!&amp;nbsp; (저도이렇게생각했습니다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄밀히 말해, &lt;code&gt;{ theme: 'dark', fontSize: 14 }&lt;/code&gt; 라는 &lt;b&gt;원본 객체의 내용 자체는 전혀 바뀌지 않았습니다.&lt;/b&gt; &lt;br /&gt;(마치 코팅된 첫 번째 종이처럼요.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;불변성에서 &quot;값을 바꾼다&quot;는 것은 다음 두 단계를 의미합니다:&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;새로운 상태 값(객체) 생성:&lt;/b&gt; 변경사항(&lt;code&gt;theme: 'light'&lt;/code&gt;)이 적용된 &lt;b&gt;완전히 새로운 객체&lt;/b&gt;(&lt;code&gt;{ theme: 'light', fontSize: 14 }&lt;/code&gt;)를 메모리에 만듭니다. (새 종이를 만듭니다.)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참조(Reference) 변경:&lt;/b&gt; 상태를 가리키던 &lt;b&gt;변수&lt;/b&gt;(위 코드의 &lt;code&gt;currentSettings&lt;/code&gt;)가 이제 &lt;b&gt;새로 만들어진 객체&lt;/b&gt;를 가리키도록 &lt;b&gt;연결을 바꿉니다.&lt;/b&gt; (손에 든 종이를 새 종이로 바꿉니다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론:&lt;/b&gt; 원본 값 자체를 수정(Mutation)한 것은 아니지만, &lt;br /&gt;프로그램이 바라보는 &lt;b&gt;'현재 상태'를 나타내는 객체가 새로운 객체로 교체&lt;/b&gt;되었기 때문에, &lt;br /&gt;결과적으로 &lt;b&gt;상태가 변경된 효과&lt;/b&gt;를 얻는 것입니다. 이것이 불변성을 유지하면서 상태를 업데이트하는 핵심 원리입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  직접 접근 막기: 왜 중요할까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;code&gt;Object.freeze()&lt;/code&gt;를 사용하지 않아서 다음과 같은 코드가 가능하다면 어떨까요?&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;// 어딘가에서 갑자기 상태를 직접 수정한다면?
appState.user.isAdmin = true; //   누가? 언제? 왜?&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 객체를 직접 수정하면, &lt;b&gt;누가 언제 어떻게 상태를 바꿨는지 추적하기 매우 어려워집니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버그가 발생했을 때 원인을 찾기 힘들어지죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단방향 데이터 흐름(Flux, Redux 등)은 &lt;b&gt;상태는 오직 정해진 '공식 경로'(Action, Reducer 등)를 통해서만 변경되어야 한다&lt;/b&gt;는 원칙을 세워 이런 혼란을 막습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Object.freeze()&lt;/code&gt;는 이 원칙을 코드 레벨에서 &lt;b&gt;기술적으로 강제&lt;/b&gt;하여 실수를 방지하는 효과적인 방법입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  잠깐, 매번 새 객체를 만들면 메모리 낭비 아닌가요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맞습니다. 표면적으로 보면 이전 상태 객체가 메모리에 남아있어 낭비처럼 보일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실제로는 다음과 같은 이유로 크게 걱정하지 않아도 괜찮습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;구조적 공유 (Structural Sharing):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체를 복사할 때 &lt;b&gt;변경된 부분만 새로 만들고, 변경되지 않은 부분은 이전 객체의 메모리 참조를 그대로 공유&lt;/b&gt;하는 최적화 기법입니다.&lt;/li&gt;
&lt;li&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const state1 = {
  user: {
    name: &quot;쮸롱&quot;,
    age: 1,
  },
  settings: {
    theme: &quot;dark&quot;,
  },
};
const state2 = {
  ...state1,
  user: {
    ...state1.user,
    age: 2,
  },
};

// state2를 만들 때, settings 객체는 state1의 것을 그대로 참조합니다. (메모리 절약!)

console.log(state1.settings === state2.settings); // true&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;특히 상태 관리 라이브러리(Immer 등)는 이 기법을 적극 활용하여 효율을 높입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가비지 컬렉션 (Garbage Collection):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;더 이상 아무도 참조하지 않는 이전 상태 객체(쓸모 없어진 &lt;code&gt;고양이: 1&lt;/code&gt; 종이)는 자바스크립트 엔진의 가비지 컬렉터가 &lt;b&gt;자동으로 메모리에서 회수&lt;/b&gt;합니다. 영원히 남아있는 것이 아닙니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;얻는 이점과의 트레이드오프:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;변경 추적 용이:&lt;/b&gt; 이전 상태와 새 상태가 명확히 구분되어 디버깅이 쉬워집니다. (Time Travel Debugging!)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 최적화 (React 등):&lt;/b&gt; 객체 참조(&lt;code&gt;===&lt;/code&gt;)만 비교하면 변경 여부를 매우 빠르게 알 수 있어, 불필요한 화면 업데이트를 건너뛸 수 있습니다. (&lt;code&gt;React.memo&lt;/code&gt; 등)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예측 가능성 및 안정성:&lt;/b&gt; 데이터 흐름이 명확해져 코드 예측이 쉽고 부작용이 줄어듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로, 약간의 메모리 오버헤드를 감수하는 대신 개발 편의성, 디버깅 용이성, 성능 최적화 등 더 큰 이점을 얻기 때문에 불변성 패턴이 널리 사용됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Object.freeze()&lt;/code&gt;는 단순해 보이지만, &lt;b&gt;안정적인 상태 관리의 핵심 철학인 '불변성'을 코드 레벨에서 지키도록 도와주는 강력한 도구&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 React, Redux처럼 상태의 일관성과 예측 가능성이 중요한 환경에서 &lt;code&gt;Object.freeze()&lt;/code&gt; 를 잘 활용하면 코드의 안정성과 유지보수성을 크게 향상시킬 수 있습니다. &quot;값을 바꾼다&quot;는 것의 의미를 정확히 이해하고 사용한다면 더욱 효과적일 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에는 같이 사용하면 더 좋은 proxy에 대해 알아볼 생각입니다 !&lt;/p&gt;</description>
      <category>JavaScript</category>
      <author>쮸롱이</author>
      <guid isPermaLink="true">https://cwnsgh.tistory.com/10</guid>
      <comments>https://cwnsgh.tistory.com/entry/%F0%9F%94%92-Objectfreeze%EB%A1%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%EC%83%81%ED%83%9C%EB%A5%BC-%EB%B3%B4%ED%98%B8%ED%95%98%EB%8A%94-%EB%B2%95-%E2%80%94-%EB%B6%88%EB%B3%80%EC%84%B1immutability%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83#entry10comment</comments>
      <pubDate>Tue, 15 Apr 2025 23:55:56 +0900</pubDate>
    </item>
  </channel>
</rss>