<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>lsh__97.log</title>
        <link>https://velog.io/</link>
        <description>기록 기록 기록..</description>
        <lastBuildDate>Mon, 11 Apr 2022 02:38:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>lsh__97.log</title>
            <url>https://images.velog.io/images/lsh__97/profile/237123df-814b-4311-812f-b0e251cc5aa0/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. lsh__97.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/lsh__97" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[React (6) Fragments, Portals]]></title>
            <link>https://velog.io/@lsh__97/React-6-Fragments-Portals-Refs</link>
            <guid>https://velog.io/@lsh__97/React-6-Fragments-Portals-Refs</guid>
            <pubDate>Mon, 11 Apr 2022 02:38:57 GMT</pubDate>
            <description><![CDATA[<h1 id="fragments-portals">Fragments, Portals</h1>
<h2 id="jsx-제한-사항-및-해결-방법">JSX 제한 사항 및 해결 방법</h2>
<p>JSX는 기본적으로 여러 요소들을 같이 사용할 경우 이들을 감싸주는 요소가 필요합니다.</p>
<p>이때 &quot;div&quot; 태그를 사용해서 wrapping 해주면 다음과 같은 문제점이 발생 합니다. </p>
<ol>
<li>실제 DOM으로 렌더릴 될때 리액트 컴포넌트가 많이 중첩될 수 있다.</li>
<li>페이지에 어떤 의미나 구조적인 의미를 가지지 않지만 스타일을 망칠 수도 있다. </li>
<li>너무 많은 HTML요소를 렌더링 하기 때문에 애플리케이션이 느려질 수도 있다.</li>
</ol>
<p>그래서 이를 위한 해결 방법으로는 다음과 같은 방법들이 있습니다.</p>
<h3 id="-빈-태그-사용하기">&lt;&gt; &lt;/&gt; 빈 태그 사용하기</h3>
<p>장점으로는 짧고 간편합니다, 그리고 실제 HTML요소를 DOM에 렌더링하지 않는다. 
하지만 프로젝트 설정에 따라 다르기 때문에 빌드 워크플로가 이를 지원 해야 사용할 수 있다. </p>
<pre><code>    &lt;&gt;
        &lt;div&gt;HI&lt;/div&gt;
        &lt;div&gt;HIII&lt;/div&gt;
    &lt;/&gt;</code></pre><h3 id="fragment-사용">Fragment 사용</h3>
<p>이것도 마찬가지로 실제 HTML요소를 DOM에 렌더링 하지 않는다.
그리고 리액트에 내장되어 있기 때문에 항상 사용할 수 있다.</p>
<p>사용 방법은 Fragment를 따로 임포트해서 사용하거나 React.Fragment를 사용하면 된다.</p>
<pre><code>    &lt;React.Fragment&gt;
        &lt;div&gt;HI&lt;/div&gt;
        &lt;div&gt;HIII&lt;/div&gt;
    &lt;/React.Fragment&gt;</code></pre><h3 id="wrapper-컴포넌트-사용">Wrapper 컴포넌트 사용</h3>
<p>Wrapper 컴포넌트를 따로 만들어서 사용 해도 DOM에 영향을 주지 않는다. 
다음과 같이 작성하면 빈껍데기에 하위 요소를 렌더링 해주는거기 때문에 위에 두 방법과 동일하다.</p>
<pre><code>    const Wrapper = props =&gt; {
        return {props.children}
    }
    export default Wrapper 

    &lt;Wrapper&gt;
        &lt;div&gt;HI&lt;/div&gt;
        &lt;div&gt;HIII&lt;/div&gt;
    &lt;/Wrapper&gt;</code></pre><h2 id="portal">Portal</h2>
<p><img src="https://velog.velcdn.com/images/lsh__97/post/fadf979f-3e03-44ab-a494-4a1d102b31b9/image.png
">
이전 포스팅에서 모달을 구현할때 위와 같은 방식으로 구현 하였는데 이때 스타일링을 통해서 동작은 잘하지만 구조적으로 봤을때 문제점이 생긴다. </p>
<p>*<em>우선 모달은 오버레이이다. *</em></p>
<p>오버레이는 전체 페이지 위에 표시되는 것을 말하는데 위와 같이 구현 했을때 다른 HTML 코드 안에 중첩 되어 렌더링 되기 때문에 스타일링을 통해 작동은 할지 몰라도 좋은 구조를 가지는 것은 아니다, 그리고 스크린 리더가 HTML 코드를 해석할 때 일반적인 오버레이로 인식하지 못 할 수도 있다. </p>
<p>또한 이것은 HTML 코드 안 깊은 곳에 자리 잡고 있기 때문에 다른 모든 내용에 대한 오버레이인지 명확하지 않다.</p>
<p><strong>이를 위한 해결 방법으로는 리액트의 포털을 사용하면 된다.</strong></p>
<h3 id="portal-사용법">Portal 사용법</h3>
<p>ReactDOM.createPortal은 렌더링될 HTML 내용을 지정해둔 포인터로 옮겨 주기 때문에 오버레이를 사용할때 사용하면 좋다.</p>
<p>이때 렌더링 되어야 하는 리액트 노드(<strong>반드시 JSX</strong>),DOM 엘리먼트</p>
<h4 id="1-public-폴더의-indexhtml렌더링되는-html파일에-렌더링-되어야-하는-포인터를-설정-해준다">1. public 폴더의 index.html(렌더링되는 html파일)에 렌더링 되어야 하는 포인터를 설정 해준다.</h4>
<pre><code>&lt;body&gt;
    &lt;div id=&quot;backdrop-root&quot;&gt;&lt;/div&gt;
    &lt;div id=&quot;overlay-root&quot;&gt;&lt;/div&gt;
    &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
&lt;/body&gt;</code></pre><h4 id="2-reactdom-을-임포트-해준다설치">2. ReactDOM 을 임포트 해준다(설치).</h4>
<pre><code>import ReactDom from &quot;react-dom&quot;</code></pre><h4 id="3-reactdomcreateportal-사용될-컴포넌트-생성">3. ReactDOM.createPortal 사용될 컴포넌트 생성</h4>
<pre><code>import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom&quot;;
import Button from &quot;../UI/Button&quot;;
import Card from &quot;../UI/Card&quot;;

import styles from &quot;./Modal.module.css&quot;;

const Backdrop = ({ onCloseModal }) =&gt; {
    return &lt;div className={styles.backdrop} onClick={onCloseModal}&gt;&lt;/div&gt;;
};

const ModalOverlay = ({ onCloseModal, message, title }) =&gt; {
    return (
        &lt;Card className={styles.modal}&gt;
            &lt;h2 className={styles.head}&gt;{title}&lt;/h2&gt;
            &lt;div className={styles.content}&gt;{message}&lt;/div&gt;
            &lt;div className={styles.control}&gt;
                &lt;Button type=&quot;button&quot; onClick={onCloseModal}&gt;
                    Okay
                &lt;/Button&gt;
            &lt;/div&gt;
        &lt;/Card&gt;
    );
};</code></pre><h4 id="4-reactdomcreateportal사용">4. ReactDOM.createPortal사용</h4>
<p>JSX안에서 사용되기 때문에 {}를 사용해준다.</p>
<pre><code>const ErrorModal = ({ onCloseModal, message, title }) =&gt; {
    return (
        &lt;React.Fragment&gt;
            {ReactDOM.createPortal(
                &lt;Backdrop onCloseModal={onCloseModal} /&gt;,
                document.getElementById(&quot;backdrop-root&quot;)
            )}
            {ReactDOM.createPortal(
                &lt;ModalOverlay
                    onCloseModal={onCloseModal}
                    title={title}
                    message={message}
                /&gt;,
                document.getElementById(&quot;backdrop-root&quot;)
            )}
        &lt;/React.Fragment&gt;
    );
};
export default ErrorModal;</code></pre><p>출처 <a href="https://www.udemy.com/course/best-react/">【글로벌 Best】 React 완벽 가이드 with Redux, Next.js, TypeScript
</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React (5) 연습 프로젝트]]></title>
            <link>https://velog.io/@lsh__97/React-5-%EC%97%B0%EC%8A%B5-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@lsh__97/React-5-%EC%97%B0%EC%8A%B5-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Wed, 06 Apr 2022 14:32:57 GMT</pubDate>
            <description><![CDATA[<h1 id="연습-프로젝트">연습 프로젝트</h1>
<img src="https://user-images.githubusercontent.com/59095793/161978097-f4bf4814-95a5-4a2c-aa99-f89acc64a61a.gif">

<p>지금 까지 배운 양방향 바인딩, 상향식 통신, 사용자 state를 관리하고 state를 통해 사용자 리스트 관리, 재사용 컴포넌트 사용등을 복습 할 수 있는 간단한 연습 프로젝트 였습니다.</p>
<h2 id="어려웠던-점">어려웠던 점</h2>
<p>원래는 유저 입력값을 검증 하는 과정에서 다음과 같이 코드를 작성하였습니다.</p>
<p>하지만 제가 생각한 결과가 나오지 않고 isValidName,isValidAge의 state가 바로 변경 되지 않아서 계속 시간을 낭비 했는데요🙄🙄 
이유는!! 
다음과 같이 함수 안에서 state의 변경이 생기면 함수가 종료된 뒤에 변경되는것을 몰라서 생긴일이였습니다.</p>
<pre><code>const NewForm = () =&gt; {
    const [name,setName] = useState(&#39;&#39;)
    const [age,setAge] = useState(&#39;&#39;)
       const [isValidName, setIsvalidName] = useState(true)
    const [isValidAge, setIsValidAge] = useState(true)

    const checkName = () =&gt; {
        if(name.trim().length === 0) setIsvalidName(false)
    }
    const checkAge = () =&gt; {
        if(age.trim().length === 0) setIsvalidName(false)
        if(+age &lt; 0) setIsvalidName(false)
    }
    const submitHandler = (event) =&gt; {
        event.preventDefault();
        checkName()
        checkAge() 
        if(isValidName &amp;&amp; isValidAge) {
            /*
                유저 객체 생성 및 전달 받은 props 함수를 통해 
                부모 컴포넌트로 유저 데이터 전달
                name, age의 state를 &#39;&#39;으로 저장
            */
        }else{
            // 에러 모달창 state 값 변경  
        }
    }
}</code></pre><p>그래서 state를 사용하지 않고 다음과 같이 코드를 변경하여 원하는 결과을 얻을 수 있었습니다!!😃🤣</p>
<pre><code>const NewForm = () =&gt; {
    const [name,setName] = useState(&#39;&#39;)
    const [age,setAge] = useState(&#39;&#39;)
    if (name.trim().length === 0 || age.trim().length === 0) {
            // 에러 메세지 저장 및 에러 모달 state 변경
            return;
        }
        if (+age &lt; 0 || +age &gt; 100) {
            // 에러 메세지 저장 및 에러 모달 state 변경
            return;
        }
        /*
           유저 객체 생성 및 전달 받은 props 함수를 통해 
           부모 컴포넌트로 유저 데이터 전달
           name, age의 state를 &#39;&#39;으로 저장
        */
    };
}</code></pre><h2 id="추가-사항">추가 사항</h2>
<p>추가로 유저 리스트의 목록을 지우는 버튼도 구현해봤습니다.</p>
<p><a href="https://sh-lee2.github.io/userList/">userList 깃헙 페이지</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React (3)]]></title>
            <link>https://velog.io/@lsh__97/React-3</link>
            <guid>https://velog.io/@lsh__97/React-3</guid>
            <pubDate>Sat, 02 Apr 2022 14:59:32 GMT</pubDate>
            <description><![CDATA[<h1 id="렌더링-리스트-및-조건부-content">렌더링 리스트 및 조건부 content</h1>
<h2 id="동적-렌더링">동적 렌더링</h2>
<p>아래와 같이 하드코딩하여 아이템 리스트를 렌더링 하면 아이템의 변화가 있을때 동적으로 변하지 않는다. 그렇다면 어떻게 동적으로 아이템들을 렌더링 할 수 있을까? </p>
<pre><code>const Expense = ({expenses}) =&gt;{
    return (
    &lt;&gt;
        &lt;ExpenseItem
            title={expenses.title}
            amount={expenses.amount}
            date={expenses.date}
         /&gt;
           &lt;ExpenseItem
            title={expenses.title}
            amount={expenses.amount}
            date={expenses.date}
         /&gt;
     &lt;/&gt;        
    )
}</code></pre><p>아래 코드와 같이 JSX에서 map메서드를 사용하여 코드를 작성하면 expenses의 값이 변경 되더라도 동적으로 렌더링 할 수 있다.!!😆</p>
<pre><code>const Expense = ({expenses}) =&gt;{
    return (
        &lt;&gt;
          {expenses.map((expense)=&gt;(
            &lt;ExpenseItem
                title={expense.title}
                amount={expense.amount}
                date={expense.date}
             /&gt;
          )}
          &lt;/&gt;         
    )
}</code></pre><p>하지만 위에서 처럼 코드를 작성하면 동작은 잘 되지만 한가지 경고를 받는다.😨😨
<img src="https://media.vlpt.us/images/lsh__97/post/cf880ba5-b350-4c0b-99a8-f8241b9196e1/image.png"></p>
<p>이때 Key는 React가 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕는다. key는 엘리먼트에 안정적인 고유성을 부여하기 위해 배열 내부의 엘리먼트에 지정해줘야 한다. </p>
<pre><code>const Expense = ({expenses}) =&gt;{
    return (
        &lt;&gt;
          {expenses.map((expense)=&gt;(
            &lt;ExpenseItem
                title={expense.title}
                amount={expense.amount}
                date={expense.date}
                key={expense.id}
             /&gt;
          )}
          &lt;/&gt;         
    )
}</code></pre><h3 id="key-선택">Key 선택</h3>
<p>key를 선택할때는 항목의 인덱스를 key로 사용하는 것 보다 해당 항목을 고유하게 식별할 수 있는 문자열을 사용하는것이 좋다.</p>
<p>만약 항목의 순서가 매번 바뀔수 있는 경우에 항목의 인덱스를 key로 사용해버리면 성능이 저하되거나 컴포넌트의 state와 관련된 문제가 발생할 수있다.</p>
<h2 id="조건부-렌더링">조건부 렌더링</h2>
<p>만약 아이템 리스트의 길이가 0일때 또는 0이상일때 렌더릴을 다르게 하고 싶다면 간단하게 삼항 연산자 또는 &amp;&amp;, 따로 변수를 지정해서 사용할 수 있다. </p>
<h3 id="삼항-연산자">삼항 연산자</h3>
<pre><code>{filteredExpenses.length === 0 ? (&lt;p&gt;지출 내역 없음.&lt;/p&gt;) : (
    filteredExpenses.map((expense) =&gt; (
        &lt;ExpenseItem
           title={expense.title}
           amount={expense.amount}
           date={expense.date}
           key={expense.id}
         /&gt;
     ))
)}</code></pre><h3 id="연산자">&amp;&amp; 연산자</h3>
<p>&amp;&amp; 연산자의 경우 앞의 조건이 참이면 실행된다. </p>
<pre><code>{filteredExpenses.length === 0 &amp;&amp; &lt;p&gt;지출 내역 없음.&lt;/p&gt;}
{filteredExpenses.length &gt; 0 &amp;&amp; filteredExpenses.map((expense) =&gt; (
  &lt;ExpenseItem
       title={expense.title}
       amount={expense.amount}
       date={expense.date}
       key={expense.id}
 /&gt;
  ))}</code></pre><h3 id="변수-지정">변수 지정</h3>
<p>이 경우가 가장 깔끔하다</p>
<pre><code>const Expense = (expens) =&gt; {
    let expensesContent = &lt;p&gt;지출 내역 없음.&lt;/p&gt;;
    if (filteredExpenses.length &gt; 0) {
        expensesContent = filteredExpenses.map((expense) =&gt; (
            &lt;ExpenseItem
                title={expense.title}
                amount={expense.amount}
                date={expense.date}
                key={expense.id}
            /&gt;
        ));
    }
    return (
        &lt;&gt;
            {expensesContent}
        &lt;/&gt;
    )
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[React (2)]]></title>
            <link>https://velog.io/@lsh__97/React-2</link>
            <guid>https://velog.io/@lsh__97/React-2</guid>
            <pubDate>Fri, 01 Apr 2022 15:29:18 GMT</pubDate>
            <description><![CDATA[<h1 id="리액트-state-및-이벤트-다루기">리액트 state 및 이벤트 다루기</h1>
<h2 id="handling-events">handling Events</h2>
<p>React의 모든 이벤트는 on으로 시작하고 함수를 값으로 필요로 한다.
아래의 예제에서는 onClick 이벤트를 사용한다.
이때 함수는 JSX내부에서 익명의 함수를 사용하는 것 보다 따로 함수를 정의 하여 사용하는것이 깔끔하고 더 좋다. </p>
<pre><code>function App(){
    const clickHandler = () =&gt; {
        console.log(&quot;clicked&quot;)
    }
    return (
    &lt;button onClick(clickHandler)&gt;click button&lt;/button&gt;
        )
}</code></pre><h2 id="usestate">useState()</h2>
<pre><code>function App(){
    let title = &quot;title&quot;
    const clickHandler=()=&gt;{
        title = &quot;update&quot;
    }
    return(
        &lt;&gt;
            &lt;div&gt;{title}&lt;/div&gt;
            &lt;button onClick={clickHandler}&gt;click&lt;/button&gt;
        &lt;/&gt;
    )
}</code></pre><p>위의 코드는 버튼을 클릭시 title값을 변경하여 보여주는 코드이다.
하지만 버튼을 클릭 해도 예상과 달리 변경된 title 값이 아닌 기존의 &quot;title&quot; 값만 볼 수 있다. 
이러한 이유는 리액트의 작동방식에 있다.
리액트는 처음 컴포넌트를 평가하고 나서 컴포넌트 안의 변수가 변해도 재평가 하지 않고 무시한다, 그렇기 때문에 title 변수가 변경 되더라도 컴포넌트의 변화는 없다!!!😨</p>
<p>*<em>그렇다면 어떻게 리액트가 컴포넌트를 재평가 하게 할 수 있을까? *</em></p>
<p>*<em>useState를 사용하면 된다. *</em>
useState를 사용하여 컴포넌트 내부 상태가 변경되면 리액트는 컴포넌트를 재평가 한다. </p>
<p>useState는 다음과 같이 사용된다. </p>
<ul>
<li>title : state변수 이름,</li>
<li>setTitle :  title변수의 값을 갱신 </li>
<li>useState(&quot;title&quot;) : 초기 값</li>
</ul>
<pre><code>const [title,setTitle] = useState(&quot;title&quot;)
</code></pre><p>아래 코드와 같이 useState를 사용하여 코드를 작성하면 title가 변경 될때 마다 컴포넌트가 재평가 되며 title이 변경된 값이 표시 된다.</p>
<pre><code>function App(){
    const [title,setTitle] = useState(&#39;title&#39;)
    const clickHandler = () =&gt; {
        setTitle(&#39;update&#39;)
    }
    return (
        &lt;div&gt;{title}&lt;/div&gt;
        &lt;button onClic={clickHandler}&gt;button&lt;/button&gt;
    )
}</code></pre><p>추가로 React는 해당 변수(여기서는 title)를 리렌더링할 때 기억하고, 가장 최근에 갱신된 값을 제공한다.</p>
<h3 id="여러개의-state-다루기">여러개의 state 다루기</h3>
<h4 id="방법-1-usestate-여러개-사용">방법 1. useState 여러개 사용</h4>
<pre><code>function App(){
    const [title,setTitle] = useState(&#39;&#39;)
    const [amount,setAmount] = useState(&#39;&#39;)
}</code></pre><h4 id="방법-2-usestate-초기값을-객체로-저장">방법 2. useState 초기값을 객체로 저장</h4>
<p>이렇게 state를 저장하면 한번에 여러개의 state를 저장할 수 있지만.. 주의점으로는 state를 변경할때 나머지 state들도 전개연산자를 통해 복사해 줘야한다.</p>
<pre><code>function App(){
    const [userInput,setUserInput] = useState({
        title : &#39;&#39;,
        amount : &#39;&#39;
    })

    const changeHandler = (event) =&gt; {
        setUsetInput({...userInput, amount : event.target.value})
    }
}</code></pre><p>하지만 이렇게 업데이트 해주면 매번 상태를 업데이트 해줄때 마다 이전 상태에 의존하게 된다.</p>
<p>대부분의 경우에는 문제가 없겠지만 만약 동시에 많은 상태 업데이트가 생기는 조건이라면 문제가 발생한다. </p>
<p>왜냐하면 리액트의 상태 업데이트는 즉시 일어나지 않기 때문에 잘못된 상태 snapshot에 의존할 수 도 있다. </p>
<p>그래서 위의 코드와 같이 이전 상태에 의존한 상태 업데이트의 경우 아래와 같이 업데이트 해주는게 좋다.</p>
<p>아래와 같이 업데이트 해주게 되면 리액트는 항상 최신 상태 snapshot을 제공해주기 때문에 문제가 발생하지 않는다.</p>
<pre><code>const [userInput,setUserInput] = useState({
        title : &#39;&#39;,
        amount : &#39;&#39;
    })

    const changeHandler = (event) =&gt; {
        setUsetInput((prevState)=&gt;{
            ...prevState , amount : event.target.value
        })</code></pre><h3 id="자식-대-부모-컴포넌트-통신-상향식">자식 대 부모 컴포넌트 통신 (상향식)</h3>
<p>아래 사진과 같이 Expenses 컴포넌트와 NewExpense 컴포넌트는 다이렉트로 데이터를 주고 받을 수 없다. 
이때 데이터를 주고 받기 위해서는 공통된 부모 컴포넌트로 부터 데이터를 받을 수 있는데 이때! NewExpense 컴포넌트에서 어떻게 App 컴포넌트로 데이터를 보낼수 있을까? </p>
<img src="https://media.vlpt.us/images/lsh__97/post/f9b18d73-ee72-4e72-ade3-67bf8c53e294/image.png">

<p>그건 부모 컴포넌트에서 props로 자식 컴포넌트에게 데이터를 보낸 방식과 비슷하다.</p>
<p>아래 코드와 같이 부모 컴포넌트 App 에서 props로 함수를 넘겨주면 된다.</p>
<pre><code>function App (){
    const addExpenseHandler = (expenseData) =&gt; {
        console.log(expenseData)
    }
    return(
        &lt;NewExpense onAddExpense={addExpenseHandler}/&gt;
    )
}</code></pre><p>그럼 자식 컴포넌트 NewExpense 에서 props로 받은 onAddExpens함수에 인자로 데이터를 넣어주면 자식에서 부모 컴포넌트로 데이터를 받을 수 있다.</p>
<pre><code>function NewExpense({onAddExpense}){
    const [enteredTitle, setEnteredTitle] = useState(&#39;&#39;)

    const titleChangeHandler = (event) =&gt; {
        setEnteredTitle(event.target.value)
    }

    const saveExpenseData = () =&gt; {
        onAddExpense(enteredTitle)
    }
    return(
        &lt;form onSubmit={saveExpenseData}&gt;
            &lt;input type=&quot;text&quot; value={enteredTitle} onChange={titleChangeHandler} /&gt;
            &lt;button type=&quot;submit&quot;&gt;submit&lt;/button&gt;
        &lt;/from&gt;
    )
}</code></pre><p>출처 <a href="https://ko.reactjs.org/docs/hooks-state.html">useState</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React (1)]]></title>
            <link>https://velog.io/@lsh__97/React-1</link>
            <guid>https://velog.io/@lsh__97/React-1</guid>
            <pubDate>Thu, 31 Mar 2022 11:59:24 GMT</pubDate>
            <description><![CDATA[<h1 id="react">React</h1>
<p>React란 사용자 인터페이스를 만드는 JavaScript 라이브러리이다.</p>
<h2 id="react-build">React build</h2>
<pre><code>npx create-react-app appName</code></pre><h2 id="react-특징">React 특징</h2>
<h3 id="접근-방식">접근 방식</h3>
<p>React는 선언적 접근 방식을 따른다. </p>
<h4 id="선언적-접근-방식-vs-명령형-접근-방식">선언적 접근 방식 vs 명령형 접근 방식</h4>
<pre><code>// 명령적
let imperative = &#39;How&#39;
// 선언적
let declarative = &#39;What&#39;</code></pre><p>👉 실생활에서의 예: 식당에 가서 테이블에 앉을 경우 </p>
<ul>
<li>명령형 접근 : 테이블이 비어있는것을 확인하고 직원에게 다가가서 저기 비어있는 테이블에 2명 앉을게요! </li>
<li>선언적 접근 : 직원에게 2명이요!  </li>
</ul>
<p>이처럼 명령적 접근 방식은 어떻게 테이블에 앉는지가 중점이고 선언적 접근 방식은 2인용 테이블에 중점을 두고 있다. </p>
<h4 id="명령형-접근-방식">명령형 접근 방식</h4>
<pre><code>let arr = [1,2,3,4,5]
function doubble(arr){
    let res = [] 
    for(let i=0; i&lt;arr.length; i++){
        res.push(arr[i] * 2)
    }
    return res
}

function add(arr){
    let res = 0 
    for(let i=0; i&lt;arr.length; i++){
        res += arr[i]
    }
    return res 
}

const btn = document.getElementById(&#39;btn&#39;)
btn.addEventListener(&#39;click&#39;,()=&gt;{
    btn.classList.toggle(&#39;highlight&#39;)
    btn.innerText === &#39;Add Highlight&#39;
        ? btn.innerText = &#39;Remove Highlight&#39;
        : btn.innerText = &#39;Add Highlight&#39;
})
</code></pre><ul>
<li>What 보다 <strong>How를</strong> 중점으로 둔다 (원하는 기능을 구현하는 방법에 대한 단계를 명시적으로 배치)</li>
</ul>
<h4 id="선언적-접근-방식">선언적 접근 방식</h4>
<pre><code>let arr = [1,2,3,4,5]
function doubble(arr){
    return arr.map((item)=&gt;item*2)
}

function add(arr){
    return arr.reduce((total,number)=&gt;number + total, 0)
}

&lt;Btn /&gt; </code></pre><ul>
<li>How 보다 *<em>What에 *</em>중점을 둔다 (우리는 map,reduce안에서 무슨 일이 일어 나는지 모른다)</li>
<li>가독성이 높다 (map,reduce가 무슨 역할을 하는지 알면)</li>
</ul>
<p>선언적 코드의 또 다른 장점은
프로그램이 컨텍스트에 독립적일 수 있다는 것이다.
즉, 코드는 단계보다 궁극적인 목표에 관심이 있기 때문에 동일 코드가 다른 프로그램에서도 제대로 작동할 수 있게 된다.
명령형 코드는 현재 상태의 컨텍스트에 의존하는 경우가 많기 때문에 프로그램이 컨텍스트에 독립적이기 어렵다.</p>
<h3 id="컴포넌트-기반">컴포넌트 기반</h3>
<ul>
<li>리액트는 모두 컴포넌트로 구성되어 있고 이때, 컴포넌트는 하나의 기능만 하게 잘게 쪼개서 관리하는게 좋다.</li>
<li>컴포넌트 단위로 개발하기 때문에 재사용성이 좋다.</li>
<li>컴포넌트는 처음 시작단어와 새로운 단어 사이에는 대문자를 사용한다</li>
</ul>
<h2 id="jsx">JSX</h2>
<p>JSX는 JavaScript를 확장한 문법이다.
React는 JSX 사용이 필수가 아니지만, 대부분의 사람들은 JSX를 사용한다.</p>
<pre><code>function App(){
    return (
        &lt;div&gt;Hello&lt;/div&gt;
        )
}</code></pre><h3 id="jsx-규칙">JSX 규칙</h3>
<ol>
<li>컴포넌트에 여러 요소가 있다면 반드시 래핑 태그가 필요하다.
&lt;React.Fragment&gt; 또는 &lt;&gt; 사용해줘야 한다.<pre><code> // true
 function App(){
     return(
         &lt;&gt;
             &lt;div&gt;Hi&lt;/div&gt;
             &lt;div&gt;HIHIHI&lt;/div&gt;
         &lt;/&gt;
     )
 }
 // false
 function App(){
     return(
         &lt;div&gt;Hi&lt;/div&gt;
         &lt;div&gt;HIHIHI&lt;/div&gt;
     )
 }</code></pre></li>
<li>자바스크립트 표현
{}를 사용하여 JSX 내부에서 사용가능 이때 로직은 JSX안에서 사용하지 않고 변수나 상수로 입력하는게 깔끔하고 좋다.</li>
</ol>
<pre><code>function App(){
    const month = new Date().getMonth()
    return (&lt;div&gt;{month}&lt;/div&gt;)
}</code></pre><h3 id="jsx없이-react-사용하기">JSX없이 React 사용하기</h3>
<p>만약 JSX없이 React를 사용한다면 엄청..불편하다.
React.createElement(component, props, ...children)는 항상 하나의 root 엘리먼트를 만든 다음에 사용한다.(JSX에서 래핑 태그가 필요한 이유)</p>
<pre><code>//false
function App(){
    return (
    React.createElement(&#39;div&#39;,{},&#39;HI&#39;)
    React.createElement(&#39;h2&#39;, {}, &quot;HELLO&quot;)
    )
}

//true
function App(){
    return(
      React.createElement(
        &quot;div&quot;,
        {},
        React.createElement(&quot;div&quot;, {}, &quot;HI&quot;),
        React.createElement(&quot;h2&quot;, {}, &quot;Heooooo&quot;)
      )
    )
}

</code></pre><h2 id="props">props</h2>
<p>props를 통해 컴포넌트간 데이터 이동이 가능하다</p>
<pre><code>const expenses = [
    {
      id: &quot;e1&quot;,
      title: &quot;Toilet Paper&quot;,
      amount: 94.12,
      date: new Date(2020, 7, 14),
    }
 ]

// 컴포넌트 A
function App(){
    return (
        &lt;Expenses item={expenses}/&gt;
    )
}

// 컴포넌트 B
function Expenses({title,amount,date})
    return(
        &lt;div&gt;{title}&lt;div&gt;
    )
</code></pre><h3 id="propschildren">props.children</h3>
<p>props.children는 래핑한 태그의 콘텐츠를 의미한다
아래의 예제에서는 Card로 래핑한 태그 안의 콘텐츠 모두를 의미한다.</p>
<pre><code>function Card(props){
    const classes = &#39;card &#39; + props.className
    function Card(props) {
        return &lt;div className={classes}&gt;{props.children}&lt;/div&gt;;
    }

 &lt;Card className=&quot;name&quot;&gt;
     &lt;h2&gt;Name&lt;h2&gt;
 &lt;/Card&gt;
}</code></pre><p>출처 <a href="https://www.youtube.com/watch?v=E7Fbf7R3x6I">Imperative vs Declarative Programming</a>
출처 <a href="https://reactjs.org/docs/introducing-jsx.html">Introducing JSX</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[querySrv ETIMEOUT _mongodb 에러]]></title>
            <link>https://velog.io/@lsh__97/querySrv-ETIMEOUT-mongodb-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@lsh__97/querySrv-ETIMEOUT-mongodb-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Sat, 26 Mar 2022 21:38:20 GMT</pubDate>
            <description><![CDATA[<p>mongoose를 연결하고 서버를 실행 했는데 아래와 같은 에러가 발생하였습니다...</p>
<h2 id="에러-코드">에러 코드</h2>
<img src="https://images.velog.io/images/lsh__97/post/a64af7a9-64ee-4a86-a0cb-764a565f83c3/image.png">

<h2 id="해결-방법">해결 방법</h2>
<p>라우터 설정을 구글 DNS로 변경해주면 정상적으로 서버가 실행 됩니다. </p>
<p><strong>제어판 -&gt; 네트워크 및 인터넷 -&gt; 네트워크 및 공유 센터 -&gt; 어댑터 설정 변경</strong></p>
<h3 id="step1-제어판에서-네트워크-및-인터넷-클릭">step1. 제어판에서 네트워크 및 인터넷 클릭</h3>
<img src="https://images.velog.io/images/lsh__97/post/7ce0f92f-a433-4892-b4fe-3444b53d754f/image.png" width="600">

<h3 id="step2-네트워크-및-공유-센터">step2. 네트워크 및 공유 센터</h3>
<img src="https://images.velog.io/images/lsh__97/post/04bb8f37-82a2-4a7a-a84f-1ba2c02ea0b6/image.png" width="600">

<h3 id="step3-어댑터-설정-변경">step3. 어댑터 설정 변경</h3>
<img src="https://images.velog.io/images/lsh__97/post/b79fc3cd-e8fa-4e48-8639-876c4174640e/image.png" width="600">

<h3 id="step4-이더넷-속성-변경">step4. 이더넷 속성 변경</h3>
<img src="https://images.velog.io/images/lsh__97/post/78107125-95a0-44cc-9f5d-a7beac147b4a/image.png"   width="600" >

<h3 id="step5-인터넷-프로토콜-버전4tcpipv4-속성---기본-설정-dns-주소를-8888로-변경">step5. 인터넷 프로토콜 버전4(TCP/IPv4) 속성 -&gt; 기본 설정 DNS 주소를 8.8.8.8로 변경</h3>
<img src="https://images.velog.io/images/lsh__97/post/3497f7b8-014a-424a-93f6-adcecad483ed/image.png" width="600">

<h2 id="구글-dns-변경후-서버-재실행-결과-성공">구글 DNS 변경후 서버 재실행 결과 (성공!!)</h2>
<img src="https://images.velog.io/images/lsh__97/post/aca7d5bd-3949-4602-bb28-af9f95b2d69c/image.png" width="500">

<p>출처 <a href="https://stackoverflow.com/questions/62035107/error-querysrv-etimeout-mongodb-tcp-when-i-connect-with-my-home-router-netwo">Error: querySrv ETIMEOUT _mongodb._tcp. when i connect with my home router Network</a>
출처 <a href="https://www.techworm.net/2016/08/change-default-dns-google-dns-fast-internet-speeds.html">How to Change Your Default DNS to Google DNS for Fast Internet Speeds</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[npm init -y 의미!!]]></title>
            <link>https://velog.io/@lsh__97/npm-init-y-%EC%9D%98%EB%AF%B8</link>
            <guid>https://velog.io/@lsh__97/npm-init-y-%EC%9D%98%EB%AF%B8</guid>
            <pubDate>Fri, 25 Mar 2022 18:51:52 GMT</pubDate>
            <description><![CDATA[<p>프로젝트 초기 세팅 중 문득 y 옵션이 무슨 의미를 가지는지 궁금하여 찾아봤습니다.
우선 npm init은 package.json 파일을 생성하는 데 사용되는데, 이때 y 옵션 없이 사용하게 되면 아래의 이미지에 보이는 양식들에 대하여 일일이 값을 입력해 줘야 하지만, -y를 사용할 경우 이러한 일련의 과정을 거치지 않고 아래의 이미지처럼 empty값을 가진 package.json 파일이 생성됩니다.!!</p>
<img src="https://images.velog.io/images/lsh__97/post/a8114061-fe26-400f-bf01-865f0b72a705/image.png">

<p>출처 <a href="https://stackoverflow.com/questions/62725481/what-is-the-meaning-of-npm-init-y#:~:text=of%20asking%20questions.-,npm%20init%20%2Dy,The%20%2Dy%20stands%20for%20yes%20.">What is the meaning of npm init -y</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Expected indentation of 1 tab but found 4 spaces.eslint , Parsing error: Unexpected token]]></title>
            <link>https://velog.io/@lsh__97/Expected-indentation-of-1-tab-but-found-4-spaces.eslint-Parsing-error-Unexpected-token</link>
            <guid>https://velog.io/@lsh__97/Expected-indentation-of-1-tab-but-found-4-spaces.eslint-Parsing-error-Unexpected-token</guid>
            <pubDate>Mon, 21 Mar 2022 16:31:32 GMT</pubDate>
            <description><![CDATA[<h1 id="eslint-세팅-오류">ESLint 세팅 오류</h1>
<p>ESLint를 처음 세팅하여 사용중 오류가 발생한것에 대해 정리 하였습니다.</p>
<h2 id="에러-1-expected-indentation-of-2-spaces-but-found-4-eslintindent">에러 1. expected indentation of 2 spaces but found 4. eslint(indent)</h2>
<h3 id="방법-1-eslint-congig-prettier-설치">방법 1. eslint-congig-prettier 설치</h3>
<p>eslint와 prettier의 충돌로 인해서 생긴 오류라고 합니다!
그래서 .eslintrc.js 파일의 extends 값에 &quot;prettier&quot;을 추가해주면 해결됩니다.</p>
<blockquote>
<pre><code>npm install --save-dev eslint-config-prettier</code></pre></blockquote>
<pre><code>
&gt; ```
&quot;extends&quot; : [&quot;some-other-config-you-ues&quot;,&quot;prettier&quot;] </code></pre><h2 id="에러-2-arsing-error-unexpected-token">에러 2. arsing error: Unexpected token</h2>
<h3 id="방법-1-babel-parser-추가">방법 1. &quot;babel-parser&quot; 추가</h3>
<blockquote>
<pre><code>&quot;parser&quot;: &quot;babel-parser&quot;</code></pre></blockquote>
<p>```</p>
<p>출처 : [링크텍스트](<a href="https://github.com/prettier/eslint-config-prettier">https://github.com/prettier/eslint-config-prettier</a>  출처: <a href="https://interacting.tistory.com/143">https://interacting.tistory.com/143</a> [interacting])</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[수학 기본 이론 ]]></title>
            <link>https://velog.io/@lsh__97/%EC%88%98%ED%95%99-%EA%B8%B0%EB%B3%B8-%EC%9D%B4%EB%A1%A0</link>
            <guid>https://velog.io/@lsh__97/%EC%88%98%ED%95%99-%EA%B8%B0%EB%B3%B8-%EC%9D%B4%EB%A1%A0</guid>
            <pubDate>Sat, 12 Feb 2022 13:05:58 GMT</pubDate>
            <description><![CDATA[<h1 id="수학-기본-이론">수학 기본 이론</h1>
<h2 id="경우의-수">경우의 수</h2>
<p>어떤 사건 혹은 일이 일어날 수 있는 경우이 수를 가짓수로 표현</p>
<h2 id="완전탐색으로-경우의-수를-푸는-알고리즘">완전탐색으로 경우의 수를 푸는 알고리즘</h2>
<ol>
<li>순열 : 서로 다른 n개의 원소중에서 r개를 <strong>중복없이</strong> 골라 <strong>순서에 상관 있게</strong> 나열하는 수 (nPr = n!/(n-r)!)</li>
<li>조합 : 서로 다른 n개의 원소중에서 r개를 <strong>중복없이</strong> 골라 <strong>순서에 상관 없이</strong> 나열하는 수 (nCr = n!/(n-r)!r!)</li>
</ol>
<h3 id="순열">순열</h3>
<h4 id="방법-1-for문-사용">방법 1. for문 사용</h4>
<p>단점 : r의 수 와 동일한 for문을 가져야되기 때문에 r의 수가 커질수록 구현하기 힘들다.</p>
<blockquote>
<pre><code>let arr = [&#39;a&#39;,&#39;b&#39;,&#39;c&#39;];
// 첫번째 [i,0,0]
for(let i=0; i&lt;arr.length; i++){
    // [i,j,0]
    for(let j=0; j&lt;arr.length; j++){
        if(i===j) continue;
        // [i,j,k]
        for(let k=0; k&lt;arr.length; k++){
            if(i===k) continue;
            if(j===k) continue;
            console.log(arr[i],arr[j],arr[k])
        }
    }
}</code></pre></blockquote>
<h4 id="방법-2-재귀">방법 2. 재귀</h4>
<p>for문의 문제를 해결할 수 있다.</p>
<blockquote>
<pre><code>let input = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;];
function permutation(arr, s, r) {
  if (s === r) {
    count++;
    console.log(arr.join(&quot; &quot;));
    return;
  }
  for (let i = s; i &lt; arr.length; i++) {
    [arr[s], arr[i]] = [arr[i], arr[s]];
    permutation(arr, s + 1, r);
    [arr[s], arr[i]] = [arr[i], arr[s]];
  }
}
permutation(input, 0, 2);</code></pre></blockquote>
<h3 id="조합">조합</h3>
<h4 id="방법-1-for문-사용-1">방법 1. for문 사용</h4>
<p>순열과 마찬가지로 r의 수만큼 for문을 사용하기 때문에 패스</p>
<h4 id="방법-2-재귀-1">방법 2. 재귀</h4>
<blockquote>
<pre><code>function solution(n,r){
    let tmp = Array.from({length:r},()=&gt;0)
    let answer = []
    // l은 뽑은 개수를 나타냄 
    function DFS(l,s){
        if(l===r){
            answer.push(tmp.slice())
        }else{
            for(let i=s; i&lt;=n;i++){
                tmp[l]=i
                DFS(l+1,i+1)
            }
        }
    }
    DFS(0,1)
}
solution(4,2)</code></pre></blockquote>
<h2 id="점화식-재귀식">점화식 (재귀식)</h2>
<p>점화식이란 수열에서 이웃하는 두개의 항사이에 성립하는 관계를 나타낸 관계식</p>
<ol>
<li>등차 수열 : F(n) = F(n-1) + a (고정된 수)</li>
<li>등비 수열 : F(n) = F(n-1) * a</li>
<li>팩토리얼 : F(n) = F(n-1) * n</li>
<li>피보나치 수열 : F(n) = F(n-1) + F(n-2)</li>
</ol>
<h3 id="등차-수열">등차 수열</h3>
<h4 id="방법-1-for문-사용-2">방법 1. for문 사용</h4>
<blockquote>
<pre><code>// s : 시작값, a : 고정값
function test(s,a,n){
    let acc = 0
    for(let i=0;i&lt;n;i++){
        if(i===1){
            acc+=s
        }else{
            acc+=a
        }
    }
    return acc
}
test(3,2,5)</code></pre></blockquote>
<h4 id="방법-2-재귀-사용">방법 2. 재귀 사용</h4>
<blockquote>
<pre><code>function test(s,a,n){
    if(n===1) return s
    return test(s,a,n-1) + a
}
test(3,2,5)
// n=5 : 9 + 2
// n=4 : 7 + 2
// n=3 : 5 + 2
// n=2 : 3 + 2
// n=1 : 3</code></pre></blockquote>
<h3 id="등비-수열">등비 수열</h3>
<h4 id="방법-1-for문-사용-3">방법 1. for문 사용</h4>
<blockquote>
<pre><code>// s : 시작값, a : 고정값
function test(s,a,n){
    let acc = 0
    for(let i=0;i&lt;n;i++){
        if(i===1){
            acc*=s
        }else{
            acc*=a
        }
    }
    return acc
}
test(3,2,5)</code></pre></blockquote>
<h4 id="방법-2재귀-사용">방법 2.재귀 사용</h4>
<blockquote>
<pre><code>function test(s,a,n){
    if(n===1) return s
    return test(s,a,n-1) * a
}
test(3,2,5)</code></pre></blockquote>
<h3 id="팩토리얼">팩토리얼</h3>
<h4 id="방법-1-재귀">방법 1. 재귀</h4>
<blockquote>
<pre><code>function test(n){
    if(n===1) return 1
    return test(n-1) * n
}
test(5)</code></pre></blockquote>
<h3 id="피보나치">피보나치</h3>
<p>전 항과 전전 항의 값이 현재 항의 값이다.
f(5) : f(4) + f(3)
f(4) : f(3) + f(2)</p>
<h4 id="방법-1-재귀-1">방법 1. 재귀</h4>
<blockquote>
<pre><code>function test(n){
    if(n===0 || n===1) return n 
    return test(n-1) + test(n-2)
}
test(5)</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체 복사]]></title>
            <link>https://velog.io/@lsh__97/%EA%B0%9D%EC%B2%B4-%EB%B3%B5%EC%82%AC</link>
            <guid>https://velog.io/@lsh__97/%EA%B0%9D%EC%B2%B4-%EB%B3%B5%EC%82%AC</guid>
            <pubDate>Fri, 11 Feb 2022 09:12:48 GMT</pubDate>
            <description><![CDATA[<h1 id="문제점">문제점</h1>
<p>다음과 같이 admin 변수에 user 객체를 복사했을때 admin값을 변경하면 admin값만 변경 될거 같지만 user의 값 또한 변경되어 출력된다, 이는 admin이 user의 주소값만 복사됬기 때문에 이러한 문제점이 발생하게 된다. </p>
<blockquote>
<pre><code>let user = {
    name : &#39;jjj&#39;,
    age : 23
}
</code></pre></blockquote>
<p>let admin = user;
admin.name = &quot;park&quot;</p>
<blockquote>
</blockquote>
<p>console.log(admin.name) // &quot;park&quot;
consoel.log(user.name) // &quot;park&quot;</p>
<blockquote>
</blockquote>
<p>user.age = 30;
console.log(admin.age , user.age) // 30 30 </p>
<blockquote>
<p>``</p>
</blockquote>
<h1 id="해결-방법">해결 방법</h1>
<h2 id="얕은-복사">얕은 복사</h2>
<h3 id="1-for문">1. for문</h3>
<p>for문을 통해 복사할 객체의 키와 값을 하나씩 복사</p>
<blockquote>
<pre><code>let admin = {}
for(let key in user){
    admin[key] = user[key]
}</code></pre></blockquote>
<h3 id="2-objectassign">2. Object.assign()</h3>
<blockquote>
<pre><code>let admin = Object.assign({}, user);</code></pre></blockquote>
<h3 id="3-es6-전개-연산자">3. es6 전개 연산자</h3>
<p>복사할 객체의 필드 값을 하나씩 나열해준다. (user.name , user.age)</p>
<blockquote>
<pre><code>let admin = {...user}</code></pre></blockquote>
<h2 id="깊은-복사">깊은 복사</h2>
<p>얕은 복사의 문제점을 해결할 수 있다. (객체 내 또 다른 객체가 있다면 복사되지 않음)
만약 다음과 같이  user의 객체가 있을때 얕은 복사를 한 경우 sizes의 객체는 주소값만 복사되어 값을 변경시 user의 sizes값 또한 변경된다. </p>
<blockquote>
<pre><code>let user = {
    name : &quot;jjj&quot;,
    age : 23,
    sizes : {
        height : 170,
        weight : 67,
    }
}</code></pre></blockquote>
<h3 id="1-json">1. JSON</h3>
<p>JSON 객체를 이용한 깊은 복사, stringify는 객체를 문자열로 변환하는데 이때 원복 객체(user)와의 참조가 끊긴다. </p>
<blockquote>
<pre><code>//user객체를 문자열로 바꿔준뒤 다시 객체로 변환해주어 새로운 주소값을 받는다.
let admin_json = JSON.parse(JSON.stringify(user))</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[NULL 처리하기]]></title>
            <link>https://velog.io/@lsh__97/NULL-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@lsh__97/NULL-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 07 Feb 2022 08:15:57 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p>주어진 테이블 NAME이 NULL 값을 가지는 경우 &quot;No name&quot;으로 변경해서 조회하는 문제이다.</p>
<h2 id="풀이">풀이</h2>
<p>IFNULL 을 사용하여 간단하게 풀었다.
IFNULL은 만약 값이 NULL일 경우 대체된 값(&quot;No name&quot;)을 출력하고 NULL이 아닐경우 기존 값을 출력 해준다.</p>
<blockquote>
<pre><code>SELECT ANIMAL_TYPE , IFNULL(NAME,&#39;No name&#39;) AS NAME , SEX_UPON_INTAKE
FROM ANIMAL_INS</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS 값 과 단위]]></title>
            <link>https://velog.io/@lsh__97/CSS-%EA%B0%92-%EA%B3%BC-%EB%8B%A8%EC%9C%84</link>
            <guid>https://velog.io/@lsh__97/CSS-%EA%B0%92-%EA%B3%BC-%EB%8B%A8%EC%9C%84</guid>
            <pubDate>Sat, 05 Feb 2022 11:51:10 GMT</pubDate>
            <description><![CDATA[<h1 id="css-단위">CSS 단위</h1>
<h2 id="절대길이-단위">절대길이 단위</h2>
<ul>
<li>px : 고정 값 (브라우저를 확대하거나 축소해도 고정된 값이 적용되기 때문에 접근성 문제를 유발할 수 있다. 그렇기 때문에 font-size의 경우 상대길이 단위인 em,rem을 사용하는게 좋다)</li>
</ul>
<h2 id="상대길이-단위">상대길이 단위</h2>
<h3 id="글꼴">글꼴</h3>
<ul>
<li><p>em : 1em === 부모의 font-size 만약 부모에 font-size가 없다면 브라우저의 기본 font-size를 사용한다(16).</p>
</li>
<li><p>rem : 1rem === root의 font-size(브라우저 기본 사이즈인 16)를 사용해 좀 더 직관적이다.</p>
<h3 id="뷰포트">뷰포트</h3>
<img src="https://user-images.githubusercontent.com/59095793/152639065-8a632246-2c6b-4998-8baa-11294fdcd011.png" width="400">
빨간색 영영이 뷰포트 영역이다.
<p>디바이스의 크기에 따라 반응형으로 만들때 유용하다.</p>
</li>
<li><p>vw : 뷰포트 가로, 50vw는 전체 뷰포트영역에서 50프로만 사용한다는 뜻이며 디바이스 크키
가 줄어도 항상 유지된다.</p>
</li>
<li><p>vh : 뷰포트 세로 </p>
</li>
<li><p>vmin, vmax : 뷰포트에서 가로 세로중 작은쪽이 vmin 큰쪽이 vmax를 가지며, 가로모드나 세로모드에 대응해야 하는 경우 사용한다.</p>
</li>
</ul>
<h2 id="함수-표기법">함수 표기법</h2>
<ul>
<li>calc() : 여러개의 단위를 섞어서 사용하고 싶을때 사용
ex) width : calc(100% - 50px); </li>
<li>min() : ,로 구분하여 값을 입력하며 width : min(100%,200px)이 있다면 브라우저가 둘중 작은 값을 사용한다.</li>
<li>max() : ,로 구분하여 값을 입력하며 width : max(100%,200px)이 있다면 브라우저가 둘중 큰 값을 사용한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[시맨틱 웹/태그]]></title>
            <link>https://velog.io/@lsh__97/%EC%8B%9C%EB%A7%A8%ED%8B%B1-%EC%9B%B9%ED%83%9C%EA%B7%B8</link>
            <guid>https://velog.io/@lsh__97/%EC%8B%9C%EB%A7%A8%ED%8B%B1-%EC%9B%B9%ED%83%9C%EA%B7%B8</guid>
            <pubDate>Sat, 05 Feb 2022 05:41:56 GMT</pubDate>
            <description><![CDATA[<h1 id="시맨틱-웹">시맨틱 웹</h1>
<p>&#39;semantic&#39;이란 의미론적인 뜻을 가지며 마크업은 HTML문서 태그로 문서를 작성하는 것을 말한다.</p>
<h2 id="시맨틱-마크업-사용-장점">시맨틱 마크업 사용 장점</h2>
<ul>
<li><strong>검색 엔진</strong>은 시맨틱 마크업을 분석하여 페이지의 검색 랭킹에 영향을 줄 수 있는 중요한 키워드로 간주하여 SEO(Search Engine Optimize)에 영향을준다.</li>
<li>시각 장애가 있는 사용자가 <strong>스크린리더</strong>로 페이지를 탐색할 때 시맨틱 마크업을 푯말로 사용할 수 있다.</li>
<li>의미가 없는 div태그들을 탐색하는 것보다, 의미있는 코드 블록을 작성하는게 나중에 보기도 편하고 찾기도 쉽다.</li>
<li>개발자에게 태그안에 채워질데이터 유형을 제안할 수 있다.</li>
</ul>
<h2 id="시맨틱-태그-종류-및-특징">시맨틱 태그 종류 및 특징</h2>
<ul>
<li>header : 소개 및 탐색에 도움을 주는 콘텐츠를 나타낸다. 
예시로는 제목(페이지 제목, 글 제목), 로고, 검색 폼, 작성자 이름 등의 요소를 포함한다.
header태그 안에 header태그 또는 footer 태그를 넣을 수 없다.</li>
</ul>
<blockquote>
<pre><code></code></pre></blockquote>
<header>
  <h1>Main Page Title </h1>
</header>
>
<article>
    <header>
      <h2>Article Title</h2>
      </hedaer>
</article>
>```

<ul>
<li><p>footer : 일반적으로 작성자, 저작권 정보, 관련 문서들의 내용을 담는다. header와 마찬가지로 footer 안에 footer 또는 header를 넣을 수 없다.</p>
</li>
<li><p>nav :  현재 페이지 내, 또는 다른 페이지로의 링크를 보여주는 구획을 나타내며, 현재 페이지를 기준으로 상위 요소 또는 현재 페이지의 개요를 나타낼때 사용한다.(footer는 전체 페이지를 나타내는 요소)
예시로는 메뉴, 목차 등이 있다.</p>
</li>
<li><p>aside : 본문과 간접적 정보이거나 부가적 정보일때 사용 (없어도 상관 없는 것,관련 컨텐츠나 광고). 예시로는 사이드바.</p>
</li>
<li><p>main : body태그의 하위 자식으로 하나만 사용할 수 있으며 주요 콘텐츠를 나타낼때 사용된다.</p>
</li>
<li><p>article : 사이트 안에서 독립적으로 구분해 배포하거나 재사용할 수 있는 구획을 나타낸다(단독 콘텐츠), 콘텐츠를 따로 구분해야 할 필요가 있을때 사용.</p>
</li>
<li><p><em>article안에 주로 제목 태그(h1~h6)요소를 사용하여 제목을 표시해준다.*</em>
예시로는 게시판과 블로그 글, 잡지나 뉴스 기사, 댓글 등이 있다.</p>
</li>
<li><p>section : article이 아니면 section 사용 </p>
</li>
<li><p><em>section안에 주로 제목 태그(h1~h6)요소를 사용하여 제목을 표시해준다.*</em></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[그래프]]></title>
            <link>https://velog.io/@lsh__97/%EA%B7%B8%EB%9E%98%ED%94%84</link>
            <guid>https://velog.io/@lsh__97/%EA%B7%B8%EB%9E%98%ED%94%84</guid>
            <pubDate>Fri, 04 Feb 2022 15:50:15 GMT</pubDate>
            <description><![CDATA[<h1 id="그래프">그래프</h1>
<p>노드나 노드들의 연결을 모은 것</p>
<h2 id="사용-예시">사용 예시</h2>
<ol>
<li>SNS</li>
<li>위치 찾기</li>
<li>구글 지도</li>
<li>라우팅</li>
<li>넷플릭스 영화추천 </li>
</ol>
<h2 id="용어">용어</h2>
<ul>
<li>Vertex (정점) : 노드</li>
<li>Edge(간선) : 노드 사이의 연결</li>
<li>Weighted(가중)/Unweighted(비가중) : 간선에 가중치를 부여한것(최단경로를 계산할때 사용)과 안한것</li>
<li>Directed(방향)/Undirected(무방향) : 간선에 방향이 표시된것(양방향,단방향)과 방향이 없는 무방향 </li>
</ul>
<h2 id="그래프-정렬">그래프 정렬</h2>
<h3 id="인접-행렬">인접 행렬</h3>
<p>정점 사이에 간선이 있는지 체크하여 행렬을 만든다. 보통 있으면 1, 없으면 0을 사용한다.
<img src="https://user-images.githubusercontent.com/59095793/152521393-50dee992-bae6-4fdc-bf33-3d54ad319f82.png"></p>
<h3 id="인접-리스트">인접 리스트</h3>
<p>각 정점들의 간선을 리스트로 저장한다, 이때 정점이 숫자가 아니거나 숫자 사이에 큰 차이가 있을 경우 맵을 이용하여 다음과 같이 저장 할 수 있다.
<img src="https://user-images.githubusercontent.com/59095793/152533891-12fbd72d-3f3b-4e7b-9f93-86491fabec61.png"></p>
<h3 id="비교">비교</h3>
<p>인접리스트가 인접 행렬에 비해 차지 하는 공간이 적다.</p>
<ul>
<li>희소 그래프(정점의 개수에 비해 간선의 개수가 매우적은 그래프) : 인접 리스트 </li>
<li>완전 그래프(모든 정점간에 간선이 존재하는 경우) : 인접 행렬 </li>
<li>모든 간선을 순환하고 싶은 경우 : 인접 리스트</li>
<li>특정 간선이 있는지 확인하고 싶은 경우 : 인접 행렬  <img src="https://user-images.githubusercontent.com/59095793/152559101-c68ed0b1-0a8c-491e-8a3c-da33a12710e3.png">

</li>
</ul>
<h2 id="인접-리스트를-사용한-그래프-구현-무방향-그래프">인접 리스트를 사용한 그래프 구현 (무방향 그래프)</h2>
<blockquote>
<pre><code>class Graph{
  constructor(){
    this.adjaceneyList = {}
  }
}</code></pre></blockquote>
<pre><code>
### 정점 추가 
1. 정점의 이름을 인접 리스트의 키로 입력하고, 값은 빈 배열로 저장한다.

&gt; ```
addVertex(vertex){
  if(!this.adjaceneyList[vertex]) this.adjaceneyList[vertex] = []
}</code></pre><h3 id="간선-추가">간선 추가</h3>
<ol>
<li>정점1, 정점2를 인자로 받는다.</li>
<li>리스트에서 정점1에 정점2를 삽입 해주고 정점2에 정점1을 삽입해준다.</li>
</ol>
<blockquote>
<pre><code>addEdge(vertex1,vertex2){
  if(this.adjaceneyList[vertex1]) this.adjaceneyList[vertex1].push(vertex2)
  if(this.adjaceneyList[vertex2]) this.adjaceneyList[vertex2].push(vertex1)
}</code></pre></blockquote>
<pre><code>
### 간선 제거 
1. 정점1, 정점2를 인자로 받는다.
2. 리스트에서 정점1에 정점2를 제거 해주고 정점2에 정점1을 제거해준다.

&gt; ```
removeEdge(vertex1,vertex2){
  if(this.adjaceneyList[vertex1]){
      this.adjaceneyList[vertex1] = this.adjaceneyList[vertex1].filter(v=&gt; v !== vertex2)
  } 
  if(this.adjaceneyList[vertex2]){
      this.adjaceneyList[vertex2] = this.adjaceneyList[vertex2].filter(v=&gt; v !== vertex1)
  }
}</code></pre><h3 id="정점-제거">정점 제거</h3>
<ol>
<li>제거하는 정점을 인자로 받는다</li>
<li>제거하는 정점과 연결된 모든 정점에 대해 루프를 돌며 연결된 간선을 제거 한다.</li>
<li>모두 제거한뒤 리스트에서 정점을 제거한다.</li>
</ol>
<blockquote>
<pre><code>removeVertex(vertex){
  if(this.adjaceneyList[vertex]){
      this.adjaceneyList[vertex].forEach(v=&gt;{
          this.removeEdge(vertex,v)
      })
      delete this.adjaceneyList[vertex]
  }
}</code></pre></blockquote>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[중복 제거하기]]></title>
            <link>https://velog.io/@lsh__97/%EC%A4%91%EB%B3%B5-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@lsh__97/%EC%A4%91%EB%B3%B5-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 04 Feb 2022 02:43:17 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>주어진 테이블에서 동물의 이름이 NULL값이 아니고 중복되지 않은 동물 이름의 수를 조회하는 문제이다.</p>
<h2 id="풀이">풀이</h2>
<p>DISTINCT : 중복 제거
COUNT : 집계 함수로 행의 개수를 출력해준다.</p>
<blockquote>
<pre><code>SELECT COUNT(DISTINCT NAME) as count
FROM ANIMAL_INS
WHERE NAME IS NOT NULL </code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[이진 힙]]></title>
            <link>https://velog.io/@lsh__97/%EC%9D%B4%EC%A7%84-%ED%9E%99</link>
            <guid>https://velog.io/@lsh__97/%EC%9D%B4%EC%A7%84-%ED%9E%99</guid>
            <pubDate>Thu, 03 Feb 2022 17:19:01 GMT</pubDate>
            <description><![CDATA[<h1 id="이진-힙-binary-heap">이진 힙 (Binary Heap)</h1>
<ul>
<li>트리 구조중 하나로 이진 탐색 트리와 매우 비슷하나 다른 규칙을 가진다.</li>
<li>최대 이진 힙에서는 부모 노드가 항상 자식 노드보다 큰 값을 가진다. (모든 자식 노드가 부모보다 작다)</li>
<li>최소 이진 힙에서는 부모 노드가 항상 자식 노드보다 작은 값을 가진다.</li>
<li>각각의 부모 노드들은 최대 두개의 자식을 가진다.</li>
</ul>
<h2 id="시간-복잡도">시간 복잡도</h2>
<ul>
<li>Insertion : O(log N) </li>
<li>Removal : O(log N)</li>
<li>Search : O(N) (순서가 없기 때문에 전체 다 탐색)</li>
</ul>
<h2 id="현재-위치에서-자식-노드-찾기">현재 위치에서 자식 노드 찾기</h2>
<ul>
<li>left : 2n + 1</li>
<li>right : 2n +2</li>
</ul>
<h2 id="현재-위치에서-부모-노드-찾기">현재 위치에서 부모 노드 찾기</h2>
<ul>
<li>Math.floor((n-1)/2)</li>
</ul>
<h2 id="최대-이진-힙">최대 이진 힙</h2>
<blockquote>
<pre><code>class MaxBinaryHeap{
    constructor(){
        this.values = []
    }
}</code></pre></blockquote>
<pre><code>
## Insert method 구현
1. 가장 끝에 값을 추가한뒤 부모의 위치를 찾아 값을 비교한다 만약에 부모가 자신보다 작다면 bubbleUp을 한다
2. 부모가 자신보다 클때까지 반복한다.

### Bubble up 
- 추가한 값과 부모의 값을 비교한뒤 작은경우 스왑한다. (부모의 값이 추가한 값보다 큰 경우까지)

&gt; ```
bubbleUp(){
        let currentIndex = this.values.length-1
        let parentIndex = Math.floor((currentIndex-1)/2)
        while(true){
            parentIndex = Math.floor((currentIndex-1)/2)
            if(this.values[parentIndex] &lt; this.values[currentIndex]){
                [this.values[parentIndex],this.values[currentIndex]] = [this.values[currentIndex],this.values[parentIndex]]
                currentIndex = parentIndex
            }else break
        }
    }
insert(val){
    this.values.push(val)
    this.bubbleUp()
    return this
}</code></pre><h2 id="extractmax-method-구현">ExtractMax method 구현</h2>
<p>-최대 이진 힙일경우 최대값(루트) 최소 이진 힙일경우 최소값(루트)를 제거</p>
<h3 id="sink-down">Sink down</h3>
<ol>
<li>루트를 제거하고 가장 끝에 있는값을 루트로 설정한다</li>
<li>자식 노드들중 가장 큰값과 비교하여 자신보다 큰경우 스왑한다 </li>
<li>반복  </li>
</ol>
<blockquote>
<pre><code>sinkDown(){
        let idx = 0
        let len = this.values.length
        let element = this.values[0]
        while(true){
            let leftChildIdx = idx*2 + 1
            let rightChildIdx = idx*2 + 2
            let leftChild,rightChild
            let swap = null
            if(leftChildIdx &lt; len){
                leftChild = this.values[leftChildIdx]
                if(leftChild &gt; element){
                    swap = leftChildIdx
                }
            }
            if(rightChildIdx &lt; len){
                rightChild = this.values[rightChildIdx]
                if((swap===null &amp;&amp; rightChild &gt; element) ||
                  (swap!==null &amp;&amp; rightChild &gt; element)){
                      swap = rightChildIdx
                  }
            }
            if(swap === null) break
            this.values[idx] = this.values[swap]
            this.values[swap] = element
            idx = swap
        }    
    }
    extractMax(){
        let max = this.values[0]
        let end = this.values.pop()
        if(this.values.length !== 0){
            this.values[0] = end
        }
        this.sinkDown()
        return max
    }</code></pre></blockquote>
<pre><code>

# 우선 순위 큐 (응급실)
- 더 높은 우선순위를 가진 요소가 더 낮은 우선순위를 가진 요소보다 먼저 처리된다.
- 각 노드에 우선순위와 값이 저장된다.
- 최대이진힙 또는 최소이진힙을 사용하여 구현할수 있다. (배열로 구현하는거 보다 훨씬 빠르다)

&gt; ```
class Node{
    constructor(val,priority){
        this.val = val
        this.priority=priority
    }
}
class PriorityQueue{
    constructor(){
        this.values = []
    }
    enqueue(val,priority){
        let newNode = new Node(val,priority)
        this.values.push(newNode)
        this.bubbleUp()
    }
    bubbleUp(){
        let idx = this.values.length-1
        let element = this.values[idx]
        while(idx &gt; 0){
            let parentIdx = Math.floor((idx-1)/2)
            let parent = this.values[parentIdx]
            if(parent.priority &gt; element.priority) break;
            this.values[parentIdx] = element
            this.values[idx] = parent
            idx = parentIdx
        }
    }
    dequeue(){
        const max = this.values[0]
        const end = this.values.pop()
        if(this.values.length !== 0){
            this.values[0] = end
            this.sinkDown()
        } 
        return max
    }
    sinkDown(){
        let idx = 0 
        let element = this.values[0]
        let length = this.values.length
&gt; 
        while(true){
            let swap = null
            let leftIdx = idx*2+1
            let rightIdx = idx*2+2
            if(leftIdx &lt; length ){
                let leftChild = this.values[leftIdx]
                if(element.priority &lt; leftChild.priority){
                    swap = leftIdx
                }
            }
            if(rightIdx &lt;length){
                let rightChild = this.values[rightChild]
                if((swap === null &amp;&amp; element.priority &lt; rightChild.priority)||
                (swap!==null &amp;&amp; element.priority &lt; rightChild.priority)){
                    swap = rightIdx
                }
            }
            if(swap === null) break
            this.values[idx] = this.values[swap] 
            this.values[swap] = element
            idx = swap
        }
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[상위 n개의 레코드]]></title>
            <link>https://velog.io/@lsh__97/%EC%83%81%EC%9C%84-n%EA%B0%9C%EC%9D%98-%EB%A0%88%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@lsh__97/%EC%83%81%EC%9C%84-n%EA%B0%9C%EC%9D%98-%EB%A0%88%EC%BD%94%EB%93%9C</guid>
            <pubDate>Thu, 03 Feb 2022 06:21:23 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>주어진 테이블에서 가장 먼저 보호소에 들어온 동물 이름을 조회하는 것이다.</p>
<h2 id="풀이">풀이</h2>
<p>처음에는 TOP 1 을 사용해 풀려고 했지만 그건 sql server, mssql에서만 사용 가능하다고 합니다.!!
그래서 찾아보니 mysql는 TOP 대신 LIMIT를 사용할 수 있다 하여 이를 사용하여 풀었습니다.</p>
<blockquote>
<pre><code>SELECT NAME
FROM ANIMAL_INS
ORDER BY DATETIME ASC LIMIT 1</code></pre></blockquote>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[해시 테이블]]></title>
            <link>https://velog.io/@lsh__97/%ED%95%B4%EC%8B%9C-%ED%85%8C%EC%9D%B4%EB%B8%94</link>
            <guid>https://velog.io/@lsh__97/%ED%95%B4%EC%8B%9C-%ED%85%8C%EC%9D%B4%EB%B8%94</guid>
            <pubDate>Sun, 30 Jan 2022 14:52:05 GMT</pubDate>
            <description><![CDATA[<h1 id="hash-table">Hash Table</h1>
<p> 대부분의 언어에서 이미 내장 함수를 가지지만 여기서는 직접 해시 테이블을 함수를 만들어 구현한다.!</p>
<h2 id="해시-테이블-특징">해시 테이블 특징</h2>
<ul>
<li><p>JS에서는 Obj, Map을 가진다.</p>
</li>
<li><p>해시 테이블은 키-값 쌍을 저장하는데 사용된다.</p>
</li>
<li><p>해시 테이블의 키는 순서를 가지지 않는다.</p>
</li>
<li><p>값을 찾거나, 새로운 값을 추가하거나, 값을 제거하는데 아주 빠르다.</p>
<h2 id="좋은-해시-테이블이란">좋은 해시 테이블이란?</h2>
</li>
<li><p>속도가 빠르다</p>
</li>
<li><p>일관된 방식으로 분배를 해서 다른 것들과 겹치지 않게 해야 한다.</p>
</li>
<li><p>특정 입력값을 입력할 때마다 같은 출력값이 나와야 한다.</p>
</li>
</ul>
<h2 id="충돌-처리">충돌 처리</h2>
<h3 id="개별-체이닝separate-chaining">개별 체이닝(Separate Chaining)</h3>
<ul>
<li>같은 장소에 여러 데이터를 저장할때 배열이나 연결 리스트 등과 같은 것을 활용하여 이중 데이터 구조를 쓰는것</li>
<li>테이블의 길이보다 더 많은 데이터를 저장할 수 있다.<img src="https://user-images.githubusercontent.com/59095793/151695236-303f30f6-a540-43f1-8876-74c5f0acf741.png" width="600">
### 직진 탐색법(Linear Probing)
충돌이 발생하면 다음 빈칸이 어디인지 확인하고 빈칸에 저장한다, 이렇게 하면 데이터가 같은 인덱스에 저장되는 것을 막을 수 있다.
<img src="https://user-images.githubusercontent.com/59095793/151695770-59f02b9e-1ca5-43c4-943d-e2b69fb1c659.png" width="600">

</li>
</ul>
<h2 id="해시-테이블-구현-키값은-스트링만-사용">해시 테이블 구현 (키값은 스트링만 사용)</h2>
<p>배열의 길이가 소수 일경우 소수가 아닐때보다 충돌 횟수가 줄어든다.</p>
<blockquote>
<pre><code>class HashTable { 
    constructor(size=53){
        this.keyMap = new Array(size)
    }
    _hash(key){
        let total = 0
        let WEIRD_PRIME = 31
        for(let i =0; i&lt;Math.min(key.length,100); i++){
            let char = key[i]
            let value = char.charCodeAt(0) - 96
            total = (total * WEIRD_PRIME + value) % this.keyMap.length
        }
        return total
    }
}</code></pre></blockquote>
<pre><code>
### Set method 구현
1. key와 value를 받는다.
2. key를 해시한후에 개별 체이닝을 통해 해시 테이블에 저장한다.

&gt;  ```
set(key,value){
        let hashKey = this._hash(key)
        if(!this.keyMap[hashKey]){
            this.keyMap[hashKey] = []
        }
        this.keyMap[hashKey].push([key,value])
        return this
    }</code></pre><h3 id="get-method-구현">Get method 구현</h3>
<ol>
<li>key를 받는다.</li>
<li>key를 해시한후 값을 확인한다.</li>
<li>key가 없다면 return undefined</li>
</ol>
<blockquote>
<pre><code>get(key) {
        let hashKey = this._hash(key)
        if(this.keyMap[hashKey]){
            for(let i = 0; i&lt;this.keyMap[hashKey].length; i++){
                if(this.keyMap[hashKey][i][0] === key){
                    return this.keyMap[hashKey][i][1]
                }
            }
        }
        return undefined
    }</code></pre></blockquote>
<pre><code>
### Keys method 구현
테이블에 있는 모든 키를 포함한 목록을 출력한다.

&gt; ```
 keys(){
        let keysArr = []
        for(let i = 0; i&lt; this.keyMap.length; i++){
            if(this.keyMap[i]){
                for(let j = 0; j&lt;this.keyMap[i].length; j++){
                    if(!keysArr.includes(this.keyMap[i][j][0])){
                        keysArr.push(this.keyMap[i][j][0])
                    }
                }
            }
        }
        return keysArr
    }</code></pre><h3 id="values-method-구현">Values method 구현</h3>
<p>테이블에 있는 모든 값을 포함한 목록을 출력한다.</p>
<blockquote>
<pre><code>values(){
        let valuesArr = []
        for(let i = 0; i&lt; this.keyMap.length; i++){
            if(this.keyMap[i]){
                for(let j = 0; j&lt;this.keyMap[i].length; j++){
                    if(!valuesArr.includes(this.keyMap[i][j][1])){
                        valuesArr.push(this.keyMap[i][j][1])
                    }
                }
            }
        }
        return valuesArr
    }</code></pre></blockquote>
<p>```</p>
<h2 id="시간-복잡도">시간 복잡도</h2>
<ul>
<li>Insert : O(1)</li>
<li>Deletion : O(1)</li>
<li>Access : O(1)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[트리 순회]]></title>
            <link>https://velog.io/@lsh__97/%ED%8A%B8%EB%A6%AC-%EC%88%9C%ED%9A%8C</link>
            <guid>https://velog.io/@lsh__97/%ED%8A%B8%EB%A6%AC-%EC%88%9C%ED%9A%8C</guid>
            <pubDate>Sat, 29 Jan 2022 19:42:11 GMT</pubDate>
            <description><![CDATA[<h1 id="트리-순회-tree-traversal">트리 순회 (TREE TRAVERSAL)</h1>
<ul>
<li>일반적인 트리 모두에서 사용가능하다</li>
</ul>
<h2 id="두가지-방법">두가지 방법</h2>
<h3 id="breadth-first-search너비-우선">Breadth-first Search(너비 우선)</h3>
<p>다음 레벨로 넘어가기전에 같은 레벨에 있는 모든 노드들을 거쳐가는것!(자식 노드들을 보기전에 형제 노드들을 먼저 본다.)
<img src="https://user-images.githubusercontent.com/59095793/151219308-a5439fa7-3de1-43e2-9fc6-a145aad5f6af.png" width="600"></p>
<h4 id="steps-편의상-queue를-직접-class로-구현하지않고-배열을-사용한다-dequeue는-shift">Steps (편의상 queue를 직접 class로 구현하지않고 배열을 사용한다, dequeue는 shift)</h4>
<ol>
<li>큐를 생성하고, 노드의 값을 저장할 리스트 변수(방문한 순서)를 생성한다.</li>
<li>큐에 루트노드를 넣는다.</li>
<li>큐에 아무 값이 없을때까지 루프를 돈다.</li>
<li>만약 큐에 무언가 들어있다면 dequeue를 사용하여 가장 앞의 값을 빼고 리스트 변수에 push해준다.</li>
<li>4번에서 dequeue한 노드의 왼쪽에 값이 있는지 확인하고 값이 있으면 큐에 넣는다.</li>
<li>4번에서 dequeue한 노드의 오른쪽에 값이 있는지 확인하고 값이 있으면 큐에 넣는다.</li>
<li>3~4를 반복해준다.</li>
<li>return 리스트</li>
</ol>
<h5 id="구현">구현</h5>
<blockquote>
<pre><code>BFS(){
        if(!this.root) return false
        let visited = [], queue = [], node = this.root
        queue.push(node)
        while(queue.length){
            node = queue.shift()
            visited.push(node.val)
            // queue에 push해주어 수평 레벨에 대한 노드를 넣어준다.
            if(node.left) queue.push(node.left)
            if(node.right) queue.push(node.right)
        }
        return visited
    }</code></pre></blockquote>
<pre><code>
### Depth-first Search(깊이 우선)
형제 노드로 넘어가기전에 수직으로 트리의 끝까지 내려간다.
#### DFS - PreOrder(전위순회)
root =&gt; left =&gt; right
1. 방문한 노드를 저장할 visited 변수와 현재 노드를 가르키는 current변수를 생성한다.
2. current을 인자로 받는 헬퍼 함수를 생성한다(traverse(node))
3. visited에 인자로 받은 node를 넣어준다.
4. node.left가 있다면 node.left값으로 헬퍼함수를 실행해준다.
5. node.right가 있다면 node.right값으로 헬퍼함수를 실행해준다.
6. return visited

&gt; ```
DFSPreOrder(){
        let visited = [], current = this.root
        function traverse(node){
                visited.push(node.val)
                if(node.left) traverse(node.left)
                if(node.right) traverse(node.right)
        }
        traverse(this.root)
        return visited
}</code></pre><h4 id="dfs---postorder후위순회">DFS - PostOrder(후위순회)</h4>
<p>left =&gt; right =&gt; root</p>
<blockquote>
<pre><code>DFSPostOrder(){
        let visited=[], current = this.root
        function traverse(node){
            if(node.left) traverse(node.left)
            if(node.right) traverse(node.right)
            visited.push(node.val)
        }
        traverse(current)
        return visited
    }</code></pre></blockquote>
<pre><code>
#### DFS - InOrder(중위순회)
left =&gt; root =&gt; right

&gt; ```
DFSInOrder(){
        let visited=[], current = this.root
        function traverse(node){
            if(node.left) traverse(node.left)
            visited.push(node.val)
            if(node.right) traverse(node.right)
        }
        traverse(current)
        return visited
    }</code></pre><h2 id="사용되는-상황">사용되는 상황</h2>
<p>시간 복잡도는 같기 때문에 트리의 구조에 따라 무엇을 사용할지 정한다.</p>
<ul>
<li>깊이보다 너비가 넓은 트리의 경우 : DFS (더 적은 공간을 차지한다, BFS를 사용할경우 queue에 많은 노드들을 저장해야함)<h3 id="전위후위정위">전위,후위,정위</h3>
</li>
<li>정위 : 모든 노드들을 오름차순으로 구할수있다. (이진 탐색 트리일경우)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Binary Search Tree]]></title>
            <link>https://velog.io/@lsh__97/Binary-Search-Tree</link>
            <guid>https://velog.io/@lsh__97/Binary-Search-Tree</guid>
            <pubDate>Wed, 26 Jan 2022 15:33:50 GMT</pubDate>
            <description><![CDATA[<h1 id="binary-trees">Binary Trees</h1>
<ul>
<li>비선형 구조</li>
</ul>
<h2 id="트리-사용예시">트리 사용예시</h2>
<ul>
<li>HTML DOM</li>
<li>Network Routing</li>
<li>AI</li>
<li>Computer File Systems</li>
</ul>
<h2 id="트리-용어-정리">트리 용어 정리</h2>
<ul>
<li>Root : 트리의 꼭대기 노드 </li>
<li>Child : 루트에서 멀어지는 방향으로 연결된 노드</li>
<li>Parent : Child의 반대</li>
<li>Siblings : 같은 부모노드를 가지는 자식 노드들 </li>
<li>Leaf : 자식이 없는 노드</li>
<li>Edge : 노드들을 연결하는 것</li>
</ul>
<h2 id="binary-search-tree">Binary Search Tree</h2>
<ul>
<li>정렬 데이터를 가지고 탐색 작업을 한다.</li>
</ul>
<h2 id="binary-search-tree-특징">Binary Search Tree 특징</h2>
<ul>
<li>모든 부모 노드는 <b>최대 2개</b>의 자식 노드를 가진다.</li>
<li>데이터가 특정한 순서로 저장된다.</li>
<li><b>부모 노드보다 왼쪽에 있는 모든 노드는 언제나 부모보다 작다</b></li>
<li><b>부모 노드보다 오른쪽에 있는 모든 노드는 언제나 부모보다 크다.</b></li>
</ul>
<h2 id="big-o-of-bst">Big O of BST</h2>
<ul>
<li>Insertion - O(log n)</li>
<li>Searching - O(log n)</li>
</ul>
<h2 id="binarysearchtree-class">BinarySearchTree Class</h2>
<blockquote>
<pre><code>  class Node {
    constructor(val){
      this.val = val
      this.left = null
      this.right = null
    }
  }</code></pre></blockquote>
<pre><code>
&gt; ```
  class BinarySearchTree {
    constructor(){
      this.root = null
    }
  }</code></pre><h2 id="bst-inserting-method">BST Inserting method</h2>
<ul>
<li>새로운 노드를 생성하여 제데로 된 자리에 노드를 놓는다.<h3 id="의사코드">의사코드</h3>
</li>
</ul>
<ol>
<li>새로운 노드 생성</li>
<li>루트가 있는지 확인</li>
<li>루트가 없으면 루트는 새로운 노드가 되고 트리를 리턴한다.</li>
<li>만약 루트가 있다면 현재 위치를 나타내는 currentNode변수를 생성한다</li>
<li>while문을 돌며 트리를 탐색한다.</li>
<li>만약 기존에 트리에 있는 값이 들어온다면 return undefined.</li>
<li>현재 값보다 새로운 노드의 값이 크다면 현재 위치에 오른쪽에 값이 있는지 확인 한고 없으면 그곳이 새로 생성된 노드의 위치다.</li>
<li>만약 현재 값보다 새로운 노드의 값이 작다면 현재 위치에 왼쪽에 값이 있는지 확인 하고 없다면 그곳이 새로 생성된 노드의 위치다. </li>
</ol>
<blockquote>
<pre><code>insert(val){
  let newNode = new Node(val)
  if(!this.root){
    this.root = newNode
    return this
  }else{
    let currentNode = this.root 
    //currentNode, true 둘다 상관없다.
    while(true){
      //기존에 있는 값인 경우
      if(val === currentNode.val) return undefined
      if(currentNode.val &lt; val){
        if(currentNode.right){
          currentNode = currentNode.right
        }else{
          currentNode.right = newNode
          return this
        }
      }else{
        if(currentNode.left){
          currentNode = currentNode.left 
        }else{
          currentNode.left = newNode
          return this
        }
      }
    }
  }
}</code></pre></blockquote>
<pre><code>
## BST Find method
- 새로운 노드를 생성하여 제데로 된 자리에 노드를 놓는다.
### 의사코드
1. 루트가 있는지 확인.
2. 루트가 없으면 return false.
3. 만약 루트가 있다면 현재 위치를 나타내는 currentNode변수와 found변수를 생성한다.
4. while문을 돌며 트리를 탐색한다.
5. 현재 값보다 찾고자 하는 값이 크다면 현재 위치는 현재위치 오른쪽.
6. 만약 현재 값보다 찾고자 하는 값이 작다면 현재 위치는 위치 왼쪽.
7. 5,6번이 아니라면 found는 true로 업데이트하고 while문을 종료한다.
8. return currentNode.

&gt; ```
find(val){
  if(!this.root) return false
  let currentNode = this.root
  let found = false
  while(currentNode &amp;&amp; !found){
    if(currentNode.val &lt; val){
      currentNode = currentNode.right
    }else if(val &lt; currentNode.val){
      currentNode = currentNode.left
    }else{
      found = !found
    }
  }
  return currentNode
}</code></pre>]]></description>
        </item>
    </channel>
</rss>