<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>MINIMI LAB</title>
    <link>https://minimilab.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 21 Jul 2026 15:15:38 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>운영하는 사람</managingEditor>
    <image>
      <title>MINIMI LAB</title>
      <url>https://tistory1.daumcdn.net/tistory/3108158/attach/1b66c341f63a4d52ac8dc454edf865ec</url>
      <link>https://minimilab.tistory.com</link>
    </image>
    <item>
      <title>threading 함수 실행방법</title>
      <link>https://minimilab.tistory.com/81</link>
      <description>&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import threading
import time
import logging


# 스레드 실행 함수
def thread_func(name):
    logging.info('sub-thread %s: starting', name)
    time.sleep(3)
    logging.info('sub-thread %s: finishing', name)

if __name__ == &quot;__main__&quot;:
    format = &quot;%(asctime)s: %(message)s&quot;
    logging.basicConfig(format=format, level=logging.INFO, datefmt='%H:%M:%S')
    logging.info('main-thread : before creating thread')

    # 함수 인자 확인
    x = threading.Thread(target=thread_func, args=('First', ))

    logging.info('main-thread : before running thread' )

    # 서브 스레드 시작
    x.start()

    # x.join() # # 스레드는 한번 실행되면 메인 로직과 상관없이 바로 끝까지 실행되는데, join 이 있으면, 스레드가 모두 끝난 후 다음 로직이 실행됨

    logging.info('main-thread : wait for the thread to finish' )
    logging.info('main-thread : all done' )
&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;21:31:47:&amp;nbsp;main-thread&amp;nbsp;:&amp;nbsp;before&amp;nbsp;creating&amp;nbsp;thread &lt;br /&gt;21:31:47:&amp;nbsp;main-thread&amp;nbsp;:&amp;nbsp;before&amp;nbsp;running&amp;nbsp;thread &lt;br /&gt;21:31:47:&amp;nbsp;sub-thread&amp;nbsp;First:&amp;nbsp;starting &lt;br /&gt;21:31:47:&amp;nbsp;main-thread&amp;nbsp;:&amp;nbsp;wait&amp;nbsp;for&amp;nbsp;the&amp;nbsp;thread&amp;nbsp;to&amp;nbsp;finish &lt;br /&gt;21:31:47:&amp;nbsp;main-thread&amp;nbsp;:&amp;nbsp;all&amp;nbsp;done&lt;/p&gt;</description>
      <category>Python</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/81</guid>
      <comments>https://minimilab.tistory.com/81#entry81comment</comments>
      <pubDate>Tue, 3 Jan 2023 21:32:16 +0900</pubDate>
    </item>
    <item>
      <title>Python GIL</title>
      <link>https://minimilab.tistory.com/80</link>
      <description>&lt;h1&gt;GIL이란?&lt;/h1&gt;
&lt;p&gt;Python(bytecode) 을  Cpython 가 실행함. 실행 시 여러 thread 사용할 경우 단일 스레드만이 python object 만이 접근하게 제안하는 mutex&lt;br&gt;멀티 스레드를 사용해도 단 하나의 object 만이 접근이 가능하도록 함&lt;br&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D6Vz0/btrVh6kiDgB/vbv7l3GZO4XxJzeJkJyL41/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D6Vz0/btrVh6kiDgB/vbv7l3GZO4XxJzeJkJyL41/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D6Vz0/btrVh6kiDgB/vbv7l3GZO4XxJzeJkJyL41/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD6Vz0%2FbtrVh6kiDgB%2Fvbv7l3GZO4XxJzeJkJyL41%2Fimg.jpg&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br&gt;Thread를 안전하게 사용하기 위함&lt;/p&gt;
&lt;h1&gt;GIL(Global Interpreter Lock)이 있지만 Python을 써도 되는 이유&lt;/h1&gt;
&lt;p&gt;(1) 단일스레드로도 충분히 빠르다.&lt;br&gt;(2) 멀티 프로세스로 하는 작업을 만들어서 사용하면 되기 때문에 제약이 된다고 보지 않음&lt;br&gt;    - numpy 등 대용량 라이브러리 등도 멀티 프로세스로 사용하기 때문에 문제가 되지 않음&lt;br&gt;(3) 병렬 처리는 Multiprocessing, asyncio 선택지등 다양한 방식 사용 가능&lt;br&gt;(4) thread 동시성 완벽 처리를 위해 Jython, IronPython, Stackless Python 등이 존재&lt;/p&gt;</description>
      <category>Python</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/80</guid>
      <comments>https://minimilab.tistory.com/80#entry80comment</comments>
      <pubDate>Tue, 3 Jan 2023 20:15:40 +0900</pubDate>
    </item>
    <item>
      <title>프로세스와 쓰레드</title>
      <link>https://minimilab.tistory.com/79</link>
      <description>&lt;p&gt;(1) 프로세스&lt;br&gt;    - 운영체제 -&amp;gt; 할당 받는 자원 단위 (실행 중인프로그램)&lt;br&gt;    - CPU동작 시간, 주소공간(독립적)&lt;br&gt;    - Code, Data, Stack, Heap -&amp;gt; 독립적&lt;br&gt;    - 최소 1개의 메인 스레드를 보유함&lt;br&gt;        - ex) 하나의 크롬 프로세스에서 여러가지 새탭을 통해서 스레드를 사용&lt;br&gt;    - 파이프, 파일, 소켓 등을 사용해서 프로세스간 통신&lt;br&gt;        - Context Swithing &lt;/p&gt;
&lt;p&gt;(2) 스레드&lt;br&gt;    - 프로새스 내에서 실행 흐름 단위&lt;br&gt;    - 프로세스 자원 사용&lt;br&gt;    - Stack 만 별도로 할당하고 나머지는 공유(Code, Data, Heap)&lt;br&gt;    - 메모리 공유(변수 공유)&lt;br&gt;    - 한 스레드의 결과가 다른 스레드에 영향을 끼치 수 있음&lt;br&gt;    - 동기화 문제는 정말 주의해서 코드를 작성해야함 (디버깅이 어려움)&lt;br&gt;    &lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIUylX/btrVh7pYQbB/RygVgeeyRU7A9kZMEOkib1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIUylX/btrVh7pYQbB/RygVgeeyRU7A9kZMEOkib1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIUylX/btrVh7pYQbB/RygVgeeyRU7A9kZMEOkib1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIUylX%2FbtrVh7pYQbB%2FRygVgeeyRU7A9kZMEOkib1%2Fimg.jpg&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;(3) 멀티 스레드&lt;br&gt;    - 한 개의 단일 어플리케이션(응용프로그램) -&amp;gt; 여러 스레드로 구성 후 작업 처리&lt;br&gt;    - 시스템 자원 소모 감소(효율성, 처리량 증가(cost 감소))&lt;br&gt;    - 통신 부담 감소, 디버깅 어려움, 단일 프로세스에는 효과 미약, 자원 공유 문제(교착 상태), 프로세스 영향&lt;/p&gt;
&lt;p&gt;(4) 멀티 프로세스&lt;br&gt;    - 한 개의 단일 어플리케이션(응용프로그램) -&amp;gt; 여러 프로세스로 구성 후 작업 처리&lt;br&gt;    - 한 개의 프로세스 문제 발생은 확산이 없음(독립적으로 종료시킬 수 있음(프로세스 kill))&lt;br&gt;    - 캐시 체인지, Cost 비용 매우 높음(오버헤드), 복잡한 통신 방식 사용 &lt;/p&gt;</description>
      <category>Python</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/79</guid>
      <comments>https://minimilab.tistory.com/79#entry79comment</comments>
      <pubDate>Tue, 3 Jan 2023 19:54:37 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 객체지향 기본기</title>
      <link>https://minimilab.tistory.com/78</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;HTtps-001 (5).jpg&quot; width=&quot;400&quot; height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LXb4H/btrjvrsLS5t/07eF4IxcC7q3vcrc5mRE1k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LXb4H/btrjvrsLS5t/07eF4IxcC7q3vcrc5mRE1k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LXb4H/btrjvrsLS5t/07eF4IxcC7q3vcrc5mRE1k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLXb4H%2FbtrjvrsLS5t%2F07eF4IxcC7q3vcrc5mRE1k%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;HTtps-001 (5).jpg&quot; width=&quot;400&quot; height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;코드잇의 자바스크립트 객체지향 기본기 강의를 듣고 정리한 내용입니다.&lt;br /&gt;&lt;/span&gt;문제가 될 시 삭제하겠습니다.&lt;/blockquote&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;코드잇 자바스크립트 객체지향 기본기&lt;/h1&gt;
&lt;h1&gt;1. 객체와 클래스&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 객체 지향 프로그래밍이란 ?&lt;/h2&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;/li&gt;
&lt;li&gt;절차 지향 프로그래밍 : 변수와 함수를 가지고 작업의 순서에 맞게 코드를 작성하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 1-1. object literal&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Object Literal : 객체를 나타내는 문자열&lt;/li&gt;
&lt;li&gt;index.html&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
        &amp;lt;title&amp;gt;자바스크립트 객체 지향&amp;lt;/title&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;script src=&quot;./index.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&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;index.js&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;console.log('test');

const user = {
    // property 속성 : 객체의 상태를 담음 
    email: 'chris@google.com',
    birthdate: '1991-05-11',

    // method 함수
    buy(item) {
        console.log(`${this.email} buys ${item.name}`); //this 는 현재 객체의 email
    },
};

const item = {
    name: '스웨터',
    price: 30000,
};

// 객체의 property 속성과, method 함수 실행
console.log(user.email); // chris@google.com
console.log(user.birthdate); // 1991-05-11
user.buy(item); // chris@google.com buys 스웨터&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;subunit&quot;&gt;&lt;code&gt;test
index.js:21 chris@google.com
index.js:22 1991-05-11
index.js:12 chris@google.com buys 스웨터&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 1-2. Factory function&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;index.js&lt;/li&gt;
&lt;li&gt;객체를 생성하는 Factory function을 만들고, 그 안에서 Object literal로 객체를 생성하여 리턴하는 방법입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function createUser(email, birthdate) {
    const user = {
                // email property 와 email 파라미터가 같은 경우에는 email: email, -&amp;gt; email, 로 변경해도 됨
        email: email,
        birthdate: birthdate,
        buy(item) {
            console.log(`${this.email} buys ${item.name}`);
        },
    };
    return user;
}

const item = {
    name: '스웨터',
    price: 30000,
};

// Factory Function 
const user1 = createUser('minimi@google.com', '1991-05-11');
const user2 = createUser('test@google.com', '1995-01-11');
console.log(user1.email);
console.log(user2.email);

user1.buy(item);
user2.buy(item);&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;minimi@google.com
index.js:22 test@google.com
index.js:7 minimi@google.com buys 스웨터
index.js:7 test@google.com buys 스웨터&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. Constructor function&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// constructor function
// this는 해당 객체를 의미 
// 객체 생성용 메서드는 User 처럼 맨 앞글자를 대문자로 함(관습)
function User(email, bitrhdate) {
    this.email = email;
    this.birthdate = birthdate;
    this.buy = function (item) {
        console.log(`${this.email} buys ${item.name}`);
    };
}

const item = {
    name: '스웨터',
    price : 30000,
};

// new 를 붙여야 객체를 생성할 수 있음
const user1 = new User('minimi@gmail.com', '1991-03-21');
console.log(user1.email);
console.log(user1.birthdate);
user1.buy(item);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 객체 만들기3 : Class&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class User {
    // this를 사용하여 변수를 할당한다.
    constructor(email, birthdate){
        this.email = email;
        this.birthdate = birthdate;
    }

    // 메소드는 constructor 안이 아닌 밖에 위치해아 한다. 
    buy(item) {
        console.log(`${this.email} buys ${item.name}`);
    }
}

const item = {
    name: '스웨터',
    price: 30000,
};

const user1 = new User('minimi@google.com', '1992-03-21');
console.log(user1.email);
console.log(user1.birthdate);
user1.buy(item);

const user2 = new User('minimi2@google.com', '1992-03-21');
console.log(user2.email);
console.log(user2.birthdate);
user2.buy(item);
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;2. 객체 지향 프로그래밍의 4개의 기둥&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 추상화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상화 : 어떤 구체적인 존재를 원하는 방향으로 간략화해서 나타내는 것&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 캡슐화&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;setter메소드&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class User {
    constructor(email, birthdate) {
        this.email = email;
        this.birthdate = birthdate;
    }

    buy(item) {
        console.log(`${this.email} buys ${item.name}`);
    }

    get email() {
        return this._email;
    }

    set email(address) { // 그냥 email은 setter 메소드의 이름이 됨
        if (address.includes('@')) { // 값에 대한 유효성 검사
            this._email = address; // _email 에 address를 저장함
        } else {
            throw new Error('invalid email address');
        }
    }
}

const item = {
    name: '스웨터',
    price: 30000,
};

const user1 = new User('chris123@google.com', '1992-03-21')
user1.email = 'chris_robert@google.com';
console.log(user1._email); // -&amp;gt; getter 메소드(get email()) 메소드가 구현되어 있으면 console.log(user1.email); 로 사용 가능&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 캡슐화 더 알아보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 완벽한 캡슐화를 하는 법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 영상에서는 다음 코드로 캡슐화를 배웠습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;class User {
  constructor(email, birthdate) {
    this.email = email;
    this.birthdate = birthdate;
  }

  buy(item) {
    console.log(`${this.email} buys ${item.name}`);
  }

  get email() {
    return this._email;
  }

  set email(address) {
    if (address.includes('@')) {
      this._email = address;
    } else {
      throw new Error('invalid email address');
    }
  }
}

const user1 = new User('chris123@google.com', '1992-03-21');
user1.email = 'newChris123@google.com';
console.log(user1.email);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 코드를 보면 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt; 프로퍼티에 직접 접근하지 말고, &lt;b&gt;&lt;code&gt;email&lt;/code&gt;&lt;/b&gt;이라는 getter/setter 메소드로만 접근해야 한다는 것이 눈에 잘 보입니다. 하지만 사실 완벽한 캡슐화가 된 상태는 아닙니다. 왜냐하면 보호하려는 프로퍼티 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt;에&lt;/p&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;console.log(user1._email);
user1._email = 'chris robert';
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 여전히 직접 접근할 수는 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 자바스크립트에는 캡슐화를 자체적으로 지원하는 문법이 아직 없습니다.(Java는 private이라는 키워드가 있어서 언어의 문법 차원에서 캡슐화를 지원합니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 JavaScript에서도 다른 방식으로 우회해서 완벽한 캡슐화를 할 수는 있는데요. 클로저(Closure)라고 하는 개념을 응용해서 적용하면 됩니다. 잠깐 아래 코드를 보세요.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;function createUser(email, birthdate) {
  let _email = email;

  const user = {
    birthdate,

    get email() {
      return _email;
    },

    set email(address) {
      if (address.includes('@')) {
        _email = address;
      } else {
        throw new Error('invalid email address');
      }
    },
  };

  return user;
}

const user1 = createUser('chris123@google.com', '19920321');
console.log(user1.email);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 이 코드를 보면 createUser라고 하는 Factory function이 보입니다. 그런데 생성하려는 user 객체 안에 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt; 프로퍼티가 있는 게 &lt;b&gt;아니라&lt;/b&gt;,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) createUser 함수 안에,&lt;br /&gt;(2) 그리고 user 객체 바깥에 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt;이라는 변수가 있죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신에 user 객체 안에는 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt; 변수의 값을 읽고 쓸 수 있는 &lt;b&gt;&lt;code&gt;email&lt;/code&gt;&lt;/b&gt;이라는 getter/setter 메소드가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 마지막 부분에서 &lt;b&gt;&lt;code&gt;createUser&lt;/code&gt;&lt;/b&gt;라는 Factory function으로 &lt;b&gt;&lt;code&gt;user1&lt;/code&gt;&lt;/b&gt;이라는 객체를 생성하고, &lt;b&gt;&lt;code&gt;user1&lt;/code&gt;&lt;/b&gt; 객체의 &lt;b&gt;&lt;code&gt;email&lt;/code&gt;&lt;/b&gt; getter 메소드를 호출했는데요. 이 코드의 실행 결과를 확인해보면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4462&amp;amp;directory=Untitled.png&amp;amp;name=Untitled.png&quot;&gt;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4462&amp;amp;directory=Untitled.png&amp;amp;name=Untitled.png&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt; 변수의 값이 잘 출력됩니다. 함수 안의 변수의 값을 이미 리턴된 객체에서 읽은 건데요. 어떻게 이게 가능한 걸까요? 이것은 자바스크립트의 클로저(Closure)라고 하는 것 덕분에 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저란 자바스크립트에서 &lt;b&gt;어떤 함수와 그 함수가 참조할 수 있는 값들로 이루어진 환경을 하나로 묶은 것&lt;/b&gt;을 의미하는데요. 예를 들어, 지금 &lt;b&gt;&lt;code&gt;createUser&lt;/code&gt;&lt;/b&gt; 함수가 실행되는 시점에 &lt;b&gt;&lt;code&gt;email&lt;/code&gt;&lt;/b&gt;이라는 getter/setter 메소드는 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt; 이라는 변수의 값에 접근할 수 있는 상태입니다. 그리고 여기서 핵심은 이 &lt;b&gt;&lt;code&gt;email&lt;/code&gt;&lt;/b&gt; getter/setter 메소드들은 메소드를 갖고 있는 객체가 리턴된 이후더라도 여전히 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt;에 접근하는 것이 가능하다는 점입니다. 바로 이렇게 함수가 정의된 당시에 참조할 수 있었던 변수들을 계속 참조할 수 있는 상태의 함수를 클로저라고 합니다. 이 클로저는 다른 프로그래밍 언어에서는 쉽게 찾아보기 힘든 자바스크립트만의 특징인데요.(물론 클로저 개념이 있는 다른 언어들도 있습니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 다른 프로그래밍 언어였다면 createUser 함수 내부가 실행될 때만 &lt;b&gt;&lt;code&gt;email&lt;/code&gt;&lt;/b&gt; getter/setter 메소드가 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt; 변수에 접근할 수 있었겠지만, 자바스크립트에서는 클로저라는 개념으로 해당 환경을 함수와 함께 그대로 유지시켜주는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 클로저가 아닌 경우에는 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt; 변수에 접근할 수 없습니다. 만약 이런 식으로&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function createUser(email, birthdate) {
  let _email = email;

  const user = {
    birthdate,

    get email() {
      return _email;
    },

    set email(address) {
      if (address.includes('@')) {
        _email = address;
      } else {
        throw new Error('invalid email address');
      }
    },
  };

  return user;
}

const user1 = createUser('chris123@google.com', '19920321');
console.log(user1._email);// _ 추가&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user1 객체의 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt; 프로퍼티에 접근하려고 하면, &lt;b&gt;&lt;code&gt;user1&lt;/code&gt;&lt;/b&gt; 객체 자체 내에는 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt;이라고 하는 프로퍼티가 없고, 바깥의 &lt;b&gt;&lt;code&gt;_email&lt;/code&gt;&lt;/b&gt; 변수에 현재 접근할 수도 없기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4462&amp;amp;directory=Untitled%201.png&amp;amp;name=Untitled+1.png&quot;&gt;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4462&amp;amp;directory=Untitled%201.png&amp;amp;name=Untitled+1.png&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;undefined가 출력됩니다.&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;b&gt;2. 메소드도 캡슐화할 수 있어요&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때까지 우리는 프로퍼티를 보호하기 위해 getter/setter 메소드를 활용하거나, 좀더 완벽한 캡슐화를 위해 클로저를 사용할 수 있다는 것을 배웠습니다. 그런데 사실 프로퍼티 뿐만 아니라 메소드를 캡슐화하는 것도 가능합니다. 잠깐 이 코드를 볼까요?&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;function createUser(email, birthdate) {
  const _email = email;
  let _point = 0;

  function increasePoint() {
    _point += 1;
  }

  const user = {
    birthdate,

    get email() {
      return _email;
    },

    get point() {
      return _point;
    },

    buy(item) {
      console.log(`${this.email} buys ${item.name}`);
      increasePoint();
    },
  };

  return user;
}

const item = {
  name: '스웨터',
  price: 30000,
};

const user1 = createUser('chris123@google.com', '19920321');
user1.buy(item);
user1.buy(item);
user1.buy(item);
console.log(user1.point);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 &lt;b&gt;&lt;code&gt;_point&lt;/code&gt;&lt;/b&gt;라는 변수를 추가했는데요. 사용자가 물건을 살 때마다 1포인트씩 적립해 줄 목적으로 만든 변수입니다. 그리고 &lt;b&gt;&lt;code&gt;point&lt;/code&gt;&lt;/b&gt; getter 메소드도 지금 정의해둔 상태입니다. &lt;b&gt;&lt;code&gt;_point&lt;/code&gt;&lt;/b&gt; 변수를 1씩 늘려주는 함수는 바로 밑에 보이는 &lt;b&gt;&lt;code&gt;increasePoint&lt;/code&gt;&lt;/b&gt;라는 함수입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;b&gt;&lt;code&gt;increasePoint&lt;/code&gt;&lt;/b&gt; 라는 함수는 유저 객체의 &lt;b&gt;&lt;code&gt;buy&lt;/code&gt;&lt;/b&gt; 메소드 안에서 쓰이고 있는데요. &lt;b&gt;&lt;code&gt;buy&lt;/code&gt;&lt;/b&gt; 메소드를 실행할 때 그 안에서 &lt;b&gt;&lt;code&gt;increasePoint&lt;/code&gt;&lt;/b&gt; 함수도 호출을 해주는 겁니다. 맨 마지막 부분의 코드들을 보면 &lt;b&gt;&lt;code&gt;user1&lt;/code&gt;&lt;/b&gt; 객체의 &lt;b&gt;&lt;code&gt;buy&lt;/code&gt;&lt;/b&gt; 메소드를 호출하고 &lt;b&gt;&lt;code&gt;point&lt;/code&gt;&lt;/b&gt; getter 메소드를 호출하고 있는데요. 이 코드를 실행해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4462&amp;amp;directory=Untitled%202.png&amp;amp;name=Untitled+2.png&quot;&gt;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4462&amp;amp;directory=Untitled%202.png&amp;amp;name=Untitled+2.png&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 스웨터를 3번 구매했을 때, 포인트는 총 3점이 쌓이게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 여기서 중요한 점은 지금 &lt;b&gt;&lt;code&gt;increasePoint&lt;/code&gt;&lt;/b&gt;라는 함수가 보호받고 있는 함수라는 점입니다. 지금 &lt;b&gt;&lt;code&gt;user1&lt;/code&gt;&lt;/b&gt; 객체로 바로 &lt;b&gt;&lt;code&gt;increasePoint&lt;/code&gt;&lt;/b&gt; 함수를 호출할 수는 없습니다. 호출하려고 하면&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function createUser(email, birthdate) {
  const _email = email;
  let _point = 0;

  function increasePoint() {
    _point += 1;
  }

  const user = {
    birthdate,

    get email() {
      return _email;
    },

    get point() {
      return _point;
    },

    buy(item) {
      console.log(`${this.email} buys ${item.name}`);
      increasePoint();
    },
  };

  return user;
}

const item = {
  name: '스웨터',
  price: 30000,
};

const user1 = createUser('chris123@google.com', '19920321');
user1.buy(item);
user1.buy(item);
user1.buy(item);
console.log(user1.point);
user1.increasePoint();// user1 객체로 increasePoint 직접 호출&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4462&amp;amp;directory=Untitled%203.png&amp;amp;name=Untitled+3.png&quot;&gt;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4462&amp;amp;directory=Untitled%203.png&amp;amp;name=Untitled+3.png&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 그런 함수가 없다는 에러가 출력됩니다. 왜냐하면 &lt;b&gt;&lt;code&gt;user1&lt;/code&gt;&lt;/b&gt; 객체에는 &lt;b&gt;&lt;code&gt;increasePoint&lt;/code&gt;&lt;/b&gt;라는 메소드가 없기 때문입니다. 지금 저는 &lt;b&gt;&lt;code&gt;increasePoint&lt;/code&gt;&lt;/b&gt;가 유저 객체 안에서 적절한 곳에 사용되어야 하고, 아무렇게나 함부로 호출해서는 안 되는 메소드라고 가정하고 이렇게 캡슐화를 한 것입니다. 이런 식으로 메소드(정확하게 말하자면 increasePoint가 메소드는 아니니까 함수라고 할 수 있겠죠?)도 프로퍼티와 마찬가지로 클로저를 통해 캡슐화를 해서 보호할 수 있다는 사실, 잘 기억하세요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. 상속&lt;/h2&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class User {
    constructor(email, birthdate) {
        this.email = email;
        this.birthdate = birthdate;
    }

    buy(item) {
        console.log(`${this.email} buys ${item.name}`);
    }
}

class PremiumUser extends User {
    constructor(email, birthdate, level) {
        this.level= level;
    }

    streamMusicForFree() {
        console.log(`Free music streaming for ${this.email}`);
    }
}

const item = {
    name: '스웨터',
    price: 30000,
}

const pUser1 = new PremiumUser('chris123@googl.com', '1992-03-21')
console.log(pUser1.email);
console.log(pUser1.birthdate);
console.log(pUser1.level);
pUser1.buy(item);
pUser1.streamMusicForFree();&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. super&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class User {
    constructor(email, birthdate) {
        this.email = email;
        this.birthdate = birthdate;
    }

    buy(item) {
        console.log(`${this.email} buys ${item.name}`);
    }
}

class PremiumUser extends User {
    constructor(email, birthdate, level) {
        super(email, birthdate);
        this.level= level;
    }

    streamMusicForFree() {
        console.log(`Free music streaming for ${this.email}`);
    }
}

const item = {
    name: '스웨터',
    price: 30000,
}

const pUser1 = new PremiumUser('chris123@googl.com', '1992-03-21')
console.log(pUser1.email);
console.log(pUser1.birthdate);
console.log(pUser1.level);
pUser1.buy(item);
pUser1.streamMusicForFree();&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 다형성&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;
class User {
    constructor(email, birthdate) {
        this.email = email;
        this.birthdate = birthdate;
    }

    buy(item) {
        console.log(`${this.email} buys ${item.name}`);
    }
}

class PremiumUser extends User {
    constructor(email, birthdate, level) {
        super(email, birthdate);
        this.level= level;
    }

    streamMusicForFree() {
        console.log(`Free music streaming for ${this.email}`);
    }

    buy(item) {
        console.log(`${this.email} buys ${item.name} with a 5% discount`);
    }
}

// 오버라이딩 (overriding)
const item = {
    name: '스웨터',
    price: 30000,
}

const user1 = new User('sdf@google.com', '19910511');
const pUser1 = new PremiumUser('asd@google.com', '19911210');

user1.buy(item);
pUser1.buy(item);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 부모 클래스의 메소드가 필요하다면?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;super 키워드를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class User {
    constructor(email, birthdate) {
        this.email = email;
        this.birthdate = birthdate;
    }

    buy(item) {
        console.log(`${this.email} buys ${item.name}`);
    }
}

class PremiumUser extends User {
    constructor(email, birthdate, level, point) {
        super(email, birthdate);
        this.level= level;
        this.point = point;
    }

    streamMusicForFree() {
        console.log(`Free music streaming for ${this.email}`);
    }

    buy(item) {
        super.buy(item);
        this.point += item.price * 0.05;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. instanceof 연산자&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;instanceof 메소드로 어느 클래스로 만든 객체인지를 확인할 수 있음&lt;/li&gt;
&lt;li&gt;상속받아서 만든 객체는 부모클래스 객체임을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;const users = [user1, pUser1, user2, pUser2];

users.forEach(user) =&amp;gt; {
    console.log(user instanceof User);
});&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. static 프로퍼티와 static 메소드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;static 프로퍼티&lt;/li&gt;
&lt;li&gt;static 메소드&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;객체가 아닌 클래스 자체로 접근 !&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Math {
    static PI = 3.14;
    static getCircleArea(radius) {
        return Math.Pi * radius * radius;
    }
}

Math.PI = 3.141592;
Math.getRectangleArea = function (width, height) {
    return width * height;
}

console.log(Math.PI); // 3.14
console.log(Math.getCircleArea(5)); // 78.5
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Javascript</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/78</guid>
      <comments>https://minimilab.tistory.com/78#entry78comment</comments>
      <pubDate>Mon, 1 Nov 2021 21:49:03 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 웹 개발 기본기</title>
      <link>https://minimilab.tistory.com/77</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;HTtps-001 (4).jpg&quot; width=&quot;400&quot; height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXyljf/btrjkDk1muL/PKgkERytKd50yaLcKqrRB0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXyljf/btrjkDk1muL/PKgkERytKd50yaLcKqrRB0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXyljf/btrjkDk1muL/PKgkERytKd50yaLcKqrRB0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXyljf%2FbtrjkDk1muL%2FPKgkERytKd50yaLcKqrRB0%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;HTtps-001 (4).jpg&quot; width=&quot;400&quot; height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;코드잇의 자바스크립트 웹 개발 기본기 강의를 듣고 정리한 내용입니다.&lt;br /&gt;문제가 될 시 삭제하겠습니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h1&gt;자바스크립트 웹 개발 기본기&lt;/h1&gt;
&lt;h1&gt;3. 비동기 실행과 Promise 객체&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. fetch 함수와 비동기 실행&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;then 메소드로 등록했던 callback 들이 response가 오면 출력됨&lt;/li&gt;
&lt;li&gt;then 메소드로 등록만하고, 그 아래 코드가 실행됨&lt;/li&gt;
&lt;li&gt;비동기 실행 : 시작된 작업이 완료되기 전에 다음 코드를 실행하는 것&lt;/li&gt;
&lt;li&gt;동기 실행 : 시작한 작업을 다 처리하고 나서야 다음코드를 실행하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;console.log('Start');&lt;/li&gt;
&lt;li&gt;fetch 함수(리퀘스트 보내기 및 콜백 등록)&lt;/li&gt;
&lt;li&gt;console.log('End');&lt;/li&gt;
&lt;li&gt;리스폰스가 오면 2. 에서 then 메소드로 등록해뒀던 콜백 실행&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;console.log('Start!');

fetch('https://jsonplaceholder.typicode.com/users')
    .then((response) =&amp;gt; response.text())  // (response) =&amp;gt; { return response.text() } 와 같은 의미이고, arrow function 으로 사용됨
    .then((result) =&amp;gt; {console.log(result); });

console.log('End!');&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 알아야하는 비동기 실행 함수들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. setTimeout(콜백, 시간) : 특정 함수의 실행을 원하는 시간 만큼 뒤로 미루는 함수&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;console.log('a');
setTimeout(() =&amp;gt; { console.log('b'); }, 2000);
console.log('c');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.&amp;nbsp;setInterval(콜백, 시간) : 특정 콜백을 특정 시간 간격으로 실행함&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;console.log('a');
setInterval(() =&amp;gt; { console.log('b'); }, 2000);
console.log('c');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.&amp;nbsp;addEventListener(이벤트 이름, 콜백)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터로 전달된 콜백이 당장 실행되는 것이 아닐, 특정 조건이 만족될 때마다 실행 됨&lt;br /&gt;(1) 해당 DOM 객체의 onclick 속성에 그 함수를 설정하거나,&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;...

btn.onclick = function (e) { // 해당 이벤트 객체가 파라미터 e로 넘어옵니다.
  console.log('Hello Codeit!');
};

// 또는 arrow function 형식으로 이렇게 나타낼 수도 있습니다. 
btn.onclick = (e) =&amp;gt; {
  console.log('Hello Codeit!');
};

...
(2) 해당 DOM 객체의 addEventListener 메소드의 파라미터로 전달하면 됩니다.&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;...

btn.addEventListener('click', function (e) { // 해당 이벤트 객체가 파라미터 e로 넘어옵니다.
  console.log('Hello Codeit!');
});

// 또는 arrow function 형식으로 이렇게 나타낼 수도 있습니다.
btn.addEventListener('click', (e) =&amp;gt; {
  console.log('Hello Codeit!');
});

...&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. fetch 함수는 Promise 객체를 리턴합니다.&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;promise : 작업에 관한 상태정보를 가지고 있는 객체
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pending : 작업이 진행중&lt;/li&gt;
&lt;li&gt;fulfilled : 작업 성공, 작업 성공 결과를 받음&lt;/li&gt;
&lt;li&gt;rejected : 작업 실패 , 작업 실패 결과를 받음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. fetch 함수를 사용한 코드 다시 해석하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;then 메소드는 promise 객체의 메소드임&lt;/li&gt;
&lt;li&gt;fetch 함수는 promise 객체를 return 하고, .then 메소드를 사용하면 fullfilled 상태가 되었을 때 실행할 콜백을 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;console.log('Start!');

fetch('https://jsonplaceholder.typicode.com/users')
    .then((response) =&amp;gt; response.text())  // (response) =&amp;gt; { return response.text() } 와 같은 의미이고, arrow function 으로 사용됨
    .then((result) =&amp;gt; {console.log(result); });

console.log('End!');&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. promise chaining이란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;.then 메소드는 각각 별개의 promise 객체를 return 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. text, json 메소드도 Promise 객체를 return 해요&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;text 메소드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fetch 함수로 response를 잘 받으면, repsonse 객체의 text 메소드는, fulfilled 상태 이면서 response의 body에 있는 내용을 string 타입으로 변환한 값을 작업 성공결과로 가진 promise 객체를 return 함&lt;/li&gt;
&lt;li&gt;이때 작업 성공 결과는 string 타입이고, 그 값이 만약 JSON 데이터라면 JSON 객체의 parse 메소드로 Deserialize를 해줘야 함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JSON.parse(result);&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;json 메소드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fetch 함수로 response를 잘 받으면, repsonse 객체의 json 메소드는, fulfilled 상태 이면서 response의 body에 있는 JSON 데이터를 자바스크립트 객체로 Deserialize 해서 생겨난 객체를 '작업 성공 결과'로 가진 Promise 객체를 return 함&lt;/li&gt;
&lt;li&gt;then 메소드가 리턴했던 Promise 객체(A)는 그 콜백에서 리턴한 Promise 객체(B)와 동일한 상태와 결과를 갖게 된다.&lt;/li&gt;
&lt;li&gt;text, json 메소드가 Promise 객체를 리턴하는 메소드임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. Promise Chaining이 필요한 경우&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비동기 작업을 순차적으로 처리하기 위해서 Promise Chaining 을 함&lt;/li&gt;
&lt;li&gt;response 가 들어있는 정보를 가지고 해당 사용자가 작성한 id를 조회함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;console.log('Start!');

fetch('https://jsonplaceholder.typicode.com/users')
    .then((response) =&amp;gt; response.text())
    .then((result) -&amp;gt; {
        const users = JSON.parse(result);
        const {id} = users[0];
        return fetch(`https://jsonplaceholder.typicode.com/posts?userId=${id}`);
    })
    .then(response) =&amp;gt; response.text())
    .then((posts) =&amp;gt; {
        console.log(posts);
    });

console.log('End');
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 신입 사원 정보 반영하기&lt;/h2&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fetch('https://learn.codeit.kr/api/interviews/summer')
  .then((response) =&amp;gt; response.json())
  .then((interviewResult) =&amp;gt; {
    const { interviewees } = interviewResult;
    const newMembers = interviewees.filter((interviewee) =&amp;gt; interviewee.result === 'pass');
    return newMembers;
  })
  .then((newMembers) =&amp;gt; fetch('https://learn.codeit.kr/api/members', {
    method: 'POST',
    body: JSON.stringify(newMembers),
  }))
  .then((response) =&amp;gt; { 
    if (response.status === 200) {
      return fetch('https://learn.codeit.kr/api/members');
    } else {
      throw new Error('New members not added');
    }
  })
  .then((response) =&amp;gt; response.json())
  .then((members) =&amp;gt; {
    console.log(`총 직원 수: ${members.length}`);
    console.log(members);
  });&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. rejected 상태 일 경우&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;then 메소드의 두번째 파라미터로 넣으면 rejected 시 실행됨&lt;/li&gt;
&lt;li&gt;rejected 시 작업 실패 정보가 넘어옴&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;fetch('https://jsonplaceholder.typicode.com/users'}
    .then((response) =&amp;gt; response.text(), (error) =&amp;gt; {console.log(error); })
    .then((result) =&amp;gt; { console.log(result); });&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. then 메소드 완벽하게 이해하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise 객체를 배울 때는 then 메소드에 관해서만 확실히 알면 딱히 어려운 내용이 없습니다. 이번 노트에서는 Promise의 then 메소드에 관한 규칙을 제대로 깊이있게 배워봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠깐 이 코드를 보세요.&lt;/p&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;const successCallback = function () { };
const errorCallback = function () { };

fetch('https://jsonplaceholder.typicode.com/users')// Promise-A
  .then(successCallback, errorCallback);// Promise-B&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때까지 배운 내용을 바탕으로 이 코드를 해석해봅시다. 일단, 이 코드에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) fetch 메소드가 리턴하는 Promise 객체를 Promise-A 객체라고 하고,&lt;br /&gt;(2) then 메소드가 리턴하는 Promise 객체를 Promise-B 객체라고 해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 fetch 함수의 작업이 성공하는 경우와 실패하는 경우로 나누어서 생각해보겠습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fetch 함수의 작업이 성공해서 Promise-A 객체가 &lt;b&gt;fulfilled 상태&lt;/b&gt;가 된 경우 : then 메소드 안의 &quot;첫 번째&quot; 콜백인 &lt;b&gt;successCallback&lt;/b&gt;이 실행됩니다.&lt;/li&gt;
&lt;li&gt;fetch 함수의 작업이 실패해서 Promise-A 객체가 &lt;b&gt;rejected 상태&lt;/b&gt;가 된 경우 : then 메소드 안의 &quot;두 번째&quot; 콜백인 &lt;b&gt;errorCallback&lt;/b&gt;이 실행됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 여기서 중요한 점은 &lt;b&gt;Promise-B는, 실행된 successCallback 또는 errorCallback에서 무엇을 리턴하느냐&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;그 &lt;b&gt;상태&lt;/b&gt;(fulfilled or rejected)와&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과&lt;/b&gt;(작업 성공 결과 or 작업 실패 정보)가&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;이번 노트에서는 &lt;b&gt;then 메소드가 리턴한 Promise 객체가, 콜백이 리턴하는 값에 따라 어떻게 달라지는지&lt;/b&gt; 경우를 나누어서 다뤄볼 겁니다. 이전 영상에서 배운 내용도 있고, 새롭게 배우는 내용도 있으니까 집중해서 잘 읽어보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 실행된 콜백이 어떤 값을 리턴하는 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;successCallback이 실행되든, errorCallback이 실행되든, 실행된 콜백에서 어떤 값을 리턴하는 경우입니다. 이때 그 값의 종류에 따라&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Promise 객체인 경우와&lt;/li&gt;
&lt;li&gt;Promise 객체 이외의 경우,&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 2가지 경우로 다시 나눌 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) Promise 객체를 리턴하는 경우&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; response.json())
  .then((result) =&amp;gt; { console.log(result) });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 &lt;b&gt;&lt;code&gt;(response) &amp;rArr; response.json()&lt;/code&gt;&lt;/b&gt; 이 콜백은 Promise 객체를 리턴하는 코드입니다. response 객체의 json 메소드가 Promise 객체를 리턴한다는 사실은 &lt;a href=&quot;https://www.codeit.kr/learn/courses/javascript-intermediate/4370&quot;&gt;이전 노트&lt;/a&gt;에서 배웠죠? 이렇게 콜백에서 Promise 객체를 리턴하는 경우에는 그 콜백을 등록한 then 메소드가 리턴했던 Promise 객체가 &lt;b&gt;콜백이 리턴한 Promise 객체의 상태와 결과를 똑같이 따라 갖게 됩니다.&lt;/b&gt; 즉, 위 코드의 첫 번째 then 메소드가 리턴했던 Promise 객체는, response 객체의 json 메소드가 리턴한 Promise 객체가 추후에 갖게 되는 상태와 결과를 그대로 따라서 갖게 된다는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 편하게 기억하기 위해서는 그냥 콜백에서 리턴하는 Promise 객체를 then 메소드가 그대로 리턴한다고 생각하셔도 됩니다. 그럼 이제 그 다음부터는 &lt;b&gt;콜백에서 리턴한 Promise 객체로부터 다시 Promise Chain이 쭉 이어져 나간다&lt;/b&gt;고 보면 되죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) Promise 객체 이외의 값을 리턴하는 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백이 꼭 Promise 객체만을 리턴하는 것은 아니겠죠? 그냥 단순한 숫자, 문자열, 일반 객체 등을 리턴할 수도 있는데요. 이런 경우에 then 메소드가 리턴했던 Promise 객체는 &lt;b&gt;fulfilled 상태&lt;/b&gt;가 되고 &lt;b&gt;작업 성공 결과로 그 값을 갖게 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;// Internet Disconnected

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; response.json(), (error) =&amp;gt; 'Try again!')
  .then((result) =&amp;gt; { console.log(result) });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 지금 인터넷이 안 되는 상황에서 이 코드를 실행했다고 해봅시다. 그럼 fetch 함수의 작업이 실패해서 두 번째 콜백인 &lt;b&gt;&lt;code&gt;(error) &amp;rArr; 'Try again!&lt;/code&gt;&lt;/b&gt; 이 실행되겠죠? 두 번째 콜백은 &lt;b&gt;'Try again!'&lt;/b&gt;이라는 문자열을 리턴하고 있는데요. 이렇게 하면 해당 콜백을 등록한 then 메소드가 리턴했던 Promise가 fulfilled 상태가 되고, 그 작업 성공 결과로 'Try again' 문자열을 갖게 됩니다.&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;b&gt;2. 실행된 콜백이 아무 값도 리턴하지 않는 경우&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;// Internet Disconnected

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; response.json(), (error) =&amp;gt; { alert('Try again!'); })
  .then((result) =&amp;gt; { console.log(result) });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 전과 같은 상황에서 콜백이 무언가를 리턴하는 게 아니라 이 코드에서처럼 단순히 alert 함수만 실행하고 끝난다고 해봅시다. 그럼 결과적으로 이 콜백은 아무런 값도 리턴하지 않은 것과 같은데요. 자바스크립트에서는 함수가 아무것도 리턴하지 않으면 undefined를 리턴한 것으로 간주됩니다. 따라서 방금 전 &lt;b&gt;1. (2) 규칙에 따라&lt;/b&gt; then 메소드가 리턴했던 Promise 객체는 &lt;b&gt;fulfilled 상태&lt;/b&gt;가 되고, &lt;b&gt;그 작업 성공 결과로 undefined&lt;/b&gt;를 갖게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 실행된 콜백 내부에서 에러가 발생했을 때&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백이 실행되다가 에러가 발생하는 경우가 있습니다. 예를 들어&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; {
        ...
        add(1, 2);// ReferenceError 발생
        ...
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 정의하지도 않은 함수를 콜백에서 사용해서 에러가 발생하거나&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; {
        ...
        throw new Error('failed');
        ...
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 경우에 인위적으로 throw 문을 써서 에러를 발생시키는 경우도 있을 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 콜백이 실행되다가 에러가 발생한다면, then 메소드가 리턴했던 Promise 객체는 어떻게 될까요? 이 경우에는 Promise 객체가 &lt;b&gt;rejected 상태&lt;/b&gt;가 되고, 작업 실패 정보로 해당 에러 객체를 갖게 됩니다. 잠깐 아래의 코드를 개발자 도구에서 실행해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const promise = fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; { throw new Error('test'); });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;promise&lt;/b&gt; 를 입력하여 then 메소드가 리턴한 Promise 객체의 내부를 살펴보면 이렇게 생겼는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4374&amp;amp;directory=Untitled.png&amp;amp;name=Untitled.png&quot;&gt;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4374&amp;amp;directory=Untitled.png&amp;amp;name=Untitled.png&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 [[PromiseState]]는 Promise 객체의 상태를, [[PromiseResult]]는 Promise 객체의 결과(작업 성공 결과 또는 작업 실패 정보)를 나타내는 내부 슬롯입니다.(내부 슬롯이란 자바스크립트 실행 엔진에서 내부적으로 관리하는 속성이라고 생각하시면 됩니다. 지금 당장 알아야할 내용은 아니니 Promise 객체에 집중합시다)&lt;br /&gt;자세히 보면 현재 Promise 객체가 rejected 상태이고, 발생한 Error 객체를 그 작업 실패 정보로 갖고 있다는 것을 알 수 있습니다. 이렇게 콜백 실행 중에 에러가 발생하면, then 메소드가 리턴한 Promise 객체는 &lt;b&gt;rejected 상태&lt;/b&gt;가 되고, 그 &lt;b&gt;작업 실패 정보로 해당 Error 객체를 갖게 된다&lt;/b&gt;는 점, 잘 기억하세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 아무런 콜백도 실행되지 않을 때&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;moonscript&quot;&gt;&lt;code&gt;// Internet Disconnected

fetch('https://www.google.com')// Promise-1
  .then((response) =&amp;gt; response.text())// Promise-2
  .then((result) =&amp;gt; { console.log(result) }, (error) =&amp;gt; { alert(error) });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;then 메소드의 아무런 콜백도 실행되지 않는 경우가 있습니다. 지금 인터넷을 끊고 나서 위 코드를 실행했다고 합시다. 그럼 fetch 함수가 리턴한 Promise-1 객체는 rejected 상태가 되기 때문에, 첫 번째 then 메소드의 두 번재 콜백이 실행되어야 합니다. 그런데 지금 두 번째 콜백이 없죠? 이런 경우에는 아무런 콜백도 실행되지 않는데요. 이런 경우에 then 메소드가 리턴한 Promise-2 객체는 어떻게 될까요? 이런 경우에 then 메소드가 리턴했던 Promise-2 객체는, &lt;b&gt;이전 Promise 객체와 동일한 상태와 결과를 갖게 됩니다.&lt;/b&gt; 그러니까 지금 Promise-2 객체는 Promise-1 객체처럼 rejected 상태가 되고, 똑같은 작업 실패 정보를 갖게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 rejected 상태가 된 Promise-2의 then 메소드에는 이제 두 번째 콜백이 존재하기 때문에 그 두 번째 콜백이 실행됩니다. 이렇게 아무런 콜백도 실행되지 않는 경우에는 그 이전 Promise 객체의 상태와 결과가 그대로 이어진다는 사실, 잘 기억하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 이때까지 Promise 객체의 &lt;b&gt;then 메소드가 리턴한 Promise 객체의 상태가, then 메소드 안의 콜백이 리턴하는 값에 따라 무슨 상태와 결과를 갖게 되는지&lt;/b&gt; 배웠는데요. 사실 위의 내용을 이해하지 못해도, Promise 객체를 당장 사용하는 데는 문제가 없을 수도 있습니다. 하지만 나중에 Promise 객체를 사용하는 코드에서 문제가 생기거나 고난이도의 코드를 작성해야 할 때는 이런 기본적인 규칙을 모르면 내가 무엇을 잘못했는지조차 알 수 없게 됩니다. 따라서 이번에 배울 때 제대로 배우고 넘어갑시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 내용을 이해될 때까지 반복해서 읽어보세요. 그래야 다음에 나오는 내용들을 잘 이해할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. catch 메소드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;catch 메소드는 then 메소드를 약간 변형시킨 것에 불과함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;.then(undefined, (error) &amp;rArr; {console.log(error); }) 와 동일하다고 생각하면 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; response.json())
    .catch((error) =&amp;gt; { console.log(error); })
  .then((result) =&amp;gt; { console.log(result) });
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;15. catch 메소드 이해하기&lt;/h2&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;// Internet Disconnected

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; response.text())
  .catch((error) =&amp;gt; { console.log(error); })
  .then((result) =&amp;gt; { console.log(result); });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 영상에서는 다음과 같은 catch 메소드를 봤습니다. 그런데 &lt;b&gt;어떻게 fetch 함수에서 발생한 에러가 catch 메소드 안의 콜백에까지 전달될 수 있는 걸까요?&lt;/b&gt; 지금 이 코드를 이렇게 수정해볼게요.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// Internet Disconnected

fetch('https://jsonplaceholder.typicode.com/users')// Promise-A
  .then((response) =&amp;gt; response.text())// Promise-B
  .then(undefined, (error) =&amp;gt; { console.log(error); })// Promise-C
  .then((result) =&amp;gt; { console.log(result); });// Promise-D&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;catch 메소드는 사실 then 메소드의 첫 번째 인자로 undefined을 넣은 것과 같다고 했죠? 그래서 catch 메소드를 then 메소드로 변환해봤습니다. 이 코드에서 fetch 함수와 각각의 then 메소드가 리턴하는 Promise 객체를 순서대로 Promise-A, B, C, D라고 합시다. 그리고 각각의 Promise의 상태가 어떻게 변하는지 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 fetch 함수의 작업이 실패해서 Promise-A 객체가 rejected 상태가 되면, 첫 번째 then 메소드의 두 번째 콜백이 실행되어야 합니다. 하지만 지금 첫 번째 then 메소드에는 두 번째 콜백이 없기 때문에 아무 콜백도 실행되지 않는데요. 이런 경우에는 어떻게 된다고 했죠? &lt;b&gt;Promise-B 객체가 Promise-A와 똑같은 rejected 상태가 되고, 동일한 작업 실패 정보를 갖게 됩니다!&lt;/b&gt; 혹시 기억이 안 나면 &lt;a href=&quot;https://www.codeit.kr/learn/4374&quot;&gt;'then 메소드 완벽하게 이해하기' 노트&lt;/a&gt;에서 &lt;b&gt;4. 아무런 콜백도 실행되지 않을 때&lt;/b&gt; 부분을 보고 와주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 rejected 상태가 된 Promise-B에 붙은 then 메소드에는 두 번째 콜백이 있기 때문에 이 두 번째 콜백이 실행됩니다. 즉, catch 메소드의 콜백이 실행되는 거죠. 어떻게 fetch 함수의 에러가 catch 메소드의 콜백에까지 전달될 수 있는지 이제 아시겠죠? then 메소드의 작동 원리만 잘 기억하고 있다면 딱히 어려운 내용은 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그럼 보너스 문제를 하나 드릴게요. 이 코드를 실행하면 최종적으로 무엇이 출력될까요?&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// Internet Disconnected

fetch('https://jsonplaceholder.typicode.com/users')// Promise-A
  .then((response) =&amp;gt; response.text())// Promise-B
  .then(undefined, (error) =&amp;gt; { console.log(error); })// Promise-C
  .then((result) =&amp;gt; { console.log(`Quiz: ${result}`); });// Promise-D&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 전과 동일한 코드이고, 대신 마지막 console.log에 &lt;b&gt;&lt;code&gt;Quiz:&lt;/code&gt;&lt;/b&gt;라는 단어가 붙어있습니다. 이 단어 옆의 result로 무엇이 출력되는지가 문제인데요. 코드를 실행해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4378&amp;amp;directory=Untitled.png&amp;amp;name=Untitled.png&quot;&gt;https://bakey-api.codeit.kr/api/files/resource?root=static&amp;amp;seqId=4378&amp;amp;directory=Untitled.png&amp;amp;name=Untitled.png&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;undefined가 출력되네요. 왜 그런 걸까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;catch 메소드는 사실 then 메소드라고 했으니까 이것을 기억하면 이해할 수 있습니다. 지금 catch 메소드 안의 콜백이 실행되었을 때 무슨 값을 리턴했나요? 아무 값도 리턴하지 않았는데요. 이렇게 자바스크립트에서는 아무 값도 리턴하지 않은 경우에는 undefined를 리턴한 것으로 간주한다고 했었죠? 따라서 이전에 배운 것처럼 catch 메소드가 리턴한 Promise 객체는 fulfilled 상태가 되면서, undefined를 작업 성공 결과로 가지게 되는 겁니다. 그래서 그 뒤의 then 메소드의 콜백의 파라미터로 undefined가 넘어가서 undefined가 출력된 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 결국 catch 메소드도 then 메소드의 실행 원리를 정확히 알아야 잘 해석할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;16. catch 메소드는 마지막에 씁니다.&lt;/h2&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fetch('https://jsonplaceholder.typicode.com/users')
    .then((response) =&amp;gt; response.text())
    .then(result) =&amp;gt; {
        console.log(result);
        throw new Error('test');
    })
    .catch((error) =&amp;gt; {console.log(error); });&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;19. finally 메소드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항상 실행하고 싶은 callback 이 있는 경우에 사용&lt;/li&gt;
&lt;li&gt;보통 catch 메소드 바로 뒤에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;203&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3rOqc/btrjkYJj8Vw/1D0m4i7nILBwYpWheMquJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3rOqc/btrjkYJj8Vw/1D0m4i7nILBwYpWheMquJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3rOqc/btrjkYJj8Vw/1D0m4i7nILBwYpWheMquJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3rOqc%2FbtrjkYJj8Vw%2F1D0m4i7nILBwYpWheMquJk%2Fimg.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;203&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&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;22. promise 객체는 왜 등장했을까 ?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;setTimeout 함수나, addEventlistener 메소드 처럼 직접 파라미터에 콜백을 전달하는 형식을 사용하면 콜백 헬(callback hell) 이라고 하는 문제를 일으킬 수도 있기 때문&lt;/li&gt;
&lt;li&gt;여러 비동기 작업을 순차적으로 수행해야 할 때 아래처럼 복잡해짐&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fetch('https://first.com', (response) =&amp;gt; {
  // Do Something
  fetch('https://second.com', (response) =&amp;gt; {
    // Do Something
    fetch('https;//third.com', (response) =&amp;gt; {
      // Do Something
      fetch('https;//fourth.com', (response) =&amp;gt; {
        // Do Something
      });
    });
  });
});&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;fetch 함수는 Promise 객체를 리턴하기 때문에 여러 비동기 작업을 순차적으로 좀더 세밀하게 처리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;fetch('https://first.com')
  .then((response) =&amp;gt; {
    // Do Something 
    return fetch('https://second.com');
  })
  .then((response) =&amp;gt; {
    // Do Something 
    return fetch('https://third.com');
  })
  .then((response) =&amp;gt; { 
    // Do Something 
    return fetch('https://third.com');
  });&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;24. 직접 만들어보는 Promise 객체&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const p = new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; { resolve('success'); }, 2000);  // 2초 후에 promise 객체가 fullfilled 상태가 된다는 뜻
});

p.then((result) =&amp;gt; { console.log(result); }); // 작업 성공 결과가 출력됨
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const p = new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; { reject new Error('fail')); }, 2000); // 2초 후에 promise 객체가 rejected 상태가 된다는 뜻
});

p.catch((error) =&amp;gt; { console.log(error); }); // 에러 결과가 출력됨
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;25. promisify&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 영상에서는 직접 Promise 객체를 만드는 방법을 배웠습니다. 그럼 언제 이런 식으로 Promise 객체를 직접 만들게 되는 걸까요? 다양한 경우들이 있지만, &lt;b&gt;전통적인 형식의 비동기 실행 함수를 사용하는 코드를, Promise 기반의 코드로 변환하기 위해&lt;/b&gt; Promise 객체를 직접 만드는 경우가 많습니다. 각각의 예시를 통해 이게 무슨 말인지 이해해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. setTimeout 함수 예시&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 이런 wait이라는 함수가 있다고 합시다.&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;function wait(text, milliseconds) {
  setTimeout(() =&amp;gt; text, milliseconds);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wait 함수는 특정 밀리세컨즈만큼 시간이 지난 후에 text 파라미터로 전달받은 값을 리턴하는 함수입니다. 지금 보이는 setTimeout 함수는 이전에 &lt;a href=&quot;https://www.codeit.kr/learn/courses/javascript-intermediate/4366&quot;&gt;'알아야하는 비동기 실행 함수들' 노트&lt;/a&gt;에서 배웠었죠? 이 wait 함수를 Promise Chaining 코드에서 사용해볼게요.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; response.text())
  .then((result) =&amp;gt; { console.log(result); });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 이 Promise Chaining 코드에 wait 함수를 추가해볼 건데요. 이렇게 써보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function wait(text, milliseconds) {
  setTimeout(() =&amp;gt; text, milliseconds);
}

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; response.text())
  .then((result) =&amp;gt; wait(`${result} by Codeit`, 2000))// 2초 후에 리스폰스의 내용 뒤에 'by Codeit' 추가하고 리턴
  .then((result) =&amp;gt; { console.log(result); });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 코드에 두 번째 then 메소드를 추가하고, 그 안에서 wait 함수를 호출했습니다. 이렇게 쓰면 2초 후에 리스폰스의 내용 뒤에 by Codeit이라는 문구를 붙여서 출력될 것 같은데요. 정말 그렇게 되는지 확인해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 실행해보면, &lt;b&gt;리스폰스의 내용과 by Codeit이 출력되지 않았습니다. 그 대신 undefined가 출력되었는데요.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 그런 걸까요?&lt;br /&gt;그 이유는 바로 wait 함수에 있습니다.&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;function wait(text, milliseconds) {
  setTimeout(() =&amp;gt; text, milliseconds);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 wait 함수는 내부에서 &lt;b&gt;setTimeout 함수를 호출&lt;/b&gt;합니다. 그리고 &lt;b&gt;setTimeout 함수의 첫 번째 파라미터로 들어간 콜백이 2초 후에 text를 리턴&lt;/b&gt;하죠. 그런데 여기서 혼동하면 안 되는 것은 &lt;b&gt;wait 함수가&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;...
  .then((result) =&amp;gt; { return wait(`${result} by Codeit`, 2000); })
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 두 번째 then 메소드 안의 콜백에서 실행될 때,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;wait 함수는 setTimeout 함수를 실행할 뿐 아무것도 리턴하지 않는다는 사실입니다.&lt;/b&gt;&lt;br /&gt;setTimeout 함수 안의 콜백이 2초 후에 리턴하는 &lt;b&gt;text는, wait 함수의 리턴값이 아닙니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 사실에 유의해야 하는데요. wait 함수는 단지 setTimeout 함수를 실행하고 아무것도 리턴하지 않는 함수일 뿐입니다. 그리고 자바스크립트에서는 이전에 배운대로 함수에서 아무것도 리턴하지 않으면 undefined를 리턴하는 것으로 간주하기 때문에 wait 함수의 리턴값은 undefined입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 세 번째 then 메소드의 콜백으로 undefined가 넘어가고, 그래서 위 이미지에서 보이는 것처럼 undefined가 출력된 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setTimeout은 비동기 실행되는 함수인데요. &lt;b&gt;Promise Chaining 안에서 이렇게 비동기 실행되는 함수를 바로 사용하면, 나중에 실행되는 부분의 리턴값(여기서는 text)를 Promise Chain에서 사용할 수 없게 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하려면 이전 영상에서 배웠던 Promise 객체를 직접 생성하는 방법을 사용하면 됩니다. wait 함수를 이렇게 수정해볼게요.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;// function wait(text, milliseconds) {//   setTimeout(() =&amp;gt; text, milliseconds);// }function wait(text, milliseconds) {
  const p = new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; { resolve(text); }, 2000);
  });
  return p;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 wait 함수 안에서 Promise 객체를 직접 생성했고, executor 함수 안에서 setTimeout 함수를 호출했습니다. 그리고 setTimeout 함수 안의 콜백에서 resolve 함수를 호출하는데 이 때 그 아규먼트로 text를 넣었습니다. 그렇다면 Promise 객체 p는 2초 후에 fulfilled 상태가 될 것이고, 그 작업 성공 결과는 파라미터 text의 값이 될 될 것입니다. &lt;b&gt;wait 함수는 이제 Promise 객체 p를 리턴합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 이 상태에서 코드를 다시 실행해보면&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function wait(text, milliseconds) {
  const p = new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; { resolve(text); }, 2000);
  });
  return p;
}

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; response.text())
  .then((result) =&amp;gt; wait(`${result} by Codeit`, 2000))// 2초 후에 리스폰스의 내용 뒤에 'by Codeit' 추가하고 리턴
  .then((result) =&amp;gt; { console.log(result); });
&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;이번에는 약 2초 후에 리스폰스의 내용이 잘 출력되고, 리스폰스의 내용 맨 마지막에는 by Codeit이라는 문구가 잘 붙어서 출력되는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금처럼 기존의 비동기 실행 함수(여기서는 setTimeout)의 콜백이 리턴하는 값을 Promise Chain에서 사용하고 싶다면, 해당 함수를 감싸서 Promise 객체를 직접 생성하는 코드를 작성해야 합니다. 그리고 그 Promise 객체를 리턴해야 방금처럼 Promise Chain에서 해당 리턴값을 받아서 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 전통적인 형식의 비동기 실행 함수를 Promise 객체로 감싸서 그 Promise 객체를 리턴하는 형식으로 만드는 작업을 &lt;b&gt;Promisify(프로미스화하다)&lt;/b&gt;라고 하는데요. 앞으로도 이 Promisify라는 용어를 사용하겠습니다. 계속 내용을 읽어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 콜백 헬(callback hell)과 Promise&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 Promisify의 또 다른 예시를 보겠습니다. 그런데 이번에는 브라우저가 아니라 조금 다른 환경에서의 코드를 볼 건데요. 바로 Node.js라고 하는 환경입니다. 오늘날 자바스크립트가 실행되는 환경에는 웹 브라우저뿐만 아니라 Node.js라고 하는 것도 있습니다. 이 Node.js는 오늘날 자바스크립트를 서버에서도 실행할 수 있게 해주는 또 다른 '자바스크립트 실행 환경'인데요. 이 Node.js에서는 브라우저에서와는 또 다른 비동기 함수들이 제공됩니다. (Node.js가 뭔지 더 궁금하신 분들은 &lt;a href=&quot;https://www.codeit.kr/learn/courses/nodejs-backend-development/3692&quot;&gt;이 영상&lt;/a&gt;을 참고하세요.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js에는 다음과 같이 특정 파일의 내용을 읽기 위해 사용되는 readFile이라는 비동기 실행 메소드가 있습니다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fs.readFile('file1.txt', 'utf8', (error, data) =&amp;gt; {
  if (err) {
    console.log(err);
  } else {
    console.log(data);
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 fs는 readFile 메소드를 가진 객체로, 파일에 관한 기능들을 갖고 있습니다. 일단 여기서 당장 중요한 내용은 아니니까 readFile 메소드에만 집중합시다. readFile 메소드는 첫 번째 파라미터로 파일의 이름, 두 번째 파라미터로 파일 해석 기준(인코딩 기준), 세 번째 파라미터로 콜백을 받는데요. readFile 함수는 파일을 읽다가 에러가 발생하면 콜백의 첫 번째 파라미터(error)에, 해당 에러 객체를 전달하고 콜백을 실행합니다. 만약 파일을 정상적으로 다 읽었으면 콜백의 두 번째 파라미터(data)에, 읽어들인 파일 내용을 전달하고 콜백을 실행하는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 readFile 메소드도, 콜백을 파라미터에 바로 넣는 비동기 실행 함수라는 점에서 setTimeout 함수, addEventListener 메소드와 비슷합니다. 그런데 이런 형식의 함수(또는 메소드)들은 한 가지 단점이 있다고 했었죠?(&lt;a href=&quot;https://www.codeit.kr/learn/courses/javascript-intermediate/4385&quot;&gt;참고&lt;/a&gt;) 그건 바로 콜백 헬(callback hell) 문제입니다. 예를 들어, 위 코드에서 이제 &lt;b&gt;file1.txt 파일의 내용을 출력하고 나서 그 다음에 file2.txt라는 파일의 내용을 또 출력&lt;/b&gt;해야한다고 해봅시다. 그럼 코드가 이렇게 되겠죠?&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fs.readFile('file1.txt', 'utf8', (error1, data1) =&amp;gt; {
  if (error1) {
    console.log(error1);
  } else {
    console.log(data1);
    fs.readFile('file2.txt', 'utf8', (error2, data2) =&amp;gt; {
      if (error2) {
        console.log(error2);
      } else {
        console.log(data2);
      }
    });
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 코드를 쓰면 file1.txt의 내용이 출력되고, 그 다음에 file2.txt의 내용이 출력될 겁니다. 코드가 좀 복잡해졌지만 아직은 읽을만한 것 같습니다. 그런데 이제 그 다음으로 file3.txt의 내용도 출력해야 한다고 해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;fs.readFile('file1.txt', 'utf8', (error1, data1) =&amp;gt; {
  if (error1) {
    console.log(error1);
  } else {
    console.log(data1);
    fs.readFile('file2.txt', 'utf8', (error2, data2) =&amp;gt; {
      if (error2) {
        console.log(error2);
      } else {
        console.log(data2);
        fs.readFile('file3.txt', 'utf8', (error3, data3) =&amp;gt; {
          if (error3) {
            console.log(error3);
          } else {
            console.log(data3);
          }
        });
      }
    });
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드가 이렇게 됩니다. 이제 코드를 읽기 너무 어려워지지 않았나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백을 바로 파라미터에 집어넣는 전통적인 형식의 비동기 실행 함수들은 이런 문제가 있습니다. 바로 순차적으로 비동기 실행 함수들을 실행하려고 하면 콜백 안에 또 콜백이 있고, 그 안에 또 콜백이 있는 &lt;b&gt;콜백 헬(콜백 지옥, callback hell)&lt;/b&gt; 현상을 초래하게 된다는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 실무에서 개발을 하다 보면 이런 콜백 헬이 아주 큰 문제가 됩니다. 그런데 이런 함수들은 Promise 객체를 리턴하는 것도 아니고 애초에 이런 형식으로 정의되어 있기 때문에 문제를 해결하기가 어려워 보이는데요. 이 문제에 대한 대표적인 해결책이 바로 우리가 배운 Promisify입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 이 readFile 메소드를 Promisify해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;function readFile_promisified(filename) {
  const p = new Promise((resolve, reject) =&amp;gt; {
    fs.readFile(filename, 'utf8', (error, data) =&amp;gt; {
      if (error) {
        reject(error);// 에러 발생 시 -&amp;gt; rejected
      } else {
        resolve(data);// 파일 내용 읽기 완료 -&amp;gt; fulfilled
      }
    });
  });
  return p;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 readFile_promisified라는 이름의 함수를 정의했는데요. 지금 함수 안에서는 Promise 객체를 직접 생성하고 있습니다.&lt;br /&gt;그리고 Promise 객체가 생성될 때 실행되는 &lt;b&gt;executor&lt;/b&gt; 함수 안에서는 fs 객체의 readFile 메소를 호출했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 것은 작업을 수행하다가 에러가 나면 &lt;b&gt;readFile 함수의 콜백에서&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;...                         (error, data) =&amp;gt; {
  if (error) {
    reject(error);// 에러 발생 시 -&amp;gt; rejected
  } else {
    resolve(data);// 파일 내용 읽기 완료 -&amp;gt; fulfilled
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;reject 함수를 호출&lt;/b&gt;하고, 파일의 내용을 정상적으로 다 읽었을 때는 &lt;b&gt;resolve 함수를 호출&lt;/b&gt;한다는 사실입니다. 그리고 reject 함수의 파라미터에는 error 객체를, resolve 함수의 파라미터에는 파일의 내용인 data를 전달했는데요. 이 각각은, 생성된 Promise 객체의 작업 실패 정보 또는 작업 성공 결과가 되겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;readFile 메소드를 Promisify해서 만든 readFile_promisified 함수&lt;/b&gt;를 사용해서 위의 콜백 헬 코드에서 작성했던 내용을 똑같이 작성해봅시다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;readFile_promisified('file1.txt')
  .then((data) =&amp;gt; { console.log(data); return readFile_promisified('file2.txt'); })
  .then((data) =&amp;gt; { console.log(data); return readFile_promisified('file3.txt'); })
  .then((data) =&amp;gt; { console.log(data); })
  .catch((error) =&amp;gt; { console.log(error); });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;짠! 어떤가요? 코드가 훨씬 깔끔해졌죠? readFile_promisified 함수는 Promise 객체를 리턴하기 때문에 이렇게 자유롭게 Promise Chain 안에서 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 원하는 경우에는 전통적인 형식의 비동기 실행 함수를 Promisify해서 콜백 헬을 방지하고, 가독성 높은 코드를 작성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Promisify를 하면 안 되는 함수들도 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 기존의 전통적인 형식의 비동기 실행 함수도 원하는 경우에는 Promisify해서 콜백 헬을 방지할 수 있다는 것을 알게 되었습니다. 하지만 전통적인 형식의 비동기 실행 함수라고 해서 모두 Promisify해서 사용해도 되는 것은 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 비동기 실행 함수들 중에서도 &lt;b&gt;그 콜백을 한번만 실행&lt;/b&gt;하는 것들(setTimeout, readFile 등)만 Promisify해서 사용해도 되는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것들과 달리 만약 콜백을 여러 번 실행하는 함수들(setInterval, addEventListener 등)인 경우에는 이렇게 Promisify하면 안 됩니다. 왜냐하면 &lt;b&gt;Promise 객체는 한번 pending 상태에서 fulfilled 또는 rejected 상태가 되고나면 그 뒤로는 그 상태와 결과가 바뀌지 않기 때문입니다.&lt;/b&gt; 이게 무슨 말인지 다음 코드를 보고 이해해봅시다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const box = document.getElementById('test');
let count = 0;

function addEventListener_promisified(obj, eventName) {// 이런 Promisify는 하지 마세요const p = new Promise((resolve, reject) =&amp;gt; {
    obj.addEventListener(eventName, () =&amp;gt; {// addEventListener 메소드
      count += 1;
      resolve(count);
    });
  });
  return p;
}

addEventListener_promisified(box, 'click').then((eventCount) =&amp;gt; { console.log(eventCount); });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서 보이는 addEventListener_promisified 함수는 DOM 객체의 addEventListener 메소드를 Promisify한 함수인데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 Promise 객체가 생성될 때 실행되는 executor 함수 안에서는, DOM 객체에 어떤 이벤트가 발생할 때, 실행할 콜백을 등록하고 있습니다.&lt;br /&gt;특정 이벤트가 발생할 때마다 count라고 하는 변수의 값을 1씩 늘려서 resolve 함수의 파라미터로 전달해서 실행하도록 하는 내용이 들어있는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 코드를 보면,&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;addEventListener_promisified(box, 'click')
  .then((eventCount) =&amp;gt; { console.log(eventCount); });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 addEventListener_promisified 함수의 아규먼트로 DOM 객체 box와 문자열 'click'을 넣어서 box 객체가 클릭 이벤트에 반응하도록 했습니다.&lt;br /&gt;(HTML 코드는 생략된 상태입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 코드를 실행하고 box를 클릭해보면&lt;br /&gt;&lt;b&gt;처음에 1이 딱 출력되고 나서 그 다음 count 값들은 출력되지 않습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 pending 상태에 있던 Promise 객체(여기서는 p 객체)가 한번 fulfilled 상태 또는 rejected 상태가 되고 나면&lt;br /&gt;Promise 객체의 상태 및 결과가 고정되어 그 뒤로는 바뀌지 않기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 지금 위 코드에 보이는 resolve(count)라고 하는 코드가 box 버튼을 클릭할 때마다 여러 번 실행된다고 해도 p 객체가 갖고 있는 상태와 결과는 변하지 않습니다. 그래서 then 메소드 안의 콜백도 처음 클릭했을 때 딱 한번 실행되고 끝인 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 콜백이 여러 번 실행되어야하는 비동기 실행 함수인 경우에는 Promisify를 하면 안 됩니다. Promisify를 하고 싶은 경우라도, 콜백이 딱 한 번 실행되는 함수인 경우에만 해야한다는 사실, 잘 기억하세요!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;26. 이미 상태가 결정된 Promise 객체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. fulfilled 상태의 Promise 객체 만들기&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const p = Promise.resolve('success');
p.then((result) =&amp;gt; { console.log(result); }, (error) =&amp;gt; { console.log(error); });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. rejected 상태의 Promise 객체 만들기&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;const p = Promise.reject(new Error('fail'));
p.then((result) =&amp;gt; { console.log(result); }, (error) =&amp;gt; { console.log(error); });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.&amp;nbsp;어느 시점이든, 몇번이든 then 메소드를 붙여서 해당 결과를 가져올 수 있다&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const p = new Promise((resolve, reject) =&amp;gt; {
  setTimeout(() =&amp;gt; { resolve('success'); }, 2000); // 2초 후에 fulfilled 상태가 됨
});

p.then((result) =&amp;gt; { console.log(result); }); // Promise 객체가 pending 상태일 때 콜백 등록
setTimeout(() =&amp;gt; { p.then((result) =&amp;gt; { console.log(result); }); }, 5000); // Promise 객체가 fulfilled 상태가 되고 나서 콜백 등록&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;28. 여러 promise 객체를 다루는 방법&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;all 메소드&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열 안에 있는 모든 Promise 객체가 pending 상태에서 fulfilled 상태가 될 때까지 기다림.&lt;/li&gt;
&lt;li&gt;그리고 모든 Promise 객체들이 fulfilled 상태가 되면, all 메소드가 리턴했던 Promise 객체는 fulfilled 상태가 되고,&lt;br /&gt;각 Promise 객체의 작업 성공 결과들로 이루어진 배열을, 그 작업 성공 결과로 갖게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 1번 직원 정보
const p1 = fetch('https://learn.codeit.kr/api/members/1').then((res) =&amp;gt; res.json());
// 2번 직원 정보
const p2 = fetch('https://learn.codeit.kr/api/members/2').then((res) =&amp;gt; res.json());
// 3번 직원 정보
const p3 = fetch('https://learn.codeit.kr/api/members/3').then((res) =&amp;gt; res.json());

Promise
  .all([p1, p2, p3])
  .then((results) =&amp;gt; {
    console.log(results); // Array : [1번 직원 정보, 2번 직원 정보, 3번 직원 정보]
  });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&amp;nbsp;&lt;b&gt;race 메소드&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;race 메소드가 리턴한 Promise 객체는 아규먼트로 들어온 배열의 여러 Promise 객체들 중에서 가장 먼저 fulfilled 상태 또는 rejected 상태가 된 Promise 객체와 동일한 상태와 결과를 갖게 됨&lt;/li&gt;
&lt;li&gt;아래 코드에서는 p1 객체가 결과가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const p1 = new Promise((resolve, reject) =&amp;gt; {
  setTimeout(() =&amp;gt; resolve('Success'), 1000);
});
const p2 = new Promise((resolve, reject) =&amp;gt; {
  setTimeout(() =&amp;gt; reject(new Error('fail')), 2000);
});
const p3 = new Promise((resolve, reject) =&amp;gt; {
  setTimeout(() =&amp;gt; reject(new Error('fail2')), 4000);
});

Promise
  .race([p1, p2, p3])
  .then((result) =&amp;gt; {
    console.log(result); // hello 출력
  })
  .catch((value) =&amp;gt; {
    console.log(value);
  });&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;29. axios&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios 객체에서 리퀘스트를 보내는 많은 메소드들이 fetch 함수처럼 Promise 객체를 리턴함&lt;br /&gt;그래서 fetch 함수의 사용법과 비슷한 점이 많지만, axios 객체에는 fetch 함수에는 없는 다음과 같은 몇 가지 기능 및 장점들이 있음&lt;/p&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;serialization, deserialization을 자동으로 수행&lt;/li&gt;
&lt;li&gt;특정 리퀘스트에 대해 얼마나 오랫동안 리스폰스가 오지 않으면 리퀘스트를 취소할지 설정 가능(request timeout)&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;그래서 axios에서 제공하는 추가 기능이 필요한 경우에는 axios를 쓰고, 그런 기능이 필요하지 않고 별도의 패키지 다운로드를 원하지 않는 경우에는 fetch 함수를 사용&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;axios
  .get('https://jsonplaceholder.typicode.com/users')
  .then((response) =&amp;gt; {
    console.log(response);
  })
  .catch((error) =&amp;gt; {
    console.log(error);
  });&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h1&gt;4. async/await을 활용&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. async/await 란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;async : 비동기, 함수 안에 비동기적으로 실행될 부분이 있다는 것을 의미, promise 객체를 return 하는 부분이 있다는 것을 의미
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;await : ~을 기다리다. promise 객체를 return 하는 것을 기다려줌 ,fullfilled, rejected 상태가 될때까지 기다리고 다음을 실행함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;async function fetchAndPrint() {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    const result = await response.text();
    console.log(result);
}

fetchAndPrint();&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. async/await 구문의 실행 원리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;await 키워드는 async 안에서만 사용할 수 있음&lt;/li&gt;
&lt;li&gt;async 함수 안의 코드가 실행되다가 await을 만나면, 일단 await 뒤의 코드가 실행되고, 코드의 실행 흐름이 async 함수 바깥으로 나가서 나머지 코드를 다 실행함&lt;/li&gt;
&lt;li&gt;await 뒤에 있던 Promise 객체가 fulfilled 상태가 되기를 기다림. 그리고 기다리던 Promise 객체가 fulfilled 상태가 되면 await이 Promise 객체의 작업 성공 결과를 리턴&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;async function fetchAndPrint() {
    console.log(2);
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    console.log(7);
    const result = await response.text();
    console.log(result);
}

console.log(1);
fetchAndPrint();
console.log(3);
console.log(4);
console.log(5);
console.log(6);

/* 위의 함수와 같다고 할 수 있음 
function fetchAndPrint() {
  console.log(2);
  fetch('https://jsonplaceholder.typicode.com/users')
    .then((response) =&amp;gt; {
      console.log(7);
      return response.text();
    })
    .then((result) =&amp;gt; { console.log(result); });
}
*/&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 결과
1
2
3
4
5
6
undefined // console 창에서 마지막에 return 값이 없으면 undefiend 나온 것 
7
[리스폰스의 내용]&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. catch 문과 finally 문&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;catch : try문이 실패하면 실행함&lt;/li&gt;
&lt;li&gt;finally : 성공/ 실패와 상관없이 무조건 실행함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;async function fetchAndPrint() {
    try { 
        const response = await fetch('https://jsonplaceholder.typicode.com/users');
        const result = await response.text();
        console.log(result);
    } catch (error) {
        console.log(error);
    } finally {
        console.log('exit');
    }
}

fetchAndPrint();&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. async 함수는 Promise 객체를 리턴합니다.&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;async 함수는 항상 promise 객체를 return 함&lt;/li&gt;
&lt;li&gt;작업 성공 결과를 3으로 가진 promise 객체를 return 함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;async function fetchAndPrint() {
    return 3;
}

fetchAndPrint();
&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;아래 구문도 promise 객체를 return 함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;async function fetchAndPrint() {
    return fetch('https://jsonplaceholder.typicode.com/users')
                    .then((response) =&amp;gt; response.text());
}

fetchAndPrint();&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. async 함수 안의 async 함수&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;async 함수는 항상 promise 객체를 return 하는 원리를 이용해서 async 안에 async 함수를 사용해서 같은 promise 객체를 return 하도록 할 수 있음&lt;/li&gt;
&lt;li&gt;함수 앞에 await을 붙여서 사용하면 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const applyPrivacyRule = async function (users) {
    const resultWithRuleApplied = users.map((user) =&amp;gt; {
        const keys = Object.keys(user);
        const userWithoutPrivateInfo = {};
        keys.forEach((key) =&amp;gt; {
            if (key !== 'address' &amp;amp;&amp;amp; key !== 'phone') {
                userWithoutPrivateInfo[key] = user[key];
        }
    });
    return userWithoutPrivateInfo;
});

const p = new Promise((resolve, reject) =&amp;gt; {
        setTimeout(() =&amp;gt; { resolve(resultWithRuleApplied); }, 2000); // 2초 후에 fullfilled 상태가 됨 
    });
    return p;
};

async function getUsers() {
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/users');
        const result = await response.text();
        const users = JSON.parse(result);
        const resultWithPrivacyRuleApplied = await applyPrivacyRule(users);
        return resultWithPrivacyRuleApplied; 
    } catch (error) {
        console.log(error);
    } finally {
        console.log('exit');
    }
}

getUsers().then((result) =&amp;gt; { console.log(result); });
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. async를 붙이는 위치&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 1) Function Declaration
async function example1(a, b) {
  return a + b;
}

// 2-1) Function Expression(Named)
const example2_1= async function add(a, b) {
  return a + b;
};

// 2-2) Function Expression(Anonymous)
const example2_2 = async function(a, b) {
  return a + b;
};

// 3-1) Arrow Function
const example3_1 = async (a, b) =&amp;gt; {
  return a + b;
};

// 3-2) Arrow Function(shortened)
const example3_2 = async (a, b) =&amp;gt; a + b;

// 즉시 실행 함수
(async function print(sentence) {
  console.log(sentence);
  return sentence;
}('I love JavaScript!'));

(async function (a, b) {
  return a + b;
}(1, 2));

(async (a, b) =&amp;gt; {
  return a + b; 
})(1, 2);

(async (a, b) =&amp;gt; a + b)(1, 2);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. async 함수를 작성할 때 주의해야할 성능 문제(심화)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래처럼 작성하는 경우 순서대로 각 URL 에 request를 보내고, 그 response의 내용을 출력하는 함수인데, await 문이 있기 때문에 Promise 객체가 fulfilled 상태가 될때까지는 URL에 대한 작업들이 시작될 수 없음&lt;/li&gt;
&lt;li&gt;순차적인 처리를 해야하는 경우라면 아래의 코드를 사용하는게 맞겠지만, 모든 response 내용이 잘 출력되기만 하면되고, 그 순서는 상관없는 경우라면 다르게 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;qml&quot;&gt;&lt;code&gt;async function getResponses(urls) {
  for(const url of urls){
    const response = await fetch(url);
    console.log(await response.text());
  }
}&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;아래처럼 url 에 request를 보내고 response를 받는 코드를, 별도의 즉시 실행되는 async 함수로 감싸줌&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;async function fetchUrls(urls){
  for(const url of urls){
    (async () =&amp;gt; { // 추가된 부분!
      const response = await fetch(url);
      console.log(await response.text());
    })(); // 추가된 부분!
  }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Javascript</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/77</guid>
      <comments>https://minimilab.tistory.com/77#entry77comment</comments>
      <pubDate>Fri, 29 Oct 2021 18:03:05 +0900</pubDate>
    </item>
    <item>
      <title>모던 자바스크립트</title>
      <link>https://minimilab.tistory.com/76</link>
      <description>&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;HTtps-001 (3).jpg&quot; width=&quot;400&quot; height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VtLyx/btri67AI60T/i6Y5o2i5bhsyuwRjwxy1rK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VtLyx/btri67AI60T/i6Y5o2i5bhsyuwRjwxy1rK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VtLyx/btri67AI60T/i6Y5o2i5bhsyuwRjwxy1rK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVtLyx%2Fbtri67AI60T%2Fi6Y5o2i5bhsyuwRjwxy1rK%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;HTtps-001 (3).jpg&quot; width=&quot;400&quot; height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;코드잇의 모던 자바스크립트 강의를 듣고 정리한 내용입니다. 문제가 될 시 삭제하겠습니다.&lt;/blockquote&gt;
&lt;h1&gt;코드잇 모던 자바스크립트&lt;/h1&gt;
&lt;h1&gt;1. 모던 자바스크립트 이해하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현시점에서 사용하기 적합한 범위 내에서 최신 버전의 표준을 준수하는 자바스크립트&lt;br /&gt;ECMAScript의 첫 버전은 1997년에 등장했지만, 매년 새로운 버전들을 출시하진 않았음&lt;br /&gt;하지만 여섯 번째(ES6)부터는 매년 새로운 버전들이 출시되면서 ECMAScript의 버전을 부를 때 연호를 붙여 ES2015(ES6), ES2016(ES7) ****으로 부르게 되었음&lt;br /&gt;자바스크립트 개발자들 사이에서는 ES2015 이후에 매년 출시된 버전들을 통칭하기 위해서 ES2015+ 혹은 ES6+라는 용어를 사용&lt;br /&gt;ES6부터는 연호를 사용해서 ES2015, ES2016이라고도 부른다&lt;br /&gt;개발자들 사이에서는 짧고 빠르게 소통하기 위해서 ES6, ES7이라는 용어를 사용하지만, 실제로 ECMA International에서 버전을 발표할 때 표기하는 정식 명칭은 연호를 사용해서 ECMAScript 2015라고 표기한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript는 프로그래밍 언어이고, ECMAScript는 프로그래밍 언어의 표준&lt;br /&gt;ECMAScript는 JavaScript가 갖추어야 할 내용을 정리해둔 '설명서'이고, JavaScript는 ECMAScript를 준수해서 만들어낸 '결과물'&lt;br /&gt;두 번째 차이점은 JavaScript는 ECMAScript를 기반으로 하지만 ECMAScript에 정의된 내용뿐만 아니라, 다른 부가적인 기능도 있다&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 자바스크립트의 동작 원리&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 데이터 타입의 특징과 종류&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본형 (Primitive Type)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Number, String, Boolean, Null, Undefined&lt;/li&gt;
&lt;li&gt;Symbol(유일한 값을 만들때!), BigInt(엄청 큰 숫자를 다룰 때!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;참조형(Reference Type)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Object&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. Symbol과 BigInt&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;심볼(symbol)&lt;/b&gt; : 기본형 데이터 타입(primitive data type) 중 하나입니다. 심볼은 코드 내에서 유일한 값을 가진 변수 이름을 만들 때 사용&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 어떤 값과 비교해도 true가 될 수 없는 고유한 변수가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;const user = Symbol('this is a user');

user === 'this is user'; // false
user === 'user'; // false
user === 'Symbol'; // false
user === true; // false
user === false; // false
user === 123; // false
user === 0; // false
user === null; // false
user === undefined; // false&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;똑같은 설명을 붙인 심볼을만들더라도 두 값을 비교하면 false임&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const symbolA = Symbol('this is Symbol');
const symbolB = Symbol('this is Symbol');

console.log(symbolA === symbolB); // false&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;BigInt&lt;/b&gt; : BigInt는 자바스크립트에서 아주 큰 정수(Integer)를 표현하기 위해 등장한 데이터 타입입니다.&lt;/li&gt;
&lt;li&gt;자바스크립트의 숫자형 값에는 9000조 정도의 정수 표현의 한계가 존재한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이럴때 일반 정수 마지막에 알파벳 n을 붙이거나 BigInt라는 함수를 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-python&quot;&gt;console.log(9007199254740993n); // 9007199254740993
console.log(BigInt(9007199254740993)); // 9007199254740993&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. typeof 연산자&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;typeof 'Codeit'; // string
typeof Symbol(); // symbol
typeof {}; // object
typeof []; // object
typeof true; // boolean
typeof(false); // boolean
typeof(123); // number
typeof(NaN); // number
typeof(456n); // bigint
typeof(undefined); // undefined
typeof null; // object
function sayHi() {
  console.log('Hi!?');
}

typeof sayHi; // function&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 불린인 듯 불린 아닌 불린같은 값&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;False로 평가되는 값(Falsy 값) : false, null, undefined, NaN, 0, ''&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;True로 평가되는 값(Truthy 값) : 나머지 값들&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. AND와 OR의 연산 방식&lt;/h2&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;&amp;amp;&amp;amp; 연산자는 왼쪽값이 truthy 하면 오른쪽 값을 return , falsy 하면 왼쪽값을 return 함&lt;/li&gt;
&lt;li&gt;|| 연산자는 왼쪽 값이 truthy 하면 왼쪽값을 return , 왼쪽 값이 falsy 하면 오른쪽 값을 return&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;console.log('codeit' &amp;amp;&amp;amp; 'JavaScript'); // JavaScript 가 출력됨

console.log(true &amp;amp;&amp;amp; true); // true
console.log(true &amp;amp;&amp;amp; false); // false
console.log(false &amp;amp;&amp;amp; true); // false
console.log(false &amp;amp;&amp;amp; false); // false

console.log(true || true); // true
console.log(true || false); // true
console.log(false || true); // true
console.log(false || false); // false

console.log(null &amp;amp;&amp;amp; undefined); // null
console.log(0 || true); // true
console.log('0' &amp;amp;&amp;amp; NaN); // NaN
console.log({} || 123); // {}
&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;falsy 한 값이 전달되면 'Codeit' return , 전달한 값이 있을 경우에는그 값을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;function print(value) {
    const message = value || 'Codeit';
    console.log(message);
}

print();
print('JavaScript');&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;AND와 OR 연산자 사이에서 AND연산자의 우선순위가 더 높음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;console.log(true || false &amp;amp;&amp;amp; false); // true
console.log((true || false) &amp;amp;&amp;amp; false); // false

console.log('Codeit' || NaN &amp;amp;&amp;amp; false); // Codeit
console.log(('Codeit' || NaN) &amp;amp;&amp;amp; false); // false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Operator_Precedence&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Operator_Precedence&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. null 병합 연산자&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;물음표 두개(??)를 사용해서 null 혹은 undefined 값을 가려내는 연산자&lt;/li&gt;
&lt;li&gt;연산자 왼편의 값이 null이나 undefined 라면 연산자 오른편의 값이 리턴됨&lt;/li&gt;
&lt;li&gt;연산자 왼편의 값이 null이나 undefined가 아니라면 연산자 왼편의 값이 리턴됨&lt;/li&gt;
&lt;li&gt;OR 연산자(||)와 다른점은 null 병합 연산자(??)는 왼편의 값이 null이나 undefined인지 확인하고, OR 연산자는 왼편의 값이 falsy인지를 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const example1 = null ?? 'I'; // I 
const example2 = undefined ?? 'love'; // love
const example3 = 'Codeit' ?? 'JavaScript'; // Codeit

console.log(example1, example2, example3); // ?&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 변수와 스코프&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호이스팅 : var로 선언 시 선언부분만 할당 전에 끌어올려짐&lt;/li&gt;
&lt;li&gt;let, const는 변수 선언 이전에 접근할 수 없음.&lt;/li&gt;
&lt;li&gt;var 키워드는 코드블록 밖에서도 접근이 가능함, let, const 는 코드블록 안에서만 접근이 가능함&lt;/li&gt;
&lt;li&gt;var : 함수 스코프 (function scope)&lt;/li&gt;
&lt;li&gt;let : 블록 스코프 (block scope)&lt;/li&gt;
&lt;li&gt;const : 블록 스코프 (block scope)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;console.log(title); // undefined 선언이 나중에 되었지만, 위로 올라가는 현상
var title = 'codeit';
console.log(title); // codeit

// 변수와 스코프 
console.log(title);
let title;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;var x = 3;

if (x &amp;lt; 4) {
    var y = 3;
}

for (var i = 0; i &amp;lt; 5; i++) {
    console.log(i); // 0 1 2 3 4
}

console.log('x:', x); // 3
console.log('y:', y); // 3
console.log('i:', i); // 5&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 함수 다루기&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 함수를 만드는 방법&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 선언 : function 키워드를 통해서 함수를 선언하는 일반적인 방식&lt;/li&gt;
&lt;li&gt;함수 표현식 : 이 함수 선언을 변수에 할당하거나 다른 함수의 아규먼트로 활용하면서 마치 함수 선언을 값처럼 활용해서 함수를 만드는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 함수를 만드는 방법
// 함수 선언(Function Declaration)
function 함수이름 (파라미터) {
    동작
    return 리턴값
}

// 함수 표현식 (함수 선언을 값처럼 사용)
// 선언 이후에 값을 활용
const printCodeit = function () {
    console.log('Codeit!');
};
printCodeit();

const myBtn = document.querySelector('#myBtn');
myBtn.addEventListener('click', function() {
    console.log('button is clickd!');
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 이름이 있는 함수 표현식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Named Function Expression (기명 함수 표현식)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 즉시 실행함수 (IIFE)&lt;/h2&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;(function () {
  console.log('Hi!');
})();

(function (x, y) {
  consoel.log(x + y);
})(3, 5);&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;(function sayHi() {
  console.log('Hi!');
})();

sayHi(); // ReferenceError&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;(function init() {
  // 프로그램이 실행 될 때 기본적으로 동작할 코드들..
})();&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수의 리턴값을 바로 변수에 할당하고 싶을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const firstName = Young;
const lastName = Kang;

const greetingMessage = (function () {
  const fullName = `${firstName} ${lastName} `;

  return `Hi! My name is ${fullName}`;
})();&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;(function countdown(n) {
  console.log(n);
  if (n === 0) {
    console.log('End!');
  } else {
    countdown(n - 1);
  }
})(5);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 값으로서 함수&lt;/h2&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;// 값으로서 함수
function getPrintHi() {
    return function() {
        console.log('Hi!?');
    };
};

const sayHi = getPrintHi();
sayHi();

# 출력 
# Hi!?
# getPrintHi()(); 바로 호출할 수도 있음&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. Parameter&lt;/h2&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;// name='codeit' 이런식으로 사용하면, 값이 안들어왔을 때 default값으로 사용하게 된다.
function greeting(name='codeit') { 
    console.log(`Hi! My name is ${name}!`);
}

greeting('javascript');&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;function defaultTest(x, y = x+3){
    console.log(`x: ${x}`);
    console.log(`y: ${y}`);
}

defaultTest(2);

# x: 2
# y: 5&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. Arguments&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전달되는 arguments 갯수가 다양할 때 arguments 객체를 사용함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function printArguments(a,b,c){
    console.log(arguments);
    for (const arg of arguments) {
        console.log(arg);
    }
    console.log('-------------');
}

printArguments('a', 'b', 'c');
printArguments('a');
printArguments('a', 'b');
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. Rest Parameter&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ES6 이후에 나옴&lt;/li&gt;
&lt;li&gt;...args 는 배열이기때문에 배열관련 함수들을 활용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;// Rest Parameter
function printArguments(...args){
    console.log(args.splice(0,2));
    console.log('-------------');
};

printArguments('a', 'b', 'c');
printArguments('a');
printArguments('a', 'b');

function printRank(first, second, ...others) {
    console.log('코드잇 레이스 최종 결과');
    console.log(`우승: ${first}`);
    console.log(`준우승: ${second}`);
    for (const arg of others) {
        console.log(`참가자: ${args}`);
    }
}

printRank('a', 'b', 'c', 'd', 'e');&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. Arrow Function&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;rest parameter를 사용한다거나 파라미터의 기본값을 지정하는 방식들은 기존의 함수와 똑같기 때문에 기존에 사용하던 함수 선언 방식들은 대부분 화살표 함수로 변환할 수가 있음&lt;/li&gt;
&lt;li&gt;화살표 함수는 arguments 객체가 없어서 예외적으로 arguments 객체를 활용하는 함수는 화살표 함수로 변환하기가 어려움&lt;/li&gt;
&lt;li&gt;일반함수와 this를 다루는 방법이 다름&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;const getTwice = function(number) {
    return number * 2;
};

// Arrow Function
const getTwice = (number) =&amp;gt; {
    return number * 2;
};

const getTwice = number =&amp;gt; {
    return number * 2;
};

const getTwice = number =&amp;gt; number * 2;

console.log(getTwice(5));

const getCodeit = () =&amp;gt; {
    return { name: 'Codeit', };
}

const getCodeit = () =&amp;gt; ({ name: 'Codeit', });
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;const getObject = function(a, b, c) {
  return { 0: a, 1: b, 3: c };
}

const getObject = (a, b, c) =&amp;gt; ({ 0: a, 1: b, 3: c });&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. What is this ?&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// this 
const user = {
    firstName: 'Tess',
    lastName: 'Jang',
    getFullName: function() {
        return `${user.firstName} ${user.lastName}`;
    },
};

console.log(user.getFullName());
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this : 함수를 호출한 객체를 가르킨 키워드&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;function getFullName() {
    return `${this.firstName} ${this.lastName}`;
}

const user = {
    firstName: 'Tess',
    lastName: 'Jang',
    getFullName: getFullName,
};

console.log(user.getFullName());&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;메소드가 속해있는 객체의 property 가 속해있는 상황에서도 this를 사용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;const user = {
    firstName: 'Tess',
    lastName: 'Jang',
    getFullName: function () {
        return `${this.firstName} ${this.lastName}`;
    },
};

console.log(user.getFullName());&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;함수를 호출한 객체가 this에 담김&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;//this 
console.log(this);

function printThis() {
    console.log(this);
}

const myObj = {
    content: 'myObj',
    printThis: printThis,
};

const otherObj = {
    content: 'otherObj',
    printThis: printThis,
};

myObj.printThis();
otherObj.printThis();&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. 자바스크립트의 문법과 표현&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 문장과 표현식&lt;/h2&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;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-jsx&quot;&gt;  const title = 'JavaScript';
  const codeit = {
    name: 'Codeit'
  };
  const numbers = [1, 2, 3];

  typeof codeit // object
  title // JavaScript
  codeit.name // Codeit
  numbers[3] // undefined&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;자바스크립트에서 특별한 경우를 제외하면 일반적으로 표현식인 문장은 세미콜론으로, 표현식이 아닌 문장은 문장 자체의 코드 블록(중괄호)로 그 문장의 범위가 구분&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 조건을 다루는 표현식&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 조건 연산자 (Conditional operator)

if (조건) {
    // 조건이 true 일 때 동작
} else {
    // 조건이 false 일 때 동작
}

switch (값) {
    case A: 
        // 값이 A와 일치할 때 동작
        break;

    default:
        // 값과 일치하는 case가 없을 때 동작

}

// 삼항 연산자 (Ternary operator)
// 조건 ? truthy 할 때 표현식 : falsy 할 때 표현식

const CUT_OFF = 80;

function passChecker(score) {
    return score &amp;gt; CUT_OFF ? '합격!' : '불합격!';
}

console.log(passChecker(75));
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. Spread 구문&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3];

console.log(...numbers); // 1 2 3 이 출력됨(배열에서 괄호가 벗겨지고 각각 개별 값으로 펼쳐짐)
console.log(1, 2, 3);

const sumAll = (...args) =&amp;gt; {
    let sum = 0;
    for (arg of args) {
        sum += arg;
    }
        return sum;
}

console.log(sumAll(1, 2, 3, 4));

const webPublishing = ['Html', 'CSS'];
const interactiveWeb = webPublishing; // 객체값이 참조됨
const interactiveWeb = [...webPublishing, 'JavaScript']; // 배열값이 복사됨

interactiveWeb.push('JavaScript');

console.log(webPublishing);  // ['html', 'CSS', 'JavaScript']
console.log(interactiveWeb); // ['html', 'CSS', 'JavaScript']&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

const arr3 = [...arr1, ...arr2];
console.log(arr3);

const arr4 = arr1.concat(arr2);
console.log(arr4);&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;배열을 펼쳐서 각각의 arguments로 사용할 수도 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const introduce = (name, birth, job) =&amp;gt; {
    console.log(`저는 ${name}입니다.`);
    console.log(`저는 ${birth}년 생 입니다.`);
    console.log(`직업은 ${job}입니다.`);
}

const myArr = ['코드잇', 2017, '프로그래밍 강사'];
introduce(...myArr);&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;const members = ['태호', '종훈', '우재'];

const newObject = { ...members };

console.log(newObject); // { 0:'태호', 1:'종훈', 2:'우재'}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const codeit = { 
  name: 'codeit', 
};

const codeitClone = { 
  ...codeit, // spread 문법!
};

console.log(codeit); // {name: &quot;codeit&quot;}
console.log(codeitClone); // {name: &quot;codeit&quot;}

const latte = {
  esspresso: '30ml',
  milk: '150ml'
};

const cafeMocha = {
  ...latte,
  chocolate: '20ml',
}

console.log(latte); // {esspresso: &quot;30ml&quot;, milk: &quot;150ml&quot;}
console.log(cafeMocha); // {esspresso: &quot;30ml&quot;, milk: &quot;150ml&quot;, chocolate: &quot;20ml&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 모던한 프로퍼티 표기법&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;const title = 'Codeit';
const birth = 2017;
const job = '프로그래밍 강사';

const user = {
    title,
    birth,
    job,
};

console.log(user);
// {title: 'Codeit', birth: 2017, job: '프로그래밍 강사'}&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;function getFullName() {
    return `${this.firstName} ${this.lastName}`;
};

const user = {
    firstName: 'Tess';
    lastName: 'Jang';
    getFullName,
};

console.log(user.getFullName());&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;그리고 메소드를 작성할 때도 다음과 같이 function 키워드를 생략할 수가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;const user = {
    firstName: 'Tess',
    lastName: 'Jang',
    getFullName() {
        return `${this.firstName} ${this.lastName}`;
    },
};

console.log(user.getFullName());&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const propertyName = 'birth';
const getJob = () =&amp;gt; 'job';

const codeit = {
    ['topic' + 'Name']: 'Modern JavaScript',
    [getJob()]: '프로그래밍 강사',
};

console.log(codeit);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 옵셔널 체이닝&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드에서 볼 수 있는 것처럼 물음표와 마침표를 붙여 사용하는 부분이 바로 옵셔널 체이닝 연산자(?.) 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 옵셔널 체이닝 연산자 왼편의 프로퍼티 값이 undefined 또는 null 이 아니라면&lt;br /&gt;그다음 프로퍼티 값을 리턴하고 그렇지 않은 경우에는 undefined를 반환하는 문법이다.&lt;/p&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;const user1 = {
  name: 'Captain',
  cat: {
    name: 'Crew',
    breed: 'British Shorthair',
  }
}

function printCatName(user) {
  console.log(user.cat?.name);
}

/**   
// console.log(user.cat?.name); 와 같은 내용

function printCatName(user) {
  console.log((user.cat === null || user.cat === undefined) ? undefined : user.cat.name);
}
**/&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. Destructuring (구조 분해)&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const rank = ['효준', '유나', '민환', '재하'];

const macbook = rank[0];
const ipad = rank[1];
const airpods = rank[2];
const coupon = rank[3];

console.log(macbook);
console.log(ipad);
console.log(airpods);
console.log(coupon);

const [macbook, ipad, airpods, coupon] = rank; // 길이가 넘치거나 적어도 되지만, 넘치는 변수는 담기지 않음 
console.log(macbook);
console.log(ipad);
console.log(airpods);
console.log(coupon);

const rank = ['효준', '유나', '민환', '재하', '규식'];
const [macbook, ipad, airpods, ...coupon] = rank; 
console.log(coupon); // ['재하', '규식'];
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let macbook = '효준';
let ipad = '유나';

console.log('MacBook 당첨자:', macbook);
console.log('iPad 당첨자:', ipad);

let temp = macbook;  // [macbook, ipad] = [ipad, macbook];
macbook = ipad;
ipad = temp;

console.log('MacBook 당첨자:', macbook);   
console.log('iPad 당첨자:', ipad);   
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. Destructuring (구조 분해2)&lt;/h2&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;const macbook = {
    title: '맥북프로 16형',
    price: 369000,
    memory: '16GB',
};

const { title, price } = macbook;  //  변수 이름과 똑같은 프로퍼티 네임이 있으면 할당이 됨 

const { title: product, ...rest } = macbook; // title을 product로 이름을 변경함 

console.log(title);
console.log(price);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. 함수와 Destructuring&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const macbook = {
    title : '맥북 프로 16형'
    price: 3690000,
    color: 'silver',
    memory : '16GB', 
    storage : '1TB SSD 저장장치',
    display : '16형 Retina 디스플레이',
};

function printSummary({ title, color, price }) {
    console.log(`선택한 상품은 '${title}'입니다.`);
    console.log(`색상은 '${color}'입니다.`);
    console.log(`가격은 '${price}'입니다.`);
};

printSummary(macbook); 
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;// 구조 분해
const btn = document.querySelector('#btn');

btn.addEventListener('click', (event) =&amp;gt; {
    event.target.classList.toggle('checked');
});

btn.addEventListener('click', ({ target }) =&amp;gt; {
    target.classList.toggle('checked');
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;16. 에러와 에러 객체&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에러가 발생하면 에러에 대한 정보를 name과 message라는 프로퍼티로 담고 있는 에러 객체가 만들어짐
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대표적인 에러 객체는 SyntaxError, RefereceError, TypeError&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 에러와 에러 객체 
console.log('시작!');

const title = '코드잇';
console.log(title);

console.log('끝!');

const error = new TypeError('타입 에러가 발생했습니다.');
console.log(error.name); // TypeError
console.log(error.message; // 타입 에러가 발생했습니다.

throw error ; // '타입 에러가 발생했습니다.' 에러가 발생함 

throw new TypeError('타입 에러가 발생했습니다.'); // new 키워드와 에러 객체 이름을 딴 함수를 통해 에러 객체를 만들 수 있고, throw 키워드로 에러를 발생시킬 수 있습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;17. try catch 문&lt;/h2&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;// try catch 문
try {
    // 코드 
} catch (e) {
    // try에서 코드가 실행되다가 에러가 발생했을 때 동작할 코드
    console.log(e);
    console.log(e.name);
    console.log(e.message);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;20. finally 문&lt;/h2&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;try {
  // 실행할 코드
} catch (err) {
  // 에러가 발상했을 때 실행할 코드
} finally {
  // 어떤 코드를 실행할 때 에러 여부와 상관없이 항상 실행할 코드
}&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;finally 에서도 발생한 에러를 실행하고 싶다면&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;try {
  try {
    // 실행할 코드
  } catch (err) {
    // 에러가 발상했을 때 실행할 코드
  } finally {
    // 항상 실행할 코드
  }
} catch (err) {
  // finall문에서 에러가 발생했을 때 실행할 코드
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;5. 자바스크립트의 유용한 내부 기능&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 배열 메소드 1: forEach와 map&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;forEach : 배열의 반복 작업이 필요한 경우&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-jsx&quot;&gt;  const numbers = [1, 2, 3];

  numbers.forEach((element, index, array) =&amp;gt; {
    console.log(element); // 순서대로 콘솔에 1, 2, 3이 한 줄씩 출력됨.
  });&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;map : 반복작업을 통해서 새로운 배열이 필요한 경우&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-jsx&quot;&gt;  const numbers = [1, 2, 3];
  const twiceNumbers = numbers.map((element, index, array) =&amp;gt; {
    return element * 2;
  });

  console.log(twiceNumbers); // (3) [2, 4, 6]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;
// forEach와 map
const members = ['a', 'b', 'c', 'd'];

for (let member of members) {
    console.log(`${member}`);
}

members.forEach(function (member) {
    console.log(`${member}`);
});

members.forEach((member, i, arr) =&amp;gt; {
    console.log(`${i} ${member}`);
    console.log(arr);
});

// 새로운 배열의 결과 값을 return 함
members.map((member, i, arr) =&amp;gt; {
    return members[i] + member;
});&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const list = document.querySelector('.list');
const data = [{
    title: '자바스크립트 공부하기',
    isClear: true,
  }, {
    title: '쓰레기 분리수거',
    isClear: false,
  }, {
    title: '고양이 밥주기',
    isClear: true,
  }, {
    title: '독서하기',
    isClear: false,
  }, {
    title: '영어 공부하기',
    isClear: false,
  }
];

data.forEach((todo, i) =&amp;gt; {
    const    li = document.createElement('li');

    if (todo.isClear) {
        li.classList.add('item', 'done');
    } else {
        li.classList.add('item');
    }

    li.textContent = `${i + 1}. ${todo.title}`; // 5번 조건
  list.appendChild(li); // 6번 조건

});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 배열 메소드2 : filter와 find&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;filter : 항상 return 값이 배열임&lt;/li&gt;
&lt;li&gt;find : return 값이 값임, 조건을 만족하는 순간 반복이 종료됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;//filter와 find 

const devices = [
{name: 'Galaxy', brand:'Samsung'},
{name: 'MacbookPro', brand:'Apple'},
{name: 'GalaxyWatch', brand:'Samsung'},
];

const apples = devices.filter((el) =&amp;gt; el.brand === 'Apple');
console.log(apples);

const apples = devices.filter((element, index, array) =&amp;gt; {
  return element.brand === 'Apple';
});

const myLaptop = devices.find((el) =&amp;gt; el.brand === 'Gram');
console.log(myLaptop);&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const notKims = seoul.filter((name) =&amp;gt; {
    return name[0] !== '김';
});

const notKims = seoul.filter((name) =&amp;gt; name[0] !== '김');&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;const user = data.find((da) =&amp;gt; {
    if (da.userName === nameValue &amp;amp;&amp;amp; da.phoneNumber === phoneValue )
    return da
  });

const user = data.find((el) =&amp;gt; nameValue === el.userName &amp;amp;&amp;amp; phoneValue === el.phoneNumber);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 배열 메소드 3 (some과 every)&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// some: 조건을 만족하는 요소가 1개 이상 있는지
const someReturn = numbers.some((element, index, array) =&amp;gt; {
  console.log(index); // 콘솔에는 0, 1, 2, 3까지만 출력됨.
  return element &amp;gt; 5;
});

// some과 every
const numbers = [1,3,5,7,9];

// some : 조건을 만족하는 요소가 1개이상 있는지 찾으면 true return 
const someReturn = numbers.some((el) =&amp;gt; el &amp;gt; 5);

const someReturn = numbers.some((el, i) =&amp;gt; {
    console.log('some:', i);
    return el &amp;gt; 5;
});

// some: 조건을 만족하는 요소가 1개 이상 있는지
const everyReturn = numbers.every((element, index, array) =&amp;gt; {
  console.log(index); // 콘솔에는 0까지만 출력됨.
  return element &amp;gt; 5;
});

// every : 모든 요소가 조건을 만족하는지 만족하면 true return
const everyReturn = numbers.every((el) =&amp;gt; el &amp;gt; 5);

const everyReturn = numbers.every((el, i) =&amp;gt; {
    console.log('every:', i);
    return el &amp;gt; 5;
});

console.log('some:', someReturn);
console.log('every:', everyReturn);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. 이 중 스파이가 있다.&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function checkSpy(team) {
  // 여기에 코드를 작성해 주세요.
  const result = team.members.some((member) =&amp;gt; member !== '스파이');
  let message = '';

  if (result) {
    message = `[주의!] 팀 ${team.codeName} 에 이중 스파이가 있습니다!`;
  } else {
    message = `팀 ${team.codeName} 에는 이중 스파이가 없습니다.`;
  }

  console.log(message);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function checkSpy(team) {
  // 여기에 코드를 작성해 주세요.
  const result = team.members.some((member) =&amp;gt; member !== '스파이');
  const message = result
    ? `[주의!] 팀 ${team.codeName} 에 이중 스파이가 있습니다!`
    : `팀 ${team.codeName} 에는 이중 스파이가 없습니다.`;

  console.log(message);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 배열 메소드 4: reduce&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4];

numbers.reduce((acc, el, i, arr) =&amp;gt; {
    return nextAccValue;
}, initialAccValue);

const sumAll = numbers.reduce((acc, el, i) =&amp;gt; {
    console.log(`${i}번 index 요소로 콜백함수가 동작중입니다.`);
    console.log('acc:', acc);
    console.log('el:', el);
    console.log('----------------');

    return acc + el;
}, 0); // 0은 초기값

console.log('sumAll:', sumAll);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;%E1%84%8F%E1%85%A9%E1%84%83%E1%85%B3%E1%84%8B%E1%85%B5%E1%86%BA%20%E1%84%86%E1%85%A9%E1%84%83%E1%85%A5%E1%86%AB%20%E1%84%8C%E1%85%A1%E1%84%87%E1%85%A1%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%B8%E1%84%90%E1%85%B3%20fba3ea06c15044b9b20843e1db8c2131/Untitled.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. sort, reverse&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sort&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;const numbers = [1, 10, 4, 21, 36000];

// 오름차순 정렬
numbers.sort((a, b) =&amp;gt; a - b);
console.log(numbers); // (5) [1, 4, 10, 21, 36000]

// 내림차순 정렬
numbers.sort((a, b) =&amp;gt; b - a);
console.log(numbers); // (5) [36000, 21, 10, 4, 1]&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;reverse&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;const letters = ['a', 'c', 'b'];
const numbers = [421, 721, 353];

letters.reverse();
numbers.reverse();

console.log(letters); // (3) [&quot;b&quot;, &quot;c&quot;, &quot;a&quot;]
console.log(numbers); // (3) [353, 721, 421]&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. Map, Set&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;map
&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;// Map 생성
const codeit = new Map();

// set 메소드
codeit.set('title', '문자열 key');
codeit.set(2017, '숫자형 key');
codeit.set(true, '불린형 key');

// get 메소드
console.log(codeit.get(2017)); // 숫자형 key key에 해당하는 값을 얻는 메소드. key가 존재하지 않으면 undefined를 반환.
console.log(codeit.get(true)); // 불린형 key
console.log(codeit.get('title')); // 문자열 key

// has 메소드
console.log(codeit.has('title')); // true
console.log(codeit.has('name')); // false

// size 프로퍼티
console.log(codeit.size); // 3

// delete 메소드
codeit.delete(true);
console.log(codeit.get(true)); // undefined
console.log(codeit.size); // 2

// clear 메소드
codeit.clear();
console.log(codeit.get(2017)); // undefined
console.log(codeit.size); // 0&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;set
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;set은 개별 값에 바로 접근하는 방법이 없음&lt;/li&gt;
&lt;li&gt;중복값을 허용하지 않음&lt;/li&gt;
&lt;li&gt;최초에 추가된 순서를 유지하면서, 나중에 중복된 값을 추가하려고 하면 그 값은 무시하는 특징이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;// Set 생성
const members = new Set();

// add 메소드
members.add('영훈'); // Set(1) {&quot;영훈&quot;}
members.add('윤수'); // Set(2) {&quot;영훈&quot;, &quot;윤수&quot;}
members.add('동욱'); // Set(3) {&quot;영훈&quot;, &quot;윤수&quot;, &quot;동욱&quot;}
members.add('태호'); // Set(4) {&quot;영훈&quot;, &quot;윤수&quot;, &quot;동욱&quot;, &quot;태호&quot;}

// has 메소드
console.log(members.has('동욱')); // true
console.log(members.has('현승')); // false

// size 프로퍼티
console.log(members.size); // 4

// delete 메소드
members.delete('종훈'); // false
console.log(members.size); // 4
members.delete('태호'); // true
console.log(members.size); // 3

// clear 메소드
members.clear();
console.log(members.size); // 0

// Set 생성
const members = new Set();

// add 메소드
members.add('영훈'); // Set(1) {&quot;영훈&quot;}
members.add('윤수'); // Set(2) {&quot;영훈&quot;, &quot;윤수&quot;}
members.add('동욱'); // Set(3) {&quot;영훈&quot;, &quot;윤수&quot;, &quot;동욱&quot;}
members.add('태호'); // Set(4) {&quot;영훈&quot;, &quot;윤수&quot;, &quot;동욱&quot;, &quot;태호&quot;}

for (const member of members) {
  console.log(member); // 영훈, 윤수, 동욱, 태호가 순서대로 한 줄 씩 콘솔에 출력됨.
}

const numbers = [1, 3, 4, 3, 3, 3, 2, 1, 1, 1, 5, 5, 3, 2, 1, 4];
const uniqNumbers = new Set(numbers);

console.log(uniqNumbers); // Set(5) {1, 3, 4, 2, 5}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;6. 자바스크립트 모듈&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 모듈이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈은 간단하게, 자바스크립트 파일 하나라고 할 수 있습니다.&lt;br /&gt;복잡하고 많은 양의 코드를 기능에 따라 각각의 파일로 나눠 관리하면&lt;/p&gt;
&lt;ol 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;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 모듈 파일의 조건&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 파일 안에서 선언한 변수는 외부에서 자유롭게 접근할 수 없도록 막아야 한다.&lt;br /&gt;다시 말해 모듈은 파일 안에서 모듈 파일만의 독립적인 스코프를 가지고 있어야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML파일에서 자바스크립트 파일을 불러올 때 모듈 스코프를 갖게 하려면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;script 태그에 type 속성을 module이라는 값으로 지정해 주어야 함&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;모듈 스코프 : 선언한 변수나 함수가 파일 안에서만 사용 가능해야 함 

&amp;lt;body&amp;gt;
&amp;lt;script type=&quot;module&quot; src=&quot;printer.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 모듈 문법&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// printer.js
export const title = 'CodeitPrinter';

export function print(value) {
    console.log(value);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;// index.js
// 모듈 문법
import { title, print } from './printer.js';

print(title);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 이름 바꾸기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;as 키워드로 import 한 변수나 함수의 이름 변경 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;// index.js
import { title as printerTitle, print } from './printer.js';

const title = 'Codeit';
print(title);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 한꺼번에 다루기&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// index.js
// 한꺼번에 다루기

import * as printerJS from './printer.js';
import {
    title as membersTitle,
    data as membersData
} from './members.js';

console.log(printerJS.title);

const title = 'CodeitPrinter';
function print(value) {
    console.log(value);
}

export { title as printerTitle, print };
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;default export&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;default 키워드가 붙으면 한개만 내보낼 수 있음&lt;/li&gt;
&lt;li&gt;모듈 파일 내에서 딱 한번만 사용할 수 있음&lt;/li&gt;
&lt;li&gt;import 할 때도 default as 이름 이런형식으로 사용함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;export const title = 'CodeitMembers';
export const data = [
    'a', 'b', 'c'
];

export default 'codeit'; // 변수, 함수, 혹은 값을 

import {
    default as codeit // 반드시 as 키워드를 붙여주어야 사용할 수 있음
} from '.members.js';
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Javascript</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/76</guid>
      <comments>https://minimilab.tistory.com/76#entry76comment</comments>
      <pubDate>Thu, 28 Oct 2021 14:01:10 +0900</pubDate>
    </item>
    <item>
      <title>견고한 객체지향 프로그래밍</title>
      <link>https://minimilab.tistory.com/75</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (8).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kVgda/btrhB116FHW/hBsLMvwuOKvKh8MkQPruxK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kVgda/btrhB116FHW/hBsLMvwuOKvKh8MkQPruxK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kVgda/btrhB116FHW/hBsLMvwuOKvKh8MkQPruxK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkVgda%2FbtrhB116FHW%2FhBsLMvwuOKvKh8MkQPruxK%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (8).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;파이썬의 견고한 객체지향 프로그래밍 강의를 듣고 정리한 내용입니다.&lt;br /&gt;&lt;/span&gt;문제가 될 시 삭제하겠습니다.&lt;/blockquote&gt;
&lt;h1&gt;견고한 객체지향 프로그래밍&lt;/h1&gt;
&lt;h1&gt;1. 단일 책임 원칙&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 견고한 객체 지향 프로그래밍을 위한 SOLID 원칙&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 책임 원칙 (Single Responsibility Principle)&lt;/li&gt;
&lt;li&gt;개방 폐쇄 원칙 (Open-Closed Principle)&lt;/li&gt;
&lt;li&gt;리스코프 치환원칙 (Liskov Substitution Principle)&lt;/li&gt;
&lt;li&gt;인터페이스 분리 원칙 (Interface Segregation Principle)&lt;/li&gt;
&lt;li&gt;의존 관계 역전 원칙 (Dependency Inversion Principle)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 지향 프로그래밍으로 만드는 프로그램의 크기가 커질수록 SOLID 원칙을 잘 지키는 것이 중요하다.&lt;/li&gt;
&lt;li&gt;아무리 코드가 많은 프로그래밍이라도 SOLID 원칙을 잘 지키면서 작성한다면 코드의 복잡성을 최소화하고, 코드를 유지보수 하기 쉬운 상태로 유지할 수 있다.&lt;/li&gt;
&lt;li&gt;작고 간단한 프로그램을 만드는데 원칙을 모두 지키는 것은 시간 낭비일 수도 있다.&lt;/li&gt;
&lt;li&gt;각 원칙을 적용했을 때 얻는 이점을 깨닫고 코드에서 개선해야할 점, 개선하지 않으면 생길 문제들을 파악해보자&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 단일 책임 원칙(Single Responsibility Principle)과 God Object&lt;/h2&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;/li&gt;
&lt;li&gt;단일 책임 원칙은 같이 수정해야될 것 들은 묶고, 따로 수정해야될 것들은 분리하는 것&lt;/li&gt;
&lt;li&gt;책임 하나하나가 작은 크기의 클래스에 나눠있었다면&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 단일책임 원칙 적용&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;class Ship:
    def __init__(self, fuel, fuel_per_hour, supplies, num_crew):
        self.fuel_tank = FuelTank(fuel)
        self.crew_manager = CrewManager(num_crew)
        self.supply_hold = SupplyHold(supplies, self.crew_manager)
        self.engine = Engine(self.fuel_tank, fuel_per_hour) &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 단일 책임 원칙 적용3&lt;/h2&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;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 개방 폐쇄 원칙&lt;/h1&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;/li&gt;
&lt;li&gt;어떤 클래스의 코드를 수정하지 않아도 기존 기능을 확장할 수 있어야 된다&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Keyboard(ABC): 
    @abstractmethod
    def save_input(self, content: str) -&amp;gt; None:
        pass

    @abstractmethod
    def send_input(self) -&amp;gt; str:
        pass

class AppleKeyboard(Keyboard):
    def __init__(self):
        self.keyboard_input = &quot;&quot;

    def save_input(self, input):
        self.user_input = input

    def send_input(self):
        return self.keyboard_input

    def give_user_input(self):
        return self.user_input

class SamsungKeyboard(Keyboard):
    def __init__(self):
        self.user_input = &quot;&quot;

    def save_input(self, input):
        self.user_input = input

    def send_input(self):
        return self.user_input

class KeyboardManager: # 확장에 열려있음. 추상 클래스 Keyboard를 상속받는 Keyboard 클래스 이면 사용할 수 있기 때문
    def __init__(self):  # 수정에는 닫혀있음. 추상 클래스 Keyboard를 상속받는 Keyboard 클래스 이면 KeyboardManager를 수정할 필요가 없기 때문에
        self.keyboard = None

    def connect_to_keyboard(self, keyboard):
        self.keyboard = keyboard

    def get_keyboard_input(self):
        return self.keyboard.send_input()

keyboard_manager = KeyboardManager()

apple_keyboard = AppleKeyboard()
samsung_keyboard = SamsubgKeyboard()

keyboard_manager.connect_to_keyboard(apple_keyboard)
apple_keyboard.save_input(&quot;안녕하세요&quot;)
print(keyboard_manager.get_keyboard_input())

keyboard_manager.connect_to_keyboard(samsung_keyboard)
samsung_keyboard.save_input(&quot;안녕하세요&quot;)
print(keyboard_manager.get_keyboard_input())
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 리스코프 치환 원칙 이해하기&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 리스코프 치환 원칙 이해하기&lt;/h2&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;/li&gt;
&lt;li&gt;자식 클래스가 오버라이딩을 잘못하는 경우
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식 클래스가 부모 클래스의 변수의 타입을 바꾸거나 메소드의 파라미터 또는 리턴값의 타입 or 갯수를 바꾸는 경우&lt;/li&gt;
&lt;li&gt;자식 클래스가 부모 클래스의 의도와 다르게 메소드를 오버라이딩 하는 경우&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class Employee:
    &quot;&quot;&quot;직원 클래스&quot;&quot;&quot;
    company_name = &quot;코드잇 버거&quot;
    raise_percentage = 1.03

    def __init__(self, name, wage):
        self.name = name
        self._wage = wage

    def raise_pay(self):
        &quot;&quot;&quot;직원 시급을 인상하는 메소드&quot;&quot;&quot;
        self._wage *= self.raise_percentage

    @property
    def wage(self):
        return self._wage

    def __str__(self):
        &quot;&quot;&quot;직원 정보를 문자열로 리턴하는 메소드&quot;&quot;&quot;
        return Employee.company_name + &quot; 직원: &quot; + self.name

class Cashier(Employee):
    &quot;&quot;&quot;리스코프 치환 원칙을 지키지 않는 계산대 직원 클래스&quot;&quot;&quot;
    burger_price = 4000

    def __init__(self, name, wage, number_sold=0):
        super().__init__(name, wage)
        self.number_sold = number_sold

    def raise_pay(self, raise_amount): # 부모클래스에서는 self, 외에 파라미터를 받지 않았는데, 파라미터를 추가로 받았으므로 리스코프 치환원칙을 어긴 것임
        &quot;&quot;&quot;직원 시급을 인상하는 메소드&quot;&quot;&quot;
        self.wage += self.raise_amount

    @property
    def wage(self): # 부모클래스에서는 숫자를 return 하는데, 자식클래스가 str을 리턴하므로 리스코프 치환원칙을 어긴 것임
        return &quot;시급 정보를 알려줄 수 없습니다&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 행동 규약을 어기는 자식 클래스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리스코프 치환 원칙은 개발자들끼리 협력할 때 중요!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. 인터페이스 분리 원칙&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 인터페이스 분리 원칙&lt;/h2&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;/li&gt;
&lt;li&gt;지나치게 많은 추상 메소드를 가진 거대한 인터페이스 하나를, 관련된 추상 메소드들만 모여있도록 작은 크기의 인터페이스로 분리하라는 원칙 이렇게 해야 하는 이유는 지나치게 큰 인터페이스는 그걸 상속하는 클래스가 자신에게 필요하지도 않은 메소드를 굳이 오버라이딩하도록 만들기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class IMessage(ABC):
    @property
    @abstractmethod
    def content(self):
        &quot;&quot;&quot;추상 getter 메소드&quot;&quot;&quot;
        pass

    @abstractmethod
    def edit_content(self, new_content: str) -&amp;gt; None:
        &quot;&quot;&quot;작성한 메시지를 수정하는 메소드&quot;&quot;&quot;
        pass

    @abstractmethod
    def send(self, destination: str) -&amp;gt; bool:
        &quot;&quot;&quot;작성한 메시지를 전송하는 메소드&quot;&quot;&quot;
        pass

class Email(IMessage):
    def __init__(self, content, owner_email):
        &quot;&quot;&quot;이메일은 그 내용과 보낸 사람의 이메일 주소를 인스턴스 변수로 가짐&quot;&quot;&quot;
        self._content = content
        self.owner_email = owner_email

    @property
    def content(self):
        &quot;&quot;&quot;_content 변수 getter 메소드&quot;&quot;&quot;
        return self._content

    def edit_content(self, new_content):
        &quot;&quot;&quot;이메일 내용 수정 메소드&quot;&quot;&quot;
        self._content = self.owner_email + &quot;님의 메일\n&quot; + new_content

    def send(self, destination):
        &quot;&quot;&quot;이메일 전송 메소드&quot;&quot;&quot;
        print(&quot;{}에서 {}로 이메일 전송!\n내용: {}&quot;).format(self.owner_email, destination, self._content)
        return True

class TextMessage(IMessage):
    def __init__(self, content):
        &quot;&quot;&quot;문자 메시지는 그 내용을 인스턴스 변수로 가짐&quot;&quot;&quot;
        self._content = content

    @property
    def content(self):
        &quot;&quot;&quot;_content 변수 getter 메소드&quot;&quot;&quot;
        return self._content

    def edit_content(self, new_content):
        &quot;&quot;&quot;문자 메시지 내용 수정 메소드&quot;&quot;&quot;
        self._content = new_content

    def send(self, destination):
        &quot;&quot;&quot;문자 메시지 전송 메소드&quot;&quot;&quot;
        print(&quot;{}로 문자 메시지 전송!\n내용: {}&quot;).format(destination, self._content)

class TextReader:
    &quot;&quot;&quot;인스턴스의 텍스트 내용을 읽어주는 클래스&quot;&quot;&quot;
    def __init__(self):
        self.texts = []

    def add_text(self, text: IMessage):
        &quot;&quot;&quot;인스턴스 추가 메소드, 파라미터는 IMessage 인터페이스를 상속받을 것&quot;&quot;&quot;
        self.texts.append(text)

    def read_all_texts(self):
        &quot;&quot;&quot;인스턴스 안에 있는 모든 텍스트 내용 출력&quot;&quot;&quot;
        for text in self.texts:
            print(text.content)

class Memo(IMessage):
    def __init__(self, content):
        self._content = content

    @property
    def content(self):
        return self._content

    def edit_content(self, new_content):
        self._content = new_content

    def send(self, destination): # 필요 없는데 억지로 오버라이딩 함. 클래스가 사용하지 않을 메소드를 갖도록 강요하면 안된다. ( 인터페이스 분리원칙 위반 )
        print(&quot;메모는 아무 데도 보낼 수 없습니다!&quot;)
        return False

email = Email(&quot;안녕 잘지내니? 오랜만이다!&quot;, &quot;young@codeit.kr&quot;)
text_message = TextMessage(&quot;내일 시간 가능? 한 1시쯤 만나자&quot;)
memo = Memo(&quot;내일 2시까지 숙제 끝낼 것!&quot;)

text_reader = TextReader()

text_reader.add_text(email)
text_reader.add_text(text_message)
text_reader.add_text(memo)

text_reader.read_all_texts()&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 인터페이스 분리 원칙 적용&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;아래 예시에서 send메소드를 Memo 클래스가 사용하지 않기 때문에 Itext, Isendable 인터페이스로 분리해서 사용함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
from abc import ABC, abstractmethod

class Itext(ABC):
    @property
    @abstractmethod
    def content(self):
        &quot;&quot;&quot;추상 getter 메소드&quot;&quot;&quot;
        pass

    @abstractmethod
    def edit_content(self, new_content: str) -&amp;gt; None:
        &quot;&quot;&quot;작성한 메시지를 수정하는 메소드&quot;&quot;&quot;
        pass

class ISendable(ABC):
    @abstractmethod
    def send(self, destination: str) -&amp;gt; bool:
        &quot;&quot;&quot;작성한 메시지를 전송하는 메소드&quot;&quot;&quot;
        pass

class Email(Itext, ISendable):
    def __init__(self, content, owner_email):
        &quot;&quot;&quot;이메일은 그 내용과 보낸 사람의 이메일 주소를 인스턴스 변수로 가짐&quot;&quot;&quot;
        self._content = content
        self.owner_email = owner_email

    @property
    def content(self):
        &quot;&quot;&quot;_content 변수 getter 메소드&quot;&quot;&quot;
        return self._content

    def edit_content(self, new_content):
        &quot;&quot;&quot;이메일 내용 수정 메소드&quot;&quot;&quot;
        self._content = self.owner_email + &quot;님의 메일\n&quot; + new_content

    def send(self, destination):
        &quot;&quot;&quot;이메일 전송 메소드&quot;&quot;&quot;
        print(&quot;{}에서 {}로 이메일 전송!\n내용: {}&quot;).format(self.owner_email, destination, self._content)
        return True

class Memo(Itext):
    def __init__(self, content):
        self._content = content

    @property
    def content(self):
        return self._content

    def edit_content(self, new_content):
        self._content = new_content

    ~~def send(self, destination): 
        print(&quot;메모는 아무 데도 보낼 수 없습니다!&quot;)
        return False~~

class TextReader:
    &quot;&quot;&quot;인스턴스의 텍스트 내용을 읽어주는 클래스&quot;&quot;&quot;
    def __init__(self):
        self.texts = []

    def add_text(self, text: IText):
        &quot;&quot;&quot;인스턴스 추가 메소드, 파라미터는 IMessage 인터페이스를 상속받을 것&quot;&quot;&quot;
        self.texts.append(text)

    def read_all_texts(self):
        &quot;&quot;&quot;인스턴스 안에 있는 모든 텍스트 내용 출력&quot;&quot;&quot;
        for text in self.texts:
            print(text.content)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;5. 의존 관계 역전 원칙&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 의존 관계 역전 원칙&lt;/h2&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;/li&gt;
&lt;li&gt;상위 모듈인 GameCharacter 클래스가 하위 모듈인 Sword 클래스의 구현 내용에 의존하고 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Sword 클래스의 객체를 GameCharacter 클래스 함수에서 사용하고 있기 때문에, Sword 클래스의 함수가 변경되면 GameCharacter 클래스 함수명도 변경되어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1469&quot; data-origin-height=&quot;856&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxCRI7/btrhykolybl/W0QiRMifoJKqIYkdT2bFp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxCRI7/btrhykolybl/W0QiRMifoJKqIYkdT2bFp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxCRI7/btrhykolybl/W0QiRMifoJKqIYkdT2bFp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxCRI7%2Fbtrhykolybl%2FW0QiRMifoJKqIYkdT2bFp0%2Fimg.png&quot; data-origin-width=&quot;1469&quot; data-origin-height=&quot;856&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 의존 관계 역전 원칙 적용&lt;/h2&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;/li&gt;
&lt;li&gt;인스턴스를 바로 가져다가 쓴다는 말은 하위 모듈의 구체적인 내용에 상위 모듈이 의존하게 되어 하위 모듈에 변화가 있을 때마다 상위 모듈의 코드를 자주 바꿔줘야 하기 때문입니다. 이에 대한 해결책은 &lt;b&gt;추상 클래스&lt;/b&gt;로 상위 모듈과 하위 모듈 사이에 &lt;b&gt;추상화 레이어&lt;/b&gt;를 만드는 것이다. 이렇게 되면
&lt;ol 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;/li&gt;
&lt;li&gt;그럼 상위 모듈은 새로운 하위 모듈이 생겨도 기존 코드를 수정하지 않고 새 하위 모듈을 자유롭게 가져다 쓸 수 있고 유지보수하기 편해진다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Python</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/75</guid>
      <comments>https://minimilab.tistory.com/75#entry75comment</comments>
      <pubDate>Wed, 13 Oct 2021 02:07:30 +0900</pubDate>
    </item>
    <item>
      <title>객체 지향 프로그래밍의 4개의 기둥 (추상화, 캡슐화, 상속, 다형성)</title>
      <link>https://minimilab.tistory.com/74</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (7).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn1ZDl/btrhsfNeIJT/54pmlgZDaurZiAZ65XEGH1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn1ZDl/btrhsfNeIJT/54pmlgZDaurZiAZ65XEGH1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn1ZDl/btrhsfNeIJT/54pmlgZDaurZiAZ65XEGH1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn1ZDl%2FbtrhsfNeIJT%2F54pmlgZDaurZiAZ65XEGH1%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (7).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;코드잇의 객체 지향 프로그래밍의 4개의 기둥 강의를 보고 정리한 내용입니다.&lt;br /&gt;문제될 시 삭제하겠습니다.&lt;/blockquote&gt;
&lt;h1&gt;객체 지향 프로그래밍의 4개의 기둥&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. 추상화&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 추상화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상화란 ? 프로그래머들이 특정 코드를 사용할 때 필수적인 정보를 제외한 세부사항을 가리는 것&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 추상화는 이때까지 쓰고 있었다.&lt;/h2&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;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 추상화 잘하기 : 이름 잘 짓기&lt;/h2&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;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 추상화 더 잘하기 : 문서화하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문서화 (docstring) : 함수 선언 아래에 &quot;&quot;&quot; 함수에 대한 간략한 설명 &quot;&quot;&quot;&lt;/li&gt;
&lt;li&gt;help(class name) 함수를 사용하면, docstring 문서가 나옴&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;439&quot; data-origin-height=&quot;447&quot; data-filename=&quot;Untitled.png&quot; width=&quot;200&quot; height=&quot;204&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GNSov/btrhdBEKXRv/4I2mdgk2kKJkVSvTrfesP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GNSov/btrhdBEKXRv/4I2mdgk2kKJkVSvTrfesP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GNSov/btrhdBEKXRv/4I2mdgk2kKJkVSvTrfesP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGNSov%2FbtrhdBEKXRv%2F4I2mdgk2kKJkVSvTrfesP1%2Fimg.png&quot; data-origin-width=&quot;439&quot; data-origin-height=&quot;447&quot; data-filename=&quot;Untitled.png&quot; width=&quot;200&quot; height=&quot;204&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 여기서 잠깐! 파이썬의 type hinting&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;rarr; 로 return 될 값을 넣어준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class BankAccount:
    def deposit(self, amount:float) -&amp;gt; None:
        self.balance += amount &lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;2. 캡슐화&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 캡슐화의 필요성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캡슐화의 정의&lt;/p&gt;
&lt;ol 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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;__age 와 같은 변수에 get, set 메소드를 통해 접근하는 것&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;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 밖에서 접근 못하게 할 변수, 메소드 정하기&lt;/li&gt;
&lt;li&gt;변수나 메소드 이름 앞에 언더바 2개 붙이기&lt;/li&gt;
&lt;li&gt;변수에 간접 접근할 수 있게 메소드 추가하기(getter / setter / 다른 용도의 메소드)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 객체 내부를 숨기는 법&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Citizen:
    drinking_age = 19

    def __init__(self, name, age, resident_id):
        self.name = name
        self.__age = age
        self.__resident_id = resident_id

    def __authenticate(self, id_field):
        return self.__resident_id == id_field 

kusik = Citizen(&quot;amy&quot;, 21, &quot;134&quot;)
print(kusik.__age) # 클래스 밖에서 접근이 불가능하여 에러 남
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 밑주 두개(__)와 특수 메소드들&lt;/h2&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;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 객체의 메소드를 통해 변수 접근하기 1&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Citizen:
    def __init__(self, name, age, resident_id):
        self.name = name
        self.__age = age
        self.__resident_ids = resident_id

    def get_age(self):
        return self.__age

    def set_age(self, value):
        self.__age = value

young = Citizen(&quot;younghoon&quot;, 18, &quot;123&quot;)
print(young.get_age()) # 18

young.set_age(25)
print(young.get_age()) # 25&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 객체의 메소드를 통해 변수 접근하기 2&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;getter 메소드 : 변수의 값을 읽는 메소드&lt;/li&gt;
&lt;li&gt;setter 메소드 : 변수의 값을 설정하는 메소드&lt;/li&gt;
&lt;li&gt;getter / setter 메소드를 꼭 만들 필요는 없음&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-python&quot;&gt;  def authenticate(self, id_field):
      return self.__resident_id == id_field&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. 객체의 메소드를 통해 변수 접근하기 3&lt;/h2&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;class Citizen:
    def __init__(self, name, age, resident_id):
        self.name = name
        self.set_age(age)
        self.__resident_ids = resident_id

    def set_age(self, value):
        if value &amp;lt; 0:
            print(&quot;나이는 0보다 작을 수 없습니다.&quot;)
            self.__age = 0
        else:
            self.__age = value

    def get_age(self):
        return self.__age

young = Citizen(&quot;young&quot;, -10, &quot;876&quot;) # 나이는 0보다 작을 수 없습니다.
print(young.get_age())&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 여기서 잠깐!파이썬의 캡슐화&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬은 언어 차원에서 캡슐화를 지원하지 않음(java에서는 캡슐화가 완벽하게 됨)&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) &lt;b&gt;age는 _Citizen&lt;/b&gt;age 로, &lt;b&gt;resident_id는 _Citizen&lt;/b&gt;resident_id 로 변경됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. 캡슐화와 파이썬의 문화&lt;/h2&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;/li&gt;
&lt;li&gt;_ 언더바 한개로 만든 변수 / 메소드에도 접근이 가능함 ( 언더바 한개가 아무런 기능이 없음. 단지 경고 표시일 뿐임)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 데코레이터를 사용한 캡슐화&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;class Citizen:
    def __init__(self, name, age, resident_id):
        self.name = name
        self.set_age(age)
        self.__resident_ids = resident_id

    def set_age(self, value):
        if value &amp;lt; 0:
            print(&quot;나이는 0보다 작을 수 없습니다.&quot;)
            self._age = 0
        else: self._age = value

    @property
    def age(self): # _age의 getter method
        print(&quot;나이를 리턴합니다.&quot;)
        return self._age

    @age.setter
    def age(self, value):  # _age의 setter method
        print(&quot;나이를 설정합니다.&quot;)
        if value &amp;lt; 0:
            print(&quot;나이는 0보다 작을 수 없습니다.&quot;)
            self._age = 0
        else:
            self._age = value

young = Citizen(&quot;young&quot;, -10, &quot;876&quot;)
print(young.age) # @property age를 실행하라는 의미가 됨
young.age = 30
print(young.age) # @age.setter age를 실행하라는 의미가 됨


#나이는 0보다 작을 수 없습니다.
#나이를 리턴합니다.
#0
#나이를 설정합니다.
#나이를 리턴합니다.
#30&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 객체를 사용할 땐 최대한 메소드로&lt;/h2&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;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;3. 상속&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 중복되는 코드&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;833&quot; data-filename=&quot;Untitled 1.png&quot; width=&quot;500&quot; height=&quot;275&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IFhsd/btrheyOmjTH/xRUllt1zosoUbYYKNv34eK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IFhsd/btrheyOmjTH/xRUllt1zosoUbYYKNv34eK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IFhsd/btrheyOmjTH/xRUllt1zosoUbYYKNv34eK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIFhsd%2FbtrheyOmjTH%2FxRUllt1zosoUbYYKNv34eK%2Fimg.png&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;833&quot; data-filename=&quot;Untitled 1.png&quot; width=&quot;500&quot; height=&quot;275&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 상속이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속이란 ? 두 클래스 사이에 부모-자식 관계를 설정하는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 class는 부모 class의 모든 메소드와 변수를 물려 받음&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;756&quot; data-filename=&quot;Untitled 2.png&quot; width=&quot;400&quot; height=&quot;256&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7gcmE/btrhtWT7hL2/rE1sxXdv8rSLnVnEsrNrLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7gcmE/btrhtWT7hL2/rE1sxXdv8rSLnVnEsrNrLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7gcmE/btrhtWT7hL2/rE1sxXdv8rSLnVnEsrNrLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7gcmE%2FbtrhtWT7hL2%2FrE1sxXdv8rSLnVnEsrNrLk%2Fimg.png&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;756&quot; data-filename=&quot;Untitled 2.png&quot; width=&quot;400&quot; height=&quot;256&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 부모 클래스 정의하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부모 클래스 : Employee&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 클래스 : Cashier, DeliveryMan&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A는 B다 라고 말할 수 있을 때 상속관계를 설정할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산대 직원은 직원이다. 배달원은 직원이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 상속1 (부모로부터 물려받기)&lt;/h2&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;# 부모 클래스 
class Employee:
    company_name = &quot;코드잇 버거&quot;
    raise_percentage = 1.03

    def __init__(self, name, wage):
        self.name = name
        self.wage = wage

    def raise_pay(self):
        self.wage *= self.raise_percentage

    def __str__(self):
        return Employee.company_name + &quot; 직원 : &quot; + self.name

# 자식 클래스 
class Cashier(Employee): # 부모 클래스가 Employee, 자식클래스가 Cashier 로 설정됨
    pass

# 자식 클래스
class DeliveryMan(Employee): # 부모 클래스가 Employee, 자식클래스가 Cashier 로 설정됨
    pass

younghoon = DeliveryMan(&quot;강영훈&quot;, 8900)
younghoon.raise_pay()
print(younghoon.wage)  # 9167.0
print(younghoon)  # 코드잇 버거 직원: 강영훈 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 상속과 관련된 메소드와 함수들&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;01. mro 메소드&lt;/h3&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;# 04번 상속1 (부모로부터 물려받기) 코드에서 아래 mro 함수 프린트 
print(Cashier.mro())&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;Cashier 클래스가 상속하는 부모 클래스를 볼 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;[&amp;lt;class '__main__.Cashier'&amp;gt;, &amp;lt;class '__main__.Employee'&amp;gt;, &amp;lt;class 'object'&amp;gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;print(list.mro())
[&amp;lt;class 'list'&amp;gt;, &amp;lt;class 'object'&amp;gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;print(IndentationError.mro())
[&amp;lt;class 'IndentationError'&amp;gt;, &amp;lt;class 'SyntaxError'&amp;gt;, &amp;lt;class 'Exception'&amp;gt;, &amp;lt;class 'BaseException'&amp;gt;, &amp;lt;class 'object'&amp;gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;02. isinstance 함수&lt;/h3&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;isinstance(검사할 인스턴스, 기준클래스)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;young = Cashier(&quot;강영훈&quot;, 8900)

print(isinstance(young, Cashier)) # 출력: True
print(isinstance(young, DeliveryMan)) # 출력: False
print(isinstance(young, Employee)) # 출력: True , 자식클래스로 만든 인스턴스는 부모 클래스의 인스턴스이기도 하다. &lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;03. issubclass 함수&lt;/h3&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;issubclass(검사할 인스턴스, 기준되는 부모 클래스)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;print(issubclass(Cashier, Employee)) # 출력: True
print(issubclass(Cashier, object)) # 출력: True
print(issubclass(Manager, Employee)) # 출력: True
print(issubclass(Employee, list)) # 출력: False&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. 상속2 (오버라이딩)&lt;/h2&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;super 함수 : 부모클래스의 메소드를 호출할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;# 부모 클래스 
class Employee:
    company_name = &quot;코드잇 버거&quot;
    raise_percentage = 1.03

    def __init__(self, name, wage):
        self.name = name
        self.wage = wage

    def raise_pay(self):
        self.wage *= self.raise_percentage

    def __str__(self):
        return Employee.company_name + &quot; 직원 : &quot; + self.name

# 자식 클래스 
class Cashier(Employee): # 부모 클래스가 Employee에 없는 number_sold 변수를 실행함
    raise_percentage = 1.05 # 변수 오버라이딩

    def __init__(self, name, wage, number_sold):
        super().__init__(self, name, wage) # Employee.__init__(self, name, wage) 와 같음
        self.number_sold = number_sold

    def __str__(self):
        return Cashier.company_name + &quot; 계산대 직원 : &quot; + self.name

# 자식 클래스
class DeliveryMan(Employee): 
    pass

younghoon = Cashier(&quot;강영훈&quot;, 8900, 4)
print(younghoon)  # 코드잇 버거 계산대 직원 강영훈
print(younghoon.raise_percentage)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 상속3 (mro)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mro : 클래스가 상속받는 부모 클래스들이 순서대로 담김 리스트를 리턴&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Employee:
    company_name = &quot;코드잇 버거&quot;
    raise_percentage = 1.03

    def __init__(self, name, wage):
        self.name = name
        self.wage = wage

class Cashier(Employee):
    raise_percentage = 1.05

    def __init__(self, name, wage, number_sold=0):
        super().__init__(name, wage)
        self.number_sold = number_sold

print(Cashier.mro())   # [&amp;lt;class '__main__.Cashier'&amp;gt;, &amp;lt;class '__main__.Employee'&amp;gt;, &amp;lt;class 'object'&amp;gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. 상속 4 (기능 추가하기)&lt;/h2&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;class Cashier(Employee):
    raise_percentage = 1.05

    def __init__(self, name, wage, number_sold=0):
        super().__init__(name, wage)
        self.number_sold = number_sold

    def take_order(self, money_received):
        if Cashier.burger_price &amp;gt; money_received:
            print(&quot;돈이 충분하지 않습니다. 돈을 다시 계산해서 주세요!&quot;)
            return money_received
        else:
            self.number_sold += 1 
            change = money_received - Cashier.burger_price
            return change

young = Cashier(&quot;강영훈&quot;, 8900, 0)
print(young.take_order(7000))&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 상속 정리&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1454&quot; data-origin-height=&quot;885&quot; data-filename=&quot;Untitled 3.png&quot; width=&quot;400&quot; height=&quot;243&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDQuFY/btrhjtTjYCu/wZ46oVaaYKRI9KGy22Rpd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDQuFY/btrhjtTjYCu/wZ46oVaaYKRI9KGy22Rpd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDQuFY/btrhjtTjYCu/wZ46oVaaYKRI9KGy22Rpd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDQuFY%2FbtrhjtTjYCu%2FwZ46oVaaYKRI9KGy22Rpd0%2Fimg.png&quot; data-origin-width=&quot;1454&quot; data-origin-height=&quot;885&quot; data-filename=&quot;Untitled 3.png&quot; width=&quot;400&quot; height=&quot;243&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&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;12. 다중상속&lt;/h2&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Egineer:
    def __init__(self, favorite_language):
        self. favorite_language = favorite_language

    def program(self):
        print(&quot;{}으로 프로그래밍 합니다.&quot;.format(self.favorite_language))

class TennisPlayer:
    def __init__(self, tennis_level):
        self.tennis_level = tennis_level

    def play_tennis(self):
        print(&quot;{} 반에서 테니스를 칩니다. &quot;.format(self.tennis_level))

class EngineerTennisPlayer(Engineer, TennisPlayer): # Engineer, TennisPlayer 둘다로부터 변수와 메소드를 물려 받음
    def __init__(self, favorite_language, tennis_level):
      # 다중상속한 경우, super() 했을 때 어느 클래스로 상속할 것인지를 알 수 없음
        Engineer.__init__(self, favorite_language)
        TennisPlayer.__init__(self, tennis_level)

younghoon = EngineerTennisPlayer(&quot;파이썬&quot;, &quot;초급&quot;)
younghoon.program()
younghoon.play_tennis()&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. 다중 상속의 위험성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다중상속 시 동일 메소드 호출할 때 mro 로 확인했을 때 먼저 호출되는 클래스의 메소드가 호출됨&lt;/li&gt;
&lt;/ul&gt;
&lt;ol 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;/li&gt;
&lt;li&gt;사용하고 싶다면 추상클래스 여러 개를 다중 상속받는 형식으로 사용해보기&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;4. 다형성&lt;/blockquote&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;h2 data-ke-size=&quot;size26&quot;&gt;01. 클래스 다형성1&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;shapes 변수에 들어가는 Rectangle, Circle 클래스 (둘다 동일한 메소드를 가짐)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from math import pi

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height 

    def area(self):
        return self.width * self.height 

    def perimeter(self):
        return 2*self.width * 2*self.height 

    def __str__(self):
        return &quot; 밑변 {} , 높이 {}인 직사각형&quot;.format(self.width, self.height)

class Circle:
    def __init__(self, radius):
        self.radius= radius

    def area(self):
        return pi * self.radius * self.radius 

    def perimeter(self):
        return 2 * pi * self.radius

    def __str__(self):
        return &quot;반지름 {}인 원&quot;.format(self.radius)

class Paint:
    def __init__(self):
        self.shapes = []

    def add_shape(self, shape):
        self.shapes.append(shape)

    def total_area_of_shapes(self):
        &quot;&quot;&quot;그림판에 있는 모든 도형의 넓이의 합&quot;&quot;&quot;
        return sum([shape.area() for shape in self.shapes]) # 함수를 실행함

    def total_perimeter_of_shapes(shape(self):
        &quot;&quot;&quot;그림판에 있는 모든 도형의 넓이의 합&quot;&quot;&quot;
        return sum([shape.area() for shape in self.shapes])

    def __str__(self):
        res_str = &quot;그림판 안에 있는 도형들&quot;
        for shape in self.shapes:
            res_str += str(shape) + &quot;\n&quot;
        return res_str
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 클래스 다형성2&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;rectangle = Rectangle(3, 7)
circle = Circle(4)

paint_program = Paint()
paint_program.add_shape(rectangle)
paint_program.add_shape(circle)

print(paint_program.total_area_of_shapes)
print(paint_program.total_perimeter_of_shapes)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 상속없는 다형성의 한계&lt;/h2&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def add_shape(self, shape):
        &quot;&quot;&quot;그림판에 도형을 추가한다&quot;&quot;&quot;
        if isinstance(shape, Circle) or isinstance(shape, Rectangle):
            self.shapes.append(shape)
        else:
            print(&quot;넓이, 둘레를 구하는 메소드가 없는 도형은 추가할 수 없습니다!&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 상속을 활용한 다형성 1 (일반 상속)&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from math import pi

class Shape:
    &quot;&quot;&quot;도형 클래스&quot;&quot;&quot;
    def area(self):
        &quot;&quot;&quot;도형의 넓이를 리턴한다. 자식 클래스가 오버라이딩 할 것&quot;&quot;&quot;
        pass

    def perimeter(self):
        &quot;&quot;&quot;도형의 둘레를 리턴한다. 자식 클래스가 오버라이딩 할 것&quot;&quot;&quot;
        pass

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height 

    def area(self):
        return self.width * self.height 

    def perimeter(self):
        return 2*self.width * 2*self.height 

    def __str__(self):
        return &quot; 밑변 {} , 높이 {}인 직사각형&quot;.format(self.width, self.height)

class Circle(Shape):
    def __init__(self, radius):
        self.radius= radius

    def area(self):
        return pi * self.radius * self.radius 

    def perimeter(self):
        return 2 * pi * self.radius

    def __str__(self):
        return &quot;반지름 {}인 원&quot;.format(self.radius)

class Paint:
    def __init__(self):
        self.shapes = []

    def add_shape(self, shape):
        if isinstance(shape, Shape): # Shape 클래스를 Rectangle과 Circle 클래스에서 상속했기 때문에 이렇게 사용할 수 있음
            self.shapes.append(shape)
        else:
            print(&quot;넓이, 둘레를 구하느 메소드가 없는 도형은 추가할 수 없습니다.&quot;)

    def total_area_of_shapes(self):
        &quot;&quot;&quot;그림판에 있는 모든 도형의 넓이의 합&quot;&quot;&quot;
        return sum([shape.area() for shape in self.shapes]) # 함수를 실행함

    def total_perimeter_of_shapes(shape(self):
        &quot;&quot;&quot;그림판에 있는 모든 도형의 넓이의 합&quot;&quot;&quot;
        return sum([shape.area() for shape in self.shapes])

    def __str__(self):
        res_str = &quot;그림판 안에 있는 도형들&quot;
        for shape in self.shapes:
            res_str += str(shape) + &quot;\n&quot;
        return res_str
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. 상속을 활용한 다형성3 (추상클래스 개념)&lt;/h2&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;ABC : Abstract Base Class&lt;/li&gt;
&lt;li&gt;함수 선언 위에 @abstractmethod 를 붙이면 추상 클래스&lt;/li&gt;
&lt;li&gt;추상 메소드가 1개 이상 있으면 추상 클래스&lt;/li&gt;
&lt;li&gt;추상 클래스로는 인스터스를 만들 수 없음.&lt;/li&gt;
&lt;li&gt;추상메소드 (ex) area, perimeter method 는 자식 클래스에서 반드시 오버라이딩 해서 구현해야 함&lt;/li&gt;
&lt;li&gt;오버라이딩의 방향을 제시하기 위해 추상 메소드에는 type hinting을 해주는 것이 좋음&lt;/li&gt;
&lt;li&gt;@abstractmethod 를 사용하지 않으면 일반 메소드 이고, 반드시 오버라이딩 해야되는 추상 메소드와는 다르게 일반 메소드는 물려받은 그대로 사용할지, 오버라이딩 할지를 자식 클래스에서 결정함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from math import pi
from abc import ABC, abstractmethod

class Shape(ABC) -&amp;gt; float: # ABC를 상속받아 추상클래스로 만듬
    &quot;&quot;&quot;도형 클래스&quot;&quot;&quot;

    @abstractmethod # 추상메소드
    def area(self) -&amp;gt; float:
        &quot;&quot;&quot;도형의 넓이를 리턴한다. 자식 클래스가 오버라이딩 할 것&quot;&quot;&quot;
        pass

    @abstractmethod    
    def perimeter(self):
        &quot;&quot;&quot;도형의 둘레를 리턴한다. 자식 클래스가 오버라이딩 할 것&quot;&quot;&quot;
        pass&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 상속을 활용한 다형성4 (추상클래스 활용)&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class EquilateralTriangle(Shape):
    &quot;&quot;&quot;정삼각형 클래스 &quot;&quot;&quot;
    def __init__(self, side):
        self.side = side

    def area(self): # 오버라이딩
        return sqrt(3) * self.side * self.side / 4

    def perimeter(self): # 오버라이딩
        return 3 * self.side 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 추상 클래스 더 알아보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 추상 메소드의 내용으로 그냥 pass만 썼는데, 사실 아래와 같이 추상 메소드 안에 다른 내용을 써도 됨&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Shape(ABC):
    &quot;&quot;&quot;도형 클래스&quot;&quot;&quot;
    @abstractmethod
    def area(self) -&amp;gt; float:
        &quot;&quot;&quot;도형의 넓이를 리턴한다: 자식 클래스가 오버라이딩할 것&quot;&quot;&quot;
        print(&quot;도형의 넓이 계산 중!&quot;)# ---------------- 추가된 코드    @abstractmethod
    def perimeter(self) -&amp;gt; float:
        &quot;&quot;&quot;도형의 둘레를 리턴한다: 자식 클래스가 오버라이딩할 것&quot;&quot;&quot;
        pass
&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;/li&gt;
&lt;li&gt;자식 클래스에서 오버라이딩 할 때 super 함수로 미리 채워진 내용을 가져와서 재활용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class Rectangle(Shape):
    &quot;&quot;&quot;직사각형 클래스&quot;&quot;&quot;
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        &quot;&quot;&quot;직사각형의 넓이를 리턴한다&quot;&quot;&quot;
        super().area()# ---------------- 부모의 메소드를 가져다 씀return self.width * self.height

    def perimeter(self):
        &quot;&quot;&quot;직사각형의 둘레를 리턴한다&quot;&quot;&quot;
        return 2*self.width + 2*self.height

rectangle = Rectangle(3, 4)
print(rectangle.area())# 출력: 도형의 넓이 계산 중! 12&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 추상 클래스 다중 상속 받기&lt;/h2&gt;
&lt;ol 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;/li&gt;
&lt;li&gt;다중 상속받는 부모 추상 클래스들 간에 이름이 겹치는 일반 메소드가 있으면 일반 클래스를 다중 상속받을 때와 동일한 문제가 생길 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 함수/메소드 다형성&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;def print_name(first_name, email=&quot;&quot;):&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;None : 아무값도 없다. 함수 호출 시 어떤 파라미터에 값을 전달하지 않은 경우&lt;/li&gt;
&lt;li&gt;갯수가 정해지지 않은 파라미터 *변수명으로 넣어줌
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;*변수명 tuple에 담겨서 전달됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;def print_message(message, *numbers):
    print(message)
    return sum(numbers)

print(print_message(&quot;test&quot;, 7,3,5)
print(print_message(7,3,5, message=&quot;test&quot;)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/74</guid>
      <comments>https://minimilab.tistory.com/74#entry74comment</comments>
      <pubDate>Mon, 11 Oct 2021 23:00:06 +0900</pubDate>
    </item>
    <item>
      <title>객체지향 프로그래밍이란?</title>
      <link>https://minimilab.tistory.com/73</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (6).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3k10q/btrhqKsTP7E/jYs6ukKS5m9b9jEykTzSWk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3k10q/btrhqKsTP7E/jYs6ukKS5m9b9jEykTzSWk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3k10q/btrhqKsTP7E/jYs6ukKS5m9b9jEykTzSWk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3k10q%2FbtrhqKsTP7E%2FjYs6ukKS5m9b9jEykTzSWk%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (6).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;코드잇의 객체지향 프로그래밍이란? 강의를 보고 정리한 내용입니다.&lt;br /&gt;&lt;/span&gt;문제가 될 시 삭제하겠습니다.&lt;/blockquote&gt;
&lt;h1&gt;객체 지향 프로그래밍이란?&lt;/h1&gt;
&lt;h1&gt;1. 객체 지향 프로그래밍&lt;/h1&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: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램에 어떤 객체들이 필요할지 정한다.&lt;/li&gt;
&lt;li&gt;객체들의 속성과 행동을 정한다.&lt;/li&gt;
&lt;li&gt;객체들이 서로 어떻게 소통할지 정한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 클래스와 인스턴스&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스(속성과 행동을 가진 틀)로 객체(인스턴스)를 만든다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 인스턴스 변수&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class User: # 클래스
    pass

user1 = User() # 객체 생성

user1.name = '김이름' # 인스턴스 변수 
user1.email = '김이메일'
user1.password = '김비번'&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 인스턴스 메소드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메소드의 종류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인스턴스 메소드&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; start=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 메소드&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; start=&quot;3&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 메소드&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class User:
    def say_hello(some_user):
        print('안녕하세요! 저는 {} 입니다.'format(some_user.name))

user1 = User()
user1.name = &quot;김미니미&quot;

User.say_hello(user1)
#  안녕하세요! 저는 김미니미 입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 인스턴스 메소드의 특별한 규칙&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인스턴스 메소드의 첫번째 파라미터를 self 로 쓰도록 함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class User:
    def say_hello(self):
        print(&quot;안녕하세요&quot;)

    def login(self, my_email, my_password):
        if (self.email == my_email and self.password == my_password):
            print(&quot;로그인 성공&quot;)
        else:
            print(&quot;로그인 실패, 없는 아이디이거나 잘못된 비밀번호 입니다.&quot;)

user1 = User()
user1.name = &quot;김대위&quot;
user1.email = &quot;captain@codeit.kr&quot;
user1.password = &quot;12345&quot;

user1.login(&quot;captain@codeit.kr&quot;, &quot;12345&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. __init__ 메소드&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class User:
    def __init__(self, name, email, password):
        self.name = name
        self.email = email
        self.password = password

user1 = User(&quot;young&quot;, &quot;young@codeit.kr&quot;, &quot;12345&quot;) # 인스턴스 변수 초깃값 설정
print(user1.name)
print(user1.email)
print(user1.password)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. str 메소드&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class User:
    def __init__(self, name, email, pw):
        self.name = name
        self.email = email
        self.pw = pw

    def __str__(self): # print 로 출력할 때 자동으로 호출됨
        return &quot;사용자 : {}, 이메일: {}&quot;.format(self.name, self.email)

user1 = User(&quot;김하이&quot;, &quot;sldkfj@naver.com&quot;, &quot;1234&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 클래스 변수 1&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;class User:
    count = 0

    def __init__(self, name, email, pw):
        self.name = name
        self.email = email
        self.pw = pw
        User.count += 1     # 클래스 변수가 생성될 때마다 count 1씩 늘리기


user1 = User(&quot;김하이&quot;, &quot;sldkfj@naver.com&quot;, &quot;1234&quot;)
print(User.count) # 1&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. 클래스 변수 2&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;class User:
    count = 0

    def __init__(self, name, email, pw):
        self.name = name
        self.email = email
        self.pw = pw
        User.count += 1

user1 = User(&quot;김하이&quot;, &quot;sldkfj@naver.com&quot;, &quot;1234&quot;)
user2 = User(&quot;김하이2&quot;, &quot;sldkfj@naver.com&quot;, &quot;1234&quot;)
user3 = User(&quot;김하이3&quot;, &quot;sldkfj@naver.com&quot;, &quot;1234&quot;)

User.count = 5

print(User.count) # 5
print(user1.count) # 5
print(user2.count) # 5
print(user3.count) # 5&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. 데코레이터 1&lt;/h2&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;def print_hello():
    print(&quot;안녕하세요&quot;)

def add_print_to(original): # 1
    def wrapper():
        print('함수시작') # 3
        original() # 4
        print('함수 끝') # 5
    return wrapper # 2

add_print_to(print_hello)

#함수 시작
#안녕하세요!
#함수 끝

print_hello = add_print_to(print_hello)
print_hello()&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. 데코레이터 2&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def add_print_to(original): # 1
    def wrapper():
        print('함수시작') # 3
        original() # 4
        print('함수 끝') # 5
    return wrapper # 1

@add_print_to
def print_hello():
    print(&quot;안녕하세요&quot;)

print_hello()
#함수 시작
#안녕하세요!
#함수 끝
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;15. 클래스 메소드1&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@classmethod로 선언하고, 클래스 메소드의 첫번째 파라미터 이름은 꼭 cls 로 쓰기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class User:
    count = 0

    def __init__(self, name, email, pw):
        self.name = name
        self.email = email
        self.pw = pw
        User.count += 1

    def say_hello(self):
        print(&quot;안녕하세요 저는 {} 입니다&quot;.format(self.name))

    def __str__(self):
        print(&quot;이름 : {}, 이메일 : {}&quot;.format(self.name, self.email))

    @classmethod
    def number_of_users(cls):
        print(&quot;총 유저수는 : {} 입니다.&quot;.format(cls.count))


user1 = User(&quot;김하이&quot;, &quot;sldkfj@naver.com&quot;, &quot;1234&quot;)
user2 = User(&quot;김하이&quot;, &quot;sldkfj@naver.com&quot;, &quot;1234&quot;)
user3 = User(&quot;김하이&quot;, &quot;sldkfj@naver.com&quot;, &quot;1234&quot;)

User.number_of_users()
&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;User.say_hello(user1) # 인스턴스 자신이 첫 번째 파라미터로 자동 전달
user1.say_hello()&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;# 아래 두가지 방법 모두 첫번째 파라미터로 클래스 자동 전달
# @classmethod 가 사용되었기 때문
User.number_of_users()
user1.number_of_users()&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;16. 클래스 메소드 2&lt;/h2&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;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;18. 정적 메소드&lt;/h2&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;정적 메소드는 메소드 정의 위에 @staticmethod 데코레이터를 표시해야 함&lt;/li&gt;
&lt;li&gt;정적 메소드는 인스턴스 메소드의 self, 클래스 메소드의 cls 같은 자동으로 전달되는 메소드가 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;@staticmethod
def is_valid_email(email_address):
    return &quot;@&quot; in email_address

print(User.is_valid_email(&quot;taehosung&quot;))
print(user1.is_valid_email(&quot;taehosung&quot;))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/73</guid>
      <comments>https://minimilab.tistory.com/73#entry73comment</comments>
      <pubDate>Mon, 11 Oct 2021 22:54:36 +0900</pubDate>
    </item>
    <item>
      <title>Python 모듈과 패키지</title>
      <link>https://minimilab.tistory.com/72</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (5).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ9YHg/btrhjsyNnr7/EQPppvAYXaTSnkAHhFenCK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ9YHg/btrhjsyNnr7/EQPppvAYXaTSnkAHhFenCK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ9YHg/btrhjsyNnr7/EQPppvAYXaTSnkAHhFenCK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ9YHg%2FbtrhjsyNnr7%2FEQPppvAYXaTSnkAHhFenCK%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (5).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드잇의 파이썬 모듈과 패키지 강의를 듣고 정리한 내용입니다.&lt;br /&gt;문제가 될 시 삭제하겠습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;파이썬 모듈과 패키지&lt;/h1&gt;
&lt;h1&gt;1. 모듈&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 모듈이란 ?&lt;/h2&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;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 모듈 사용하기&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# area.py
def circle(radius):
    return 3.14 * radius * radius

def square(radius):
    return 3.14 * radius * radius&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;a href=&quot;http://area.py&quot;&gt;area.py&lt;/a&gt; 와 run.py가 같은 폴더 안에 위치할 때 아래와 같이 import 파일명으로 모듈을 불러와서 함수를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# run.py
import area

print(area.circle(2))
print(area.square(9))
print(area.PI)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 모듈을 가져오는 여러가지 방법들&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 특정 함수만 가져올 때 : area 모듈에서 circle 함수를 가져와라
from area import circle, square 
print(circle(2))

# area 모듈을 ar로 사용하겠다
import area as ar 
print(ar.circle(2))

# area 모듈의 모든 함수를 가져온다. 하지만 모듈에서 필요한 함수만 가져오는 것을 추천한다.
from area import *&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 현재 파일에서 사용 가능한 기능은?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;dir 함수로 현재 파일에서 사용할 수 있는 함수를 알 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import area
print(dir(())
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'area']

print(dir(area))
['PI', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'circle', 'square']&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;from area import circle, square
print(dir())

['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'area', 'circle', 'square']&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. 네임스페이스&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;네임스페이스 : 파일에서 정의된 모든 이름

# 똑같은 이름의 함수가 나중에 정의된 것이 있으면 나중에 정의된 함수가 쓰임
from area import circle, square

def square(length):
    return 4 * length

print(dir())
print(square(3)) # 12

# 모듈에서 가져오는 함수 이름을 바꿔줄 수 있음
from area import circle, square as sq
print(square(3))
print(sq(3))&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 스탠다드 라이브러리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;int, float, string 같은 자료형&lt;/li&gt;
&lt;li&gt;print, dir 같은 내장 함수&lt;/li&gt;
&lt;li&gt;유용한 기능을 제공하는 모듈들&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. 모듈 검색 경로&lt;/h2&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;import sys

print(sys.path) # 파이썬이 모듈을 찾기 위해 검색하는 경로가 나옴 &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;sys.path 에 경로를 추가해줄 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;import sys
sys.path.append('/Users/codeit/Desktop')# macOS
sys.path.append('C:\\Users\\codeit\\Desktop')# Windows&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;모듈을 import 하면 모듈안에 있는 모든 것이 실행됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;17. &lt;b&gt;name&lt;/b&gt; 특수변수&lt;/h2&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;__name__  을 다른 곳에서 불러와서 사용하면 불러온 파일의 모듈명이 나옴 
파일을 직접 실행하면 __main__ 으로 결과 값이 나옴
그래서 if __name__ == __main__ : true 이면 파일을 직접 실행했다는 의미&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;20. main 함수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java나 c, c++ 같은 언어들에서는 어떤 파일을 실행하기보다 파일 안에 있는 main() 이라는 함수를 실행한다.&lt;br /&gt;main 함수는 말 그대로 주요 함수로서 프로그램을 작동시키는 코드를 담고 있다.&lt;br /&gt;파이썬에서는 파일 실행 시 모든 코드가 처음부터 끝까지 실행되지만, main() 함수를 사용하면 가독성이 올라가기 때문에,&lt;br /&gt;아래와 같이 main() 함수를 사용하는 것을 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;run.py&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import area

# 면적 계산기 프로그램
def main():
        x = float(input('원의 지름을 입력해 주세요: '))
        print('지름이 {}인 원의 면적은 {}입니다.\n'.format(x, area.circle(x)))

        y = float(input('정사각형의 변의 길이를 입력해 주세요: '))
        print('변의 길이가 {}인 정사각형의 면적은 {}입니다.'.format(y, area.square(y)))

if __name__ == '__main__':
    main()&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;2. 패키지&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 패키지란?&lt;/h2&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;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 패키지 만들기&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 폴더 안에 Directory 를 만들고, 해당 Directory 에 모듈들을 넣기&lt;/li&gt;
&lt;li&gt;폴더 안에 &lt;b&gt;&lt;code&gt;__init__&lt;/code&gt;&lt;/b&gt;.py 라는 파일을 만들기&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 패키지 사용하기&lt;/h2&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;shapes/
    __init__.py
    area.py
    volume.py
run.py&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;import shapes.volume 
print(shapes.volume.cube(3))

import shapes.volume as vol
print(vol.cube(3))

from shapes.area import square
print(square(3))

# from shapes import volume == import shapes.volume

import shapes
print(shapes.area.circle(2))&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. __init__ 파일이란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;python 3.3 ver 이전에는 init 파일 필수 였음. python 3.4 이후에는 init 파일 필수 아님&lt;/li&gt;
&lt;li&gt;패키지를 불러올 때 무조건 init 파일이 먼저 실행됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. __init__ 파일에서 모듈 임포트하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;__init__ 파일에서 정의해두고, 패지키 모듈을 부르면 __init__ 파일을 먼저 읽기 때문에, 가져와서 사용할수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;shapes/
    __init__.py
    area.py
    volume.py
run.py&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;__init__.py&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;PI = 3.14&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;volume.py&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;from shapes import PI&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;run.py
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래와 같이 패키지 밖에서도 패키지 내의 init 파일에 선언한 내용을 가져올 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;# PI 직접 임포트
from shapes import PI

# 패키지 임포트 후 shapes. 으로 접근
import shapes
shapes.PI&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. all 특수 변수&lt;/h2&gt;
&lt;h1&gt;&lt;b&gt;&lt;code&gt;import *&lt;/code&gt;&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈을 임포트할 때 &lt;b&gt;&lt;code&gt;from &amp;lt;module&amp;gt; import *&lt;/code&gt;&lt;/b&gt;를 하면 모듈의 모든 내용이 임포트됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 모듈 대신 패키지에 &lt;b&gt;&lt;code&gt;from &amp;lt;package&amp;gt; import *&lt;/code&gt;&lt;/b&gt;를 하면 패키지 안에 있는 게 아무것도 임포트되지 않습니다.&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;&lt;code&gt;__all__&lt;/code&gt; 특수 변수&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;__all__&lt;/code&gt; 특수 변수는 우리가 &lt;code&gt;import *&lt;/code&gt;를 했을 때 임포트 대상에서 어떤 것들을 가져와야 하는지를 정해 주는 변수입니다&lt;/b&gt;. 임포트 대상에서 내용 전체를 가져오라고 했을 때 '전체'가 무엇인지 정의해 주는 거죠. &lt;b&gt;&lt;code&gt;__all__&lt;/code&gt;&lt;/b&gt; 은 모듈에도 적용되고 패키지에도 적용됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;code&gt;__all__&lt;/code&gt; 과 모듈&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈의 &lt;b&gt;&lt;code&gt;__all__&lt;/code&gt;&lt;/b&gt; 은 모듈에 해당하는 파일에서 정의합니다. 예를 들어 area.py에 아래와 같은 코드를 추가해 주면:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shapes/area.py&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# __all__ 정의
__all__ = ['circle', 'square']

PI = 3.14

# 원의 면적을 구해 주는 함수def circle(radius):
    return PI * radius * radius

# 정사각형의 면적을 구해 주는 함수def square(length):
    return length * length&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;from shapes.area import *&lt;/code&gt;&lt;/b&gt;를 했을 때 &lt;b&gt;&lt;code&gt;area&lt;/code&gt;&lt;/b&gt; 모듈의 모든 내용이 임포트되지 않고 &lt;b&gt;&lt;code&gt;circle&lt;/code&gt;&lt;/b&gt; 과 &lt;b&gt;&lt;code&gt;square&lt;/code&gt;&lt;/b&gt; 함수만 임포트됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;code&gt;__all__&lt;/code&gt; 과 패키지&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지의 &lt;b&gt;&lt;code&gt;__all__&lt;/code&gt;&lt;/b&gt; 은 패키지에 해당하는 init 파일에서 정의합니다. 예를 들어 &lt;b&gt;&lt;code&gt;shapes&lt;/code&gt;&lt;/b&gt; 패키지의 init 파일에 아래와 같은 코드를 추가해 주면:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shapes/__&lt;b&gt;init__&lt;/b&gt;.py&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;# __all__ 정의
__all__ = ['area', 'volume']&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;&lt;code&gt;from shapes import *&lt;/code&gt;&lt;/b&gt;를 하면 &lt;b&gt;&lt;code&gt;area&lt;/code&gt;&lt;/b&gt; 모듈과 &lt;b&gt;&lt;code&gt;volume&lt;/code&gt;&lt;/b&gt; 모듈이 임포트됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;__all__&lt;/code&gt;&lt;/b&gt;을 사용하면 패키지나 모듈에 &lt;b&gt;&lt;code&gt;import *&lt;/code&gt;&lt;/b&gt;를 했을 때 어떤 것들이 임포트되는지를 제어할 수 있습니다. 그래도 여전히 &lt;b&gt;&lt;code&gt;import *&lt;/code&gt;&lt;/b&gt; 만 봐서는 정확히 어떤 것들이 임포트되는지를 알 수 없기 때문에 &lt;b&gt;&lt;code&gt;import *&lt;/code&gt;&lt;/b&gt;는 프로그램에서 정의되는 이름들, 즉 네임스페이스를 완벽히 이해하고 있을 때만 사용하는 것을 추천드립니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. init 파일과 all 사용해보기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 패키지에서 init 파일을 정의할 때는 from 패키지네임.모듈이름 import * 로 정의할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패키지 외부에서 import 패키지명으로 불러왔을 때, init 에서 불러온 함수나 변수를 사용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. 서브패키지&lt;/h2&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;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. 서브패키지 사용하기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;143&quot; data-origin-height=&quot;206&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgRiaS/btrhhTDlQ3E/xo28J5o13GPyQhEUhMJAo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgRiaS/btrhhTDlQ3E/xo28J5o13GPyQhEUhMJAo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgRiaS/btrhhTDlQ3E/xo28J5o13GPyQhEUhMJAo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgRiaS%2FbtrhhTDlQ3E%2Fxo28J5o13GPyQhEUhMJAo1%2Fimg.png&quot; data-origin-width=&quot;143&quot; data-origin-height=&quot;206&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;code&gt;import ...&lt;/code&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 방식은 &lt;b&gt;&lt;code&gt;import ...&lt;/code&gt;&lt;/b&gt; 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;run.py&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;# 패키지 임포트import mymath

# 서브패키지 임포트import mymath.shapes

# 모듈 임포트import mymath.shapes.area

# 모듈 안에 있는 변수나 함수는 이 방식으로 임포트 할 수 없음import mymath.shapes.area.circle# 오류&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 &lt;b&gt;&lt;code&gt;import&lt;/code&gt;&lt;/b&gt; 뒤에 가져오고 싶은 모듈이나 패키지를 써 주면 됩니다. 하지만 모듈 안에 있는 변수나 함수는 이 방식으로 임포트 할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 (서브)패키지를 임포트할 때는 (서브)패키지 안에서 임포트하고 싶은 걸 (서브)패키지의 init 파일에 적어줘야겠죠?&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;code&gt;from ... import ...&lt;/code&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 방식은 &lt;b&gt;&lt;code&gt;from ... import ...&lt;/code&gt;&lt;/b&gt; 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;run.py&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;# 패키지 안에 있는 패키지 임포트from mymath import shapes

# 패키지 안에 있는 모듈 임포트from mymath.shapes import area

# 모듈 안에 있는 함수 임포트from mymath.shapes.area import circle

# import 뒤에는 . 을 쓸 수 없음from mymath import shapes.area# 오류&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;from&lt;/code&gt;&lt;/b&gt; 뒤에는 모듈이나 패키지가 올 수 있습니다. &lt;b&gt;&lt;code&gt;import&lt;/code&gt;&lt;/b&gt; 뒤에는 모듈이나 패키지 안에서 가져오고 싶은 걸 써 줍니다. &lt;b&gt;&lt;code&gt;import&lt;/code&gt;&lt;/b&gt; 뒤에는 &lt;b&gt;&lt;code&gt;.&lt;/code&gt;&lt;/b&gt; 을 쓸 수 없습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;17. 상대 경로 임포트&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;203&quot; data-filename=&quot;Untitled 1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUaEg6/btrhd6RfYF0/DWVaimSprrf6gquuXaAgkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUaEg6/btrhd6RfYF0/DWVaimSprrf6gquuXaAgkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUaEg6/btrhd6RfYF0/DWVaimSprrf6gquuXaAgkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUaEg6%2Fbtrhd6RfYF0%2FDWVaimSprrf6gquuXaAgkK%2Fimg.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;203&quot; data-filename=&quot;Untitled 1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;capnproto&quot;&gt;&lt;code&gt;__init__.py
from mymath.shapes import area, volume
from . import area, volume # . 은 현재 init 파일의 위치를 의미
from .area import * 
from .volume import * &lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/72</guid>
      <comments>https://minimilab.tistory.com/72#entry72comment</comments>
      <pubDate>Sat, 9 Oct 2021 18:36:45 +0900</pubDate>
    </item>
    <item>
      <title>인터랙티브 자바스크립트</title>
      <link>https://minimilab.tistory.com/71</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;300&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GCGty/btrg2g7aG6r/eZiL7QQ5DzoHhWtTtaayc1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GCGty/btrg2g7aG6r/eZiL7QQ5DzoHhWtTtaayc1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GCGty/btrg2g7aG6r/eZiL7QQ5DzoHhWtTtaayc1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGCGty%2Fbtrg2g7aG6r%2FeZiL7QQ5DzoHhWtTtaayc1%2Fimg.jpg&quot; width=&quot;300&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드잇의 인터랙티브 자바스크립트를 보면서&lt;br /&gt;정리한 내용입니다.&lt;br /&gt;문제가 될 시 삭제하겠습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;인터랙티브 자바스크립트&lt;/h1&gt;
&lt;h1&gt;1. 인터랙티브 자바스크립트 시작하기&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. id로 태그 선택하기&lt;/h2&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// id로 태그 선택하기
// 존재하지 않는 id를 선택하면 null로 나옴
document.getElementById('id');&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. class로 태그 선택하기&lt;/h2&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;// class로 태그 선택하기
document.getElementsByClassName('class');

// class로 태그 선택하기
const test = document.getElementsByClassName('class');
console.log(test[1]);

for (let value of test) {
    console.log(value);
}

// getElementsByClassName 메소드를 통해 존재하지 않는 class 값으로 태그를 선택하게 되면 그 값은 빈 HTMLCollelction이 됩니다&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. 유사배열 (Array-Like Object)&lt;/h2&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;/ul&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자 형태의 indexing이 가능하다.&lt;/li&gt;
&lt;li&gt;length 프로퍼티가 있다.&lt;/li&gt;
&lt;li&gt;배열의 기본 메소드를 사용할 수 없다.&lt;/li&gt;
&lt;li&gt;Array.isArray(유사배열)은 false이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. 태그 이름으로 태그 선택하기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;300&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/df9XTV/btrgXhGhrDN/BTVxKxTkfJtRCeqb0hlgt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/df9XTV/btrgXhGhrDN/BTVxKxTkfJtRCeqb0hlgt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/df9XTV/btrgXhGhrDN/BTVxKxTkfJtRCeqb0hlgt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdf9XTV%2FbtrgXhGhrDN%2FBTVxKxTkfJtRCeqb0hlgt1%2Fimg.png&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;300&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;const btns = document.getElementsByTagName('button');

// 모든 태그 선택
const allTags = document.getElementsByTagName('*'); &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. CSS 선택자로 태그 선택하기&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// css 선택자로 태그 선택하기
const myTag = document.querySelector('#myNumber'); // 가장 위의 한개만 선택됨
console.log(myTag);

const myTag2 = document.getElementById('myNumber');
console.log(myTag2);

const myTag3 = document.querySelectorAll('.color-btn'); // 해당하는 것 모두 선택됨
console.log(myTag3);

const myTag4 = document.getElementsByClassName('color-btn');
console.log(myTag4);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 이벤트와 버튼 클릭&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이벤트 : 웹 페이지에서 발생하는 대부분의 일(사건)들 ex) 버튼 클릭, 스크롤, 키보드 입력, ...&lt;/li&gt;
&lt;li&gt;이벤트 핸들링 : 자바스크립트를 통해 이벤트를 다루는 일&lt;/li&gt;
&lt;li&gt;이벤트 핸들러 : 이벤트가 발생했을 때 일어나야하는 구체적인 동작들을 표현한 코드. &lt;b&gt;이벤트 리스너(Event Listener)&lt;/b&gt;라고도 부른다.&lt;/li&gt;
&lt;li&gt;버튼 클릭 시 로그가 출력됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 이벤트(Event)와 버튼 클릭 
const btn = document.querySelector('#myBtn');

// 이벤트 핸들러를 등록하는 2가지 방법
// 1. onclick 프로퍼티에 함수를 할당
btn.onclick = function() { // 이벤트 핸들러
    console.log('Hello Codeit!');
}

// 2. HTML 태그의 onclick 속성에 바로 표시하기
&amp;lt;button id=&quot;myBtn&quot; onclick=&quot;console.log('Hello Codeit!')&quot;&amp;gt;클릭!&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;2. 브라우저와 자바스크립트&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 브라우저도 객체다?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;window 객체는 자바스크립트의 최상단 객체
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;window 객체가 자바스크립트의 모든 것을 포함하고 있음&lt;/li&gt;
&lt;li&gt;window 객체는 자바스크립트 어느 곳에서나 접근 가능&lt;/li&gt;
&lt;li&gt;window 객체는 전역객체임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;// window 
console.log(window); 
console.log(window.innerWidth);
console.log(window.innerHeight);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. DOM(Document Object Model)&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;console.log(document);
console.log(typeof document);&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;console.dir(document); // property가 출력되는 모습을 볼 수 있음&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;const title = document.querySelector('#title');
title.style.color = 'red';&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. console.dir?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;console.log와 console.dir의 다른점&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출력하는 자료형이 다르다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;dir 메소드는 문자열 표시 형식으로 콘솔에 출력한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;log는 값 자체에, dir은 객체 속성에
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;log는 파라미터로 전달받은 값을 위주로 출력한다.&lt;/li&gt;
&lt;li&gt;dir은 객체의 속성을 좀 더 자세하게 출력한다. (클릭하면 함수가 가진 속성들을 더 보여줌)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파라미터로 전달할 수 있는 값의 개수에도 차이가 있다. log는 여러개 출력, dir은 여러개 입력해도 하나만 출력!&lt;/li&gt;
&lt;li&gt;DOM 객체를 다룰 때
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;log는 HTML 형태로 출력하고, dir 메소드는 대상 객체 형태로 출력함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const myDOM = document.body;

console.log(myDOM);
console.dir(myDOM);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;471&quot; data-filename=&quot;Untitled 2.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSiK1V/btrgXqpp1Mw/fi6CvmnZ8lyWdbpNlvNGYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSiK1V/btrgXqpp1Mw/fi6CvmnZ8lyWdbpNlvNGYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSiK1V/btrgXqpp1Mw/fi6CvmnZ8lyWdbpNlvNGYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSiK1V%2FbtrgXqpp1Mw%2Ffi6CvmnZ8lyWdbpNlvNGYK%2Fimg.png&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;471&quot; data-filename=&quot;Untitled 2.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. DOM 트리 (Document Object Model)&lt;/h2&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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;445&quot; data-filename=&quot;Untitled 3.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m4RbK/btrg2hdWIcy/RNMRayGRkJbKAsMfnBvoo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m4RbK/btrg2hdWIcy/RNMRayGRkJbKAsMfnBvoo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m4RbK/btrg2hdWIcy/RNMRayGRkJbKAsMfnBvoo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm4RbK%2Fbtrg2hdWIcy%2FRNMRayGRkJbKAsMfnBvoo1%2Fimg.png&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;445&quot; data-filename=&quot;Untitled 3.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. DOM 트리 여행하기&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const myTag = document.querySelector('#content');
console.log(myTag);

// 형제 요소 노드
console.log(myTag.previousElementSibling);
console.log(myTag.nextElementSibling);

// 부모 요소 노드
console.log(myTag.parentElement);

// 자식 요소 노드
console.log(myTag.children[1]); // 해당 요소의 자식 노드
console.log(myTag.firstElementChild); // 자식들 중 가장 첫번째 요소
console.log(myTag.lastElementChild); // 자식들 중 가장 마지막 요소&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. 요소 노드 프로퍼티&lt;/h2&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;// 요소 노드 주요 프로퍼티
const myTag = document.querySelector('#list-1');

// innerHTML : 요소 안에 잇는 HTML을 문자열로 return 함 (태그, 들여쓰기 모두 포함함)
console.log(myTag.innerHTML);

// innerHTML 로 요소를 추가할 수도 있음
myTag.innerHTML += '&amp;lt;li&amp;gt;Exotic&amp;lt;/li&amp;gt;';

// innerHTML 로 요소를 변경할 수도 있음
myTag.innerHTML = '&amp;lt;li&amp;gt;Exotic&amp;lt;/li&amp;gt;';

// outerHTML : 바깥 요소까지 포함되된 HTML 문자열을 return 함 
console.log(myTag.outerHTML);

// textContent : 텍스트만 다룸, &amp;lt;li&amp;gt; 요소 같은 것을 사용할 수 없음
console.log(myTag.textContent);
myTag.textContent = '&amp;lt;li&amp;gt;new text!&amp;lt;/li&amp;gt;';&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 요소 노드 추가하기&lt;/h2&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// 요소 노드 추가하기
const tomorrow = document.querySelector('#tomorrow');

// 1. 요소 노드 만들기: document.createElement('태그이름')
const first = document.createElement('li');

// 2. 요소 노드 꾸미기 : textContent, innerHTML, ...
first.textContent = '처음';

// 3. 요소 노드 추가하기 : Node.prepend, append, after, before
tomorrow.prepend(first);

const last = document.createElement('li');
last.textContent = '마지막';
tomorrow.append(last);

const prev = document.createElement('p');
last.textContent = '이전';
tomorrow.append(prev); // 혹은 tomorrow.append('문자열') 도 가능 

const prev = document.createElement('p');
last.textContent = '다음';
tomorrow.append(prev);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. 노드 삭제와 이동하기&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 노드 삭제와 이동
const today = document.querySelector('#today');
const tomorrow = document.querySelector('#tomorrow');

// 노드 삭제하기: Node.remove();
tomorrow.remove();
today.children[2].remove();

// 노드 이동하기: prepend, append, before, after
today.append(tomorrow.children[1]);
tomorrow.children[1].after(today.children[1]);
tomorrow.children[2].before(today.children[1]);
tomorrow.lastElementChild.before(today.children[1]);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. 오늘 꼭 해야할 일 !&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;li&lt;/code&gt;&lt;/b&gt; 태그이름을 가진 요소 노드를 만든 다음&lt;/li&gt;
&lt;li&gt;그 요소 노드에 파라미터로 전달받은 오늘 할 일(&lt;b&gt;&lt;code&gt;text&lt;/code&gt;&lt;/b&gt;)을 담고&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;&amp;lt;ul id=&quot;to-do-list&quot;&amp;gt;&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/b&gt;태그의 마지막 자식 요소 노드로 추가하는 함수&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const toDoList = document.querySelector('#to-do-list');

function addNewTodo(text) {
    // 여기에 코드를 작성해 주세요.
    const tag = document.createElement('li');
    tag.textContent = text;
    toDoList.append(tag); 
}

// 테스트 코드
addNewTodo('자바스크립트 공부하기');
addNewTodo('고양이 화장실 청소하기');
addNewTodo('고양이 장난감 쇼핑하기');&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. HTML 속성 다루기&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;const tomorrow = document.querySelector('#tomorrow');
const item = tomorrow.firstElementChild;
const link = item.firstElementChild;

// elem.getAttribute('속성'): 속성에 접근하기
console.log(tomorrow.getAttribute('href'));
console.log(item.getAttribute('class'));

// elem.setAttribute('속성', '값'); 속성 추가(수정)하기
tomorrow.setAttribute('class', 'list');
link.setAttribute('href', 'https://www.colde.kr');

// elem.removeAttribute('속성') : 속성 제거하기
tomorrow.removeAttribute('href');
tomorrow.removeAttribute('class');&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;16. 스타일 다루기&lt;/h2&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// 스타일 다루기
const today = document.querySelector('#today');
const tomorrow = document.querySelector('#tomorrow');

console.log(today.classList);
conole.log(today.children[1].classList;);

// class 속성의 값을 통채로 바꾸려면 className
today.children[1].className = 'done'; // .done 이라는 style class 미리 작성해두고, className을 추가

// class 속성의 내용을 부분적으로 바꾸려면 classList
// elem.classList : add, remove, toggle
item.classList.add('done', 'other'); // done과 other class 추가  
item.classList.remove('done', 'other'); // done과 other class 삭제
item.classList.toggle('done'); // done 클래스가 있으면 제거하고, 없으면 붙임

// style 프로퍼티
today.children[0].style.textDecoration = 'line-through'; // 중간에 밑줄 긋기 
today.children[0].style.backgroundColor = '#DDDDDD';&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;3. 이벤트 살펴보기&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 이벤트 핸들러 등록하기&lt;/h2&gt;
&lt;pre class=&quot;scilab&quot;&gt;&lt;code&gt;let btn = document.querySelector('#myBtn');
// 이벤트 핸들러 등록하는 방법
btn.onclick = function () {
    console.log('Hi again!');
}

function event1() {
    console.log(&quot;hi!');
}

function event2() {
    console.log(&quot;hello!');
}

// 이벤트 핸들러 등록 시 권장되는 방법
btn.addEventListenner('click', event1); // event1 처럼 함수명만 넣으면됨, event1() 로 쓰면 함수를 실행하라는 의미가 됨
btn.addEventListenner('click', event2);

// 이벤트 핸들러 삭제하기
btn.removeEventListenr('click', event2);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 다양한 이벤트&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마우스 이벤트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mousedown(마우스 버튼을 누르는 순간),&lt;/li&gt;
&lt;li&gt;mouseup(마우스 버튼을 눌렀다 떼는 순간),&lt;/li&gt;
&lt;li&gt;click(왼쪽 버튼을 클릭한 순간),&lt;/li&gt;
&lt;li&gt;dbclick(더블클릭한 순간),&lt;/li&gt;
&lt;li&gt;contextmenu(오른쪽 버튼을 클릭한 순간),&lt;/li&gt;
&lt;li&gt;mousemove(마우스를 움직인 순간),&lt;/li&gt;
&lt;li&gt;mouseover(마우스 포인터가 요소 위로 올라온 순간),&lt;/li&gt;
&lt;li&gt;mouseout(마우스 포인터가 요소에서 벗어나는 순간),&lt;/li&gt;
&lt;li&gt;mouseenter(마우스 포인터가 요소위로 올라온 순간(버블링이 일어나지 않음)),&lt;/li&gt;
&lt;li&gt;mouseleave(마우스 포인터가 요소에서 벗어나는 순간 (버블링이 일어나지 않음)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;키보드 이벤트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;keydown : 키보드의 버튼을 누르는 순간&lt;/li&gt;
&lt;li&gt;keypress : 키보드의 버튼을 누르는 순간(a, 5 등 출력이 가능한 키에서만 동작하고, shift, esc 등의 키에서는 반응하지 않음&lt;/li&gt;
&lt;li&gt;keyup : 키보드의 버튼을 눌렀다 떼는 순간&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;포커스 이벤트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;focusin (요소에 포커스가 되는 순간)&lt;/li&gt;
&lt;li&gt;focusout ( 요소로부터 포커스가 빠져나가는 순간)&lt;/li&gt;
&lt;li&gt;focus : 요소에 포커스가 되는 순간 (버블링이 일어나지 않음)&lt;/li&gt;
&lt;li&gt;blur : 요소로부터 포커스가 빠져나가는 순간 (버블링이 일어나지 않음)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;입력 이벤트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;change : 입력된 값이 바뀌는 순간&lt;/li&gt;
&lt;li&gt;input : 값이 입력되는 순간&lt;/li&gt;
&lt;li&gt;select : 입력 양식의 하나가 선택되느 순간&lt;/li&gt;
&lt;li&gt;submit : 폼을 전송하는 순간&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스크롤 이벤트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;scroll : 스크롤바가 움직일 때&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;윈도우 창 이벤트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;resize : 윈도우 사이즈를 움직일 때 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 이벤트 객체&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// 이벤트 객체
const myInput = document.querySelector('#myInput');
const myBtn = document.querySelector('#myBtn');

function prientEvent(event){ // 보통 event 대신 e로 사용함
    console.log(event);
}

// 이벤트 핸들러가 되는 함수의 첫번째 파라미터에는 이벤트 객체가 전달됨
myInput.addEventListener('keydown', printEvent);
myBtn.addEventListener('click', printEvent);&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;05. 이벤트 객체 프로퍼티&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 공통 프로퍼티&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Event&quot;&gt;이벤트&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;type : 이벤트 이름( click, mouseup, keydown 등)&lt;/li&gt;
&lt;li&gt;target : 이벤트가 발생한 요소&lt;/li&gt;
&lt;li&gt;currentTarget : 이벤트 핸들러가 등록된 요소&lt;/li&gt;
&lt;li&gt;timeStamp : 이벤트가 발생한 시각( 페이지가 로드 된 이후부터 경과한 밀리초)&lt;/li&gt;
&lt;li&gt;bubbles : 버블리이 단계인지를 판단하는 값&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 마우스 이벤트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent&quot;&gt;마우스 이벤트&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;button : 누른 마우스의 버튼 (0:왼쪽, 1:가운데, 2:오른쪽)&lt;/li&gt;
&lt;li&gt;clientX, clientY : 마우스 커서의 브라우저 표시 영역에서의 위치&lt;/li&gt;
&lt;li&gt;pageX, pageY : 마우스 커서의 문서 영역에서의 위치&lt;/li&gt;
&lt;li&gt;offsetX, offsetY : 마우스 커서의 이벤트 발생한 요소에서의 위치&lt;/li&gt;
&lt;li&gt;screenX, screenY : 마우스 커서의 모니터 화면 영역에서의 위치&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 키보드 이벤트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent&quot;&gt;키보드 이벤트&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;key : 누른 키가 가지고 있는 값&lt;/li&gt;
&lt;li&gt;code : 누른 키의 물리적인 위치&lt;/li&gt;
&lt;li&gt;altKey : 이벤트가 발생할 때 alt 키를 눌렀는지&lt;/li&gt;
&lt;li&gt;ctrlKey: 이벤트가 발생할 때 ctrl키를 눌렀는지&lt;/li&gt;
&lt;li&gt;shiftKey: 이벤트가 발생할 때 shift키를 눌렀는지&lt;/li&gt;
&lt;li&gt;metaKey : 이벤트가 발생할 때 meta키를 ㅜㄹ렀는지&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;06. 완료한 일 체크하기&lt;/h3&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;title&amp;gt;오늘 할 일&amp;lt;/title&amp;gt;
  &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;div class=&quot;main&quot;&amp;gt;
    &amp;lt;h2 class=&quot;title&quot;&amp;gt;오늘 할 일&amp;lt;/h2&amp;gt;
    &amp;lt;ul id=&quot;to-do-list&quot; class=&quot;to-do-list&quot;&amp;gt;
      &amp;lt;li&amp;gt;자바스크립트 공부하기&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;고양이 화장실 청소하기&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;고양이 장난감 쇼핑하기&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;script src=&quot;index.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;const toDoList = document.querySelector('#to-do-list');
const items = toDoList.children;

// 1. updateToDo 함수를 완성해 주세요.
function updateToDo(event) {
  event.target.classList.toggle('done');
}

// 2. 반복문을 활용해서 각 li태그에 이벤트 핸들러를 등록해 주세요.
for (let item of items) {
  item.addEventListener('click', updateToDo);
}

// 테스트 코드
items[2].removeEventListener('click', updateToDo);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;07. 이벤트 버블링&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;window 객체를 만날 때 까지 자식요소 &amp;rarr; 부모 요소까지 event 가 실행&lt;/li&gt;
&lt;li&gt;이벤트 객체의 e.stopPropagation(); 을 사용하면 버블링을 막을 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가급적 피하는 것이 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 이벤트 위임&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버블링에 따라서 부모에 등록하면, 자식을 클릭할 때 부모인 list 에 적용한 이벤트 핸들러가 실행됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;qml&quot;&gt;&lt;code&gt;// 이벤트 위임 (Event Delegation)
const list = document.querySelector('#list');

list.addEventListener('click', function(e) {
    e.target.classList.toggle('done');
});&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;위와 같이하면 list에도 done 이 생기므로, 아래와 같이 list의 item에만 적용되도록 해야함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1602&quot; data-origin-height=&quot;890&quot; data-filename=&quot;Untitled 5.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bG3klX/btrgYlIqTbB/GVKN85DfEi0sNtzQ9Gkl0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bG3klX/btrgYlIqTbB/GVKN85DfEi0sNtzQ9Gkl0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bG3klX/btrgYlIqTbB/GVKN85DfEi0sNtzQ9Gkl0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbG3klX%2FbtrgYlIqTbB%2FGVKN85DfEi0sNtzQ9Gkl0k%2Fimg.png&quot; data-origin-width=&quot;1602&quot; data-origin-height=&quot;890&quot; data-filename=&quot;Untitled 5.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. 브라우저의 기본 동작&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 이벤트가 발생했을 때 이루어지는 브라우저의 기본적인 동작들은 이벤트 객체의 preventDefault 메소드를 통해 막을 수가 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;752&quot; data-filename=&quot;Untitled 6.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzfIQr/btrg1Xtb0uL/XtPqleluo3v34YrJh3TuHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzfIQr/btrg1Xtb0uL/XtPqleluo3v34YrJh3TuHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzfIQr/btrg1Xtb0uL/XtPqleluo3v34YrJh3TuHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzfIQr%2Fbtrg1Xtb0uL%2FXtPqleluo3v34YrJh3TuHk%2Fimg.png&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;752&quot; data-filename=&quot;Untitled 6.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. 종합정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 이벤트 핸들러 등록하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML의 속성이나 DOM 프로퍼티를 활용해 이벤트를 등록하는 방법 외에 &lt;b&gt;&lt;code&gt;Element.addEventListener('type', 'handler')&lt;/code&gt;&lt;/b&gt;를 통해서 이벤트 핸들러를 등록할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 이벤트 핸들러 삭제하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;addEventListener&lt;/code&gt;&lt;/b&gt; 메소드를 활용해서 이벤트 핸들러를 등록했다면, &lt;b&gt;&lt;code&gt;Element.removeEventListner('type', 'handler')&lt;/code&gt;&lt;/b&gt;를 통해서 이벤트 핸들러를 삭제할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 이벤트 객체 (Event Object)&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;이벤트 객체는 이벤트 종류마다 가지고 있는 프로퍼티가 다르며, 이벤트에 대한 유용한 정보들을 프로퍼티로 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 이벤트 버블링 (Event Bubbling)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트는 전파가 됩니다.&lt;br /&gt;어떤 요소에서 이벤트가 발생하면 해당 요소에 등록된 이벤트 핸들러가 동작하는 것뿐만 아니라 부모 요소로 이벤트가 계속해서 전파되면서 각 요소에도 등록된 이벤트 핸들러가 있다면 차례로 이벤트 핸들러가 동작하는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 요소에서 부모 요소로 이벤트가 전파되는 것을 &lt;b&gt;이벤트 버블링(Event Bubbling)&lt;/b&gt;이라고 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 이벤트 버블링은 &lt;b&gt;이벤트 객체&lt;/b&gt;의 &lt;b&gt;&lt;code&gt;stopPropagation&lt;/code&gt;&lt;/b&gt; 메소드로 전파를 막을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 이벤트 위임 (Event Delegation)&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;이렇게 이벤트를 다루는 방식을 자식 요소의 이벤트를 부모 요소에 위임한다고 해서 &lt;b&gt;이벤트 위임(Event Delegation)&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;&lt;b&gt;6. 브라우저의 기본 동작&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;예를 들어 마우스 오른쪽 버튼을 클릭하면 상황에 맞는 메뉴 창이 뜬다거나, &lt;b&gt;&lt;code&gt;input&lt;/code&gt;&lt;/b&gt; 태그에 커서를 두고 키보드 키를 누르면 해당 값이 입력된다거나..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 만약 이러한 동작들을 막고 싶다면 &lt;b&gt;이벤트 객체&lt;/b&gt;의 &lt;b&gt;&lt;code&gt;preventDefault&lt;/code&gt;&lt;/b&gt; 메소드를 통해 막을 수가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 각 HTML 태그들이 가지고 있는 고유한 역할과 의미를 훼손하게 될 수도 있기 때문에 꼭 필요한 경우에만 주의해서 사용해야 한다는 점. 꼭 기억해 주세요 :)&lt;/p&gt;
&lt;h1&gt;다양한 이벤트 알아보기&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 마우스 버튼 이벤트&lt;/h2&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;// MouseEvent.button
0 : 마우스 왼쪽버튼
1 : 마우스 휠
2 : 마우스 오른쪽 버튼

// MouseEvent.type
// click : 마우스 왼쪽 버튼을 눌렀을 때
// contextmenu : 마우스 오른쪽 버튼을 눌렀을 때 
// dbclick : 동일한 위치에서 빠르게 두번 click
// mousedown : 마우스 버튼을 누른 순간 
// mouseup : 마우스 버튼을 눌렀다 뗀 순간 &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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;213&quot; data-filename=&quot;Untitled 7.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0FSdE/btrgYK8U7fT/rq45VkG2CKK1OH0KgAAVR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0FSdE/btrgYK8U7fT/rq45VkG2CKK1OH0KgAAVR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0FSdE/btrgYK8U7fT/rq45VkG2CKK1OH0KgAAVR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0FSdE%2FbtrgYK8U7fT%2Frq45VkG2CKK1OH0KgAAVR0%2Fimg.png&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;213&quot; data-filename=&quot;Untitled 7.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;03. 마우스 이동 이벤트 1&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;[마우스 이동 이벤트]
MouseEvent.type
mousemove : 마우스 포인터가 이동할 때 
mouseover : 마우스 포인터가 요소 밖에서 안으로 이동할 때
mouseout : 마우스 포인터가 요소 안에서 밖으로 이동할 때 

MouseEvent.clientX, clientY
화면에 표시되는 창 기준 마우스 포인터 위치 
그 순간 보여지는 화면을 기준으로 계산하기 때문에 스크롤 위치와는 무관하게 항상 보여지는 화면의 좌측 상단의 모서리 위치를 (0, 0)으로 계산

MouseEvent.pageX, pageY
웹 문서 전체 기준 마우스 포인터 위치
스크롤로 인해서 보이지 않게된 화면의 영역까지 포함해서 측정한다는 점

MouseEvent.offsetX, offsetY
이벤트가 발생한 요소 기준 마우스 포인터 위치
스크롤 위치와는 무관하게 항상 대상의 좌측 상단의 모서리 위치를 (0, 0)으로 계산

const box1 = document.querySelector('#box1');

function onMouseMove(e) {
    console.log('mouse is moving!');
    console.log('client: (${e.clientX}, ${e.clientY})');
    console.log('page: (${e.clientX}, ${e.clientY})');
    console.log('offset: (${e.offsetX}, ${e.offsetY})');
}

box1.addEventListener('mousemove', onMouseMove);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;683&quot; data-filename=&quot;Untitled 8.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6bh0s/btrg2UbBEJv/g1FMtrt3huBAFkWvqg4JZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6bh0s/btrg2UbBEJv/g1FMtrt3huBAFkWvqg4JZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6bh0s/btrg2UbBEJv/g1FMtrt3huBAFkWvqg4JZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6bh0s%2Fbtrg2UbBEJv%2Fg1FMtrt3huBAFkWvqg4JZk%2Fimg.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;683&quot; data-filename=&quot;Untitled 8.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;03. 마우스 이동 이벤트 2&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;329&quot; data-filename=&quot;Untitled 9.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI9EHi/btrg3qIeJmo/VdK4lFhcHSSOumwDSoJcAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI9EHi/btrg3qIeJmo/VdK4lFhcHSSOumwDSoJcAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI9EHi/btrg3qIeJmo/VdK4lFhcHSSOumwDSoJcAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI9EHi%2Fbtrg3qIeJmo%2FVdK4lFhcHSSOumwDSoJcAk%2Fimg.png&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;329&quot; data-filename=&quot;Untitled 9.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;const box1 = document.querySelector('#box2');

function printEventData(e) {
    if (e.target.classList.contains('cell')) { // #box2의 class=&quot;box&quot; 가 잡히므로 버블링이 일어나기 때문에
            e.target.classList.toggle('on');
    }
}

box2.addEventListener('mouseover', printEventData);
box2.addEventListener('mouseout', printEventData);&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// MouseEvent.target
// 이벤트가 발생한 요소 

// MouseEvent.relatedTarget
// 이벤트가 발생하기 직전(또는 직후)에 마우스가 위치해 있던 요소 

const box2 = document.querySelector('#box2');

function printEventData(e) {
    console.log('event:', e.type);
    console.log('target:', e.target);
    console.log('relatedTarget:', e.relatedTarget);    

}

box2.addEventListener('mouseover', printEventData);
box2.addEventListener('mouseout', printEventData);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;152&quot; data-filename=&quot;Untitled 10.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KF9fU/btrgXid8m2A/LXz59fpv8s9ga6KKSq9NJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KF9fU/btrgXid8m2A/LXz59fpv8s9ga6KKSq9NJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KF9fU/btrgXid8m2A/LXz59fpv8s9ga6KKSq9NJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKF9fU%2FbtrgXid8m2A%2FLXz59fpv8s9ga6KKSq9NJ0%2Fimg.png&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;152&quot; data-filename=&quot;Untitled 10.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mouseover의 relatedTarget 은 마우스가 이동하기 직전의 target&lt;/li&gt;
&lt;li&gt;mouseout의 relatedTarget 은 마우스가 이동한 직후의 target&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;06. mouseenter / mouseleave&lt;/h3&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;mouseover/mouseout과 비교하면서 mouseenter/mouseleave에 대해 살펴봤는데요.
간단하게 정리하면, 이벤트가 자식 요소에 영향끼치는지가 둘의 가장 큰 차이라고 할 수 있습니다.

그래서 이벤트 핸들러가 자식 요소에까지 영향을 끼치게 하고싶은 경우에는 mouseover/mouseout을, 
자식 요소에는 영향을 끼치지 않고 해당 요소에만 이벤트 핸들러를 다루고자 한다면 mouseenter/mouseleave를 활용&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;07. 효준이네 집&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// showTitle 함수를 완성해 주세요.
function showTitle(e) {
    // 여기에 코드를 작성해 주세요.
  if (e.target.dataset.title) {
    const span = document.createElement('span');
    span.classList.add('title');
    span.textContent = e.target.dataset.title;   // 자바스킙트로 HTML 태그의 비표준 속성 활용할 때 HTML 태스에 data-* 형태로 속성을 작성하고 자바스크립트로는 DOM의 dataset 프로퍼티를 활용
    e.target.append(span);
    console.log(span);
  }
}

// removeTitle 함수를 완성해 주세요.
function removeTitle(e) {
    // 여기에 코드를 작성해 주세요.
  if (e.target.dataset.title) {
    e.target.lastElementChild.remove();
  }
}

const map  = document.querySelector('.map')

// '대상'과 '타입'을 수정해 주세요.
map.addEventListener('mouseover', showTitle);
map.addEventListener('mouseout', removeTitle);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;08. 키보드 이벤트&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;&amp;gt; KeyboardEvent.type
* keydown: 키보드 버튼을 누른 순간
* keypress: 키보드 버튼을 누른 순간
* keyup : 키보드 버튼을 눌렀다 뗀 순간

&amp;gt; KeyboardEvent.key  // Shift
: 이벤트가 발생한 버튼의 값 

&amp;gt; KeyboardEvent.code  // ShiftRight
: 이벤트가 발생한 버튼의 키보드에서 물리적인 위치&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;09. 똑Talk한 Enter키!&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const chatBox = document.querySelector('#chat-box');
const input = document.querySelector('#input');
const send = document.querySelector('#send');

function sendMyText() {
  const newMessage = input.value;
  if (newMessage) {
    const div = document.createElement('div');
    div.classList.add('bubble', 'my-bubble');
    div.innerText = newMessage;
    chatBox.append(div);
  } else {
    alert('메시지를 입력하세요...');
  }

  input.value = '';
}

send.addEventListener('click', sendMyText);

function sendMyTextByEnter (e) {
  if (e.key === 'Enter' &amp;amp;&amp;amp; !e.shiftKey) { //  이벤트 객체의 프로퍼티에는 shiftKey라는 프로퍼티가 있습니다. 이 프로퍼티는 이름 그대로 이벤트가 발생할 때 shift키를 눌렀는지를 불린 형태로 담고 있음
    sendMyText();
    e.preventDefault(); // sendMyText 함수 실행 후 원래 Enter의 기본 기능이 실행되기 때문에 브라우저의 기본 동작을 막는 방법인 preventDefault 를 실행
  }
}

input.addEventListener('keypress', sendMyTextByEnter);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. input 태그 다루기&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// input 태그 다루기

&amp;gt; focus 이벤트
* focusin: 요소에 포커스가 되었을 때
* focusout: 요소에 포커스가 빠져나갈 때 
* focus: 요소에 포커스가 되었을 때 (버블링 x)
* blur: 요소에 포커스가 빠져나갈 때 (버블링 x)

&amp;gt; 입력 이벤트
* input : 사용자가 입력을 할 때 
* change: 요소의 값이 변했을 때 

const el = document.querySelector('#username');

function printEventType(e) {
    console.log('type:', e.type);
    console.log('target:', e.target);
    console.log('-------------------');
}

el.addEventListener('focusin', printEventType);
el.addEventListener('focusout', printEventType);
el.addEventListener('input', printEventType);
el.addEventListener('change', printEventType);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12. scroll 이벤트&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// Scroll 이벤트
function printEvent(e) {
    console.log(e);
    console.log(window.scrollY); // 몇 픽셀 
}

window.addEventListener('scroll', printEvent);&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Javascript</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/71</guid>
      <comments>https://minimilab.tistory.com/71#entry71comment</comments>
      <pubDate>Wed, 6 Oct 2021 22:38:52 +0900</pubDate>
    </item>
    <item>
      <title>프로그래밍과 데이터 in JavaScript</title>
      <link>https://minimilab.tistory.com/70</link>
      <description>&lt;h1&gt;프로그래밍과 데이터 in JavaScript&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;프로그래밍 핵심 개념 in javascirpt-001 (1).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wulLq/btrf1iKYIbu/Ts3E3prp1XxAobgaF2uoaK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wulLq/btrf1iKYIbu/Ts3E3prp1XxAobgaF2uoaK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wulLq/btrf1iKYIbu/Ts3E3prp1XxAobgaF2uoaK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwulLq%2Fbtrf1iKYIbu%2FTs3E3prp1XxAobgaF2uoaK%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;프로그래밍 핵심 개념 in javascirpt-001 (1).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;해당 내용은 코드잇의 '프로그래밍과 데이터 in JavaScript' 를 보고 정리한 내용입니다.&lt;br /&gt;문제가 될 시 삭제하겠습니다.&lt;/blockquote&gt;
&lt;h1&gt;01. 객체&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 객체와 프로퍼티&lt;/h2&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;property name 작성 시 따옴표로 감싸지 않을 수 있지만, 그러려면 아래의 조건을 만족해야 함
&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;/li&gt;
&lt;li&gt;하이픈(-) 금지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;{
    키 : value,
  property name : property value
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 객체에서 데이터 접근하기&lt;/h2&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;
let codeit = {
    name: '코드잇',
    'born Year': 2017,
    isVeryNice : true,
    wortCourse: null,
    bestCourse: {
        title: '자바스크립트',
        language: 'JavaScript'
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;점표기법으로 접근
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;property name 에 띄어쓰기가 있거나 하이픈(-) 이 있는 경우 사용할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;console.log(codeit.bornYear);&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대괄호 표기법&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;console.log(codeit['born Year']);
console.log(codeit['born'+' Year']);

let propertyName = 'name';
console.log(codeit[propertyName]);&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 안의 객체 접근
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;존재하지 않은 property 에 접근하려고 하면 undefined가 출력됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;console.log(codeit.bestCourse['title']);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 객체 다루기&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;
let codeit = {
    name: '코드잇',
    bornYear: 2017,
    isVeryNice : true,
    wortCourse: null,
    bestCourse: {
        title: '자바스크립트',
        language: 'JavaScript'
    }
};

codeit.name = 'codeit'; // 변경
codeit.ceo = '강영훈'; // 새로운 property 추가
delete codeit.worstCourse; // 삭제

// property 가 있는지 확인
console.log(codeit.name !== undefined);
console.log('name' in codeit);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 객체와 메소드&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let greetings = {
    width:30,
    height:50,
    sayHello: function (name) {
        console.log(`Hello! ${name}! `);
    },
    sayHi: function () {
        console.log('Hi!');
    },
    sayBye: function () {
        console.log('Bye!');
    }
};

greetings.sayHello('minimi');
greetings['sayHello']('minimi');
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. for ... in 반복문&lt;/h2&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;
for (변수 in 객체) {
    동작부분
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;let codeit = {
    name: '코드잇',
    bornYear: 2017,
    isVeryNice : true,
    wortCourse: null,
    bestCourse: {
        title: '자바스크립트',
        language: 'JavaScript'
    }
};

for (let key in codeit) {
    console.log(key);
    console.log(codeit[key]);
}&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;주의사항 : 객체의 key 를 for문으로 출력 시, 순서대로 출력되는 것이 아님&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;let myObject = {
  '3': '정수3',
  name: 'codeit',
  '1': '정수1',
  birthDay: '2017.5.17',
  '2': '정수2',
};

for (let key in myObject) {
  console.log(key);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1
2
3
name
birthDay&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. Date 객체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내장객체 : 자바스크립트가 미리 가지고 있는 객체&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// Date
let today = new Date(); // Date.now()

// new Date(milliseconds)
let myDate = new Date(1000); // 1970년 1월 1일 00:00:00 UTC + 1초

// new Date('YYYY-MM_DD')
let myDate = new Date('2017-05-18'); // 1970년 1월 1일 00:00:00 UTC + 1초

// month 는 0부터 시작
// new Date('YYYY-MM_DDThh:mm:ss')
// new Date(YYYY, MM, DD, hh, mm, ss, ms); //YYYY, MM만 필수요소

let myDate = new Date(2017, 4, 18, 19, 11, 16);

// myDate 객체가 1970년 1월 1일 00:00:00 UTC 부터 몇밀리초 지났는지
console.log(myDate.getTime()); 

let timeDiff = myDate.getTime() - today.getTime();
console.log(timeDiff / 1000 / 60 + '분');
console.log(timeDiff / 1000 / 60 /60 + '시간');
&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let myDate1 = new Date(2017, 4, 18);
let myDate2 = new Date(2017, 4, 19);

let timeDiff = myDate2 - myDate1;
console.log(timeDiff); // 86400000 (ms)
console.log(timeDiff / 1000); // 86400 (sec)
console.log(timeDiff / 1000 / 60) // 1440 (min)
console.log(timeDiff / 1000 / 60 / 60) // 24 (hour)
console.log(timeDiff / 1000 / 60 / 60 / 24) // 1 (date)&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;02. 배열&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 배열&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let courseRanking = [
    '1',
    '2',
    '3',
    '4'
];

// indexing (0 ~ ... )
console.log(배열이름[index]);
console.log(courseRanking [0]);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 배열 다루기&lt;/h2&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;let members = ['a', 'b', 'c'];

// 몇개의 요소가 들어있는지
console.log(members.length);     // 3
console.log(members['length']);  // 3

// 요소 추가하기
console.log(members[4]); // undefined
members[4] = 'nice';
console.log(members.length);     // 4

// 요소 삭제하기&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 배열 메소드 1&lt;/h2&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;let members = ['a', 'b', 'c', 'd', 'e'];

// splice(시작 index(0부터 시작), deleteCount, item(값추가))
members.splice(1, 1, 'NiceCodeit', 'HiCodeit'); 
// ['a', 'NiceCodeit', 'HiCodeit', 'c', 'd', 'e']

// 배열 특정 위치에 추가만 하고 싶은 경우 
members.splice(1, 0, 'NiceCodeit', 'HiCodeit'); 
// ['a', 'NiceCodeit', 'HiCodeit', 'b', 'c', 'd', 'e']

// 값을 대체하고 싶은 경우 
members.splice(2, 1, 'NiceCodeit'); 
// ['a', 'b', 'NiceCodeit', 'd', 'e']

// 배열의 첫 요소를 삭제 
members.splice(0, 1);

// 배열의 마지막 요소를 삭제 
members.splice(members.length -1, 1);

// 배열의 첫 요소로 값 추가
members.splice(0, 0, 'NiceCodeit');

// 배열의 마지막 요소로 값 추가 
members.splice(members.length, 0, 'HiCodeit');&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 반복문을 활용해서 numbers 배열의 요소들 중 홀수를 모두 삭제해 주세요.
numbers = [1, 2, 3, 5, 8, 9];

for (let i=0; i &amp;lt; numbers.length; i ++){
  if (numbers[i] % 2 == 1 ){
    numbers.splice(i,1)
    i --;
  } 
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 배열 메소드2&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;
members = [1, 2, 3, 4, 5, 6];

// 배열의 첫 요소를 삭제: shift()
members.shift();
console.log(members); // [2, 3, 4, 5, 6]

// 배열의 마지막 요소를 삭제: pop()
members.pop();
console.log(members); // [2, 3, 4, 5]

// 배열의 첫 요소로 값 추가: unshift(value)
members.unshift('Nice');
console.log(members); // ['Nice', 2, 3, 4, 5]

// 배열의 마지막 요소로 값 추가: push(value)
members.push('Hi');
console.log(members); // ['Nice', 2, 3, 4, 5, 'Hi']
&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;배열에서 특정 값이 있는지 확인 : array.indexOf(item)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포함되어 있다면 item 이 있는 index return&lt;/li&gt;
&lt;li&gt;포함되어 있지 않다면 -1 return&lt;/li&gt;
&lt;li&gt;여러번 포함되어 있으면, 처음 발견된 인덱스 return&lt;/li&gt;
&lt;li&gt;뒤에서 부터 탐색하려면 array.lastIndexOf(item)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let brands = ['Google', 'Kakao', 'Naver', 'Kakao'];
console.log(brands.indexOf('Kakao')); // 1
console.log(brands.indexOf('Daum')); // -1&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;배열에서 특정 값이 있는지 확인 : array.includes(item)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;array에 item이 있을 경우 true를, 없을 경우 false를 return&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-jsx&quot;&gt;let brands = ['Google', 'Kakao', 'Naver', 'Kakao'];
console.log(brands.includes('Kakao')); // true
console.log(brands.includes('Daum')); // false&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;배열 뒤집기 (reverse)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;let brands = ['Google', 'Kakao', 'Naver', 'Kakao'];

console.log(brands);
brands.reverse(); // ['Google', 'Kakao', 'Naver', 'Kakao']

console.log(brands); // ['Kakao', 'Naver', 'Kakao', 'Google']&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. for ... of 반복문&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;for ... in 과 다른 점은 배열을 돌린다는 점, 배열에는 활용하지 않는 것이 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;
for ( 변수 of 배열 ) {
    동작부분;
}

for (변수 in 객체) {
    동작부분
}

for (let element of influencer) {
    console.log(element);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. 다차원 배열&lt;/h2&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;// 다차원 배열 
let twoDimensional = [[1, 2], [3, 4]];

console.log(twoDimensional[0][1]) // 2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;03. 자료형 심화&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 다양한 숫자 표기법&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 숫자 표기법
let millionaire = 1000000000;
let myNumber = 1e9; // 지수표기법

console.log(millionaire === myNumber); // true
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;
// 16진법 (Hexadecimal)
let hex1 = 0xff; // 255
let hex2 = 0xFF; // 255

// 8진법 (Octal)
let octal = 0o377; // 255

// 2진법 (binary numeral system)
let binary = 0b11111111; // 25&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 숫자형 메소드&lt;/h2&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;let myNumber = 0.3591;

// toFixed(0 ~ 100)
console.log(myNumber.toFixed(3));  // 0.359
console.log(myNumber.toFixed(7));  // 0.3591000

console.log(typeof myNumber.toFixed(3));  // string
console.log(typeof +myNumber.toFixed(3));  // Number

// toString(2 ~ 36) 
console.log(myNumber.toString(2)); // 2진법 숫자로 변환
console.log(myNumber.toString(8)); // 8진법 숫자로 변환
console.log(myNumber.toString(16)); // 16진법 숫자로 변환
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;let myNumber = 255;

console.log(255..toString(2)); // 숫자를 그냥 쓰면 에러가 나서 .. 을 붙임 
console.log((255).toString(2)); // 숫자 양옆에 괄호를 붙이면 에러가 안남
console.log(myNumber.toString(2));
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. Math 객체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Math&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Math&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Math.abs(x) // 절대값
Math.max(2,-1) // 최대값 2
Math.min(2,-1) // 최솟값 -1
Math.pow(2,3) // 거듭제곱 8
Math.sqrt(25) // 제곱근 5
Math.round(2.3) // 반올림 2
Math.floor(2.4) // 버림 2
Math.ceil(2.4) // 올림 3
Math.random()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. 바보 자바스크립트?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0.1+0.2 를 0.3이라고 계산 못하는 멍충이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;let sum = 0.1 + 0.2; // 0.3000000000000000000004

// 올바르게 계산되도록 하기 위해서 아래와 같이 사용함
console.log(+sum.toFixed(1)); // 0.3
console.log(Math.round(sum * 10) / 10);  // 0.3
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 문자열 심화&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// String
let myString = 'Hi Codeit';

// 요소탐색
console.log(myString.indexOf('i')); // 1 앞 부터 
console.log(myString.lastIndexOf('i')); // 7 뒤 부터

// 요소 접근
console.log(myString[3]); // C 대괄호 표기법 
console.log(myString.charAt(3)); // C charAt 메소드

// 문자열 길이 
console.log(myString.length); // 9

// 대소문자 변환
console.log(myString.toUpperCase());
console.log((myString.toLowerCase());

// 양 끝 공백 제거
console.log(myString.trim());

// 부분문자열 접근 slice(start, end) 끝 인덱스 바로 직전까지의 index를 가져옴
// end 생략 시 문자열 끝까지
console.log(myString.slice(0, 2));
console.log(myString.slice(3));
console.log(myString.slice());
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 기본형과 참조형&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본형 : Number, String, Boolean, Null, Undefined&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조형 : Object (list도 Object)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. 참조형 복사하기&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let numbers1 = [1, 2, 3]
let numbers2 = numbers1;

numbers2.push(4);

console.log(numbers1); // [1, 2, 3, 4]
console.log(numbers2); // [1, 2, 3, 4]

let course1 = {
    title: '미니미 기초',
    language: '파이썬'
};

// 객체를 복사하는 방법
let course2 = Object.assign({}, course1);

course2.title = '알고리즘';

console.log(course1);
console.log(course2);&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;// 참조형 복사하기
function cloneObject(object) {
    let temp = {};

    for (let key in object) {
        temp[key] = object[key];
    }
    return temp;
};

let course1 = {
    title : '파이썬 기초',
    language: '파이썬'
    pre : []
}

let course2 = cloneObject(course1);
course2.pre.push('파이썬2'); // 객체이기 때문에 course 1,2 에 다들어가도록 됨
// 그러므로 아래와 같이 코드를 변경해줌 
function cloneObject(object) {
    if (object === null || typeof object !== 'object') {
        return object;
    }

    let temp;
    if (Array.isArray(object)) {
        temp = [];
    } else {
        temp = {};
    }

    for (let key of Object.keys(object)) {
        temp[key] = cloneObject(object[key])
    }
    return temp;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. const, 변수와 상수 사이&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;let 으로 선언한 변수는 재할당이 가능함 (변수명은 camelcase로 myName)&lt;/li&gt;
&lt;li&gt;const 로 선언한 상수는 재할당이 불가능함 (변수명은 대문자로 MY_NAME)
&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;16. 변수, 그땐 그랬지&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;var 키워드로 선언한 변수의 첫 번째 문제는, let과 const와는 다르게 중복 선언이 가능하다는 것&lt;/li&gt;
&lt;li&gt;똑같은 이름으로 변수를 한 번 더 선언하게 되면 에러가 발생하는 것이 아니라 그냥 기존의 변수를 덮어써 버림&lt;/li&gt;
&lt;li&gt;var는 Scope가 자칫 전역변수 역할을 하게 될 수 있음&lt;br /&gt;let과 const 키워드로 선언한 변수는 if, for, function 등등 어떤 키워드와 관계없이 코드 블록, 즉 {} 중괄호로 감싸진 부분을 기준으로 scope를 갖게 되지만,&lt;br /&gt;var 키워드로 선언한 변수는 scope가 function에서만 구분되어 있음&lt;br /&gt;let이나 const 키워드의 경우에는 중괄호로 감싸진 경우라면 모두 중괄호 밖에서는 지역 변수에 접근할 수 없음&lt;br /&gt;하지만 var 변수는 지역변수의 구분이 함수에만 있기 때문에 if, for, while, switch 등 다양한 상황에서 선언한 변수가 자칫, 전역변수의 역할을 하게 될 수 있음&lt;/li&gt;
&lt;li&gt;let과 const는 선언되기 이전에 사용할 수 없지만 var 는 함수 스코프를 기준으로 선언되기 이전에도 변수에 접근이 가능함&lt;/li&gt;
&lt;li&gt;끌어올림 (Hoisting)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;console.log(myVariable);
let myVariable;
Uncaught ReferenceError: Cannot access 'myVariable' before initialization&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;console.log(myVariable);
var myVariable;

undefined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수의 선언이 끌려 올라가서 마치, 2번째 줄과 첫 번째 줄이 바뀐 것처럼 동작함&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;var myVariable;
console.log(myVariable);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 변수가 끌어올려 지는 현상을 &lt;b&gt;'호이스팅(hoisting)'&lt;/b&gt;이라고 부름&lt;br /&gt;호이스팅은 선언과 동시에 값을 할당하더라도, 선언문만 올려지기 때문에 값은 그대로 두 번째 줄에 남아있는 데요.&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;console.log(myVariable);
var myVariable = 2;
console.log(myVariable);&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;undefined
2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이런 식으로 동작하는 방식은 코드의 흐름을 방해하기에 충분해 보이죠? 한 가지 주의해야 될 부분은, 함수를 선언할 때도 이 호이스팅이 적용됨&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;sayHi();

function sayHi() {
  console.log('hi');
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 코드를 작성하더라도 실행해보면,&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;hi&lt;/code&gt;&lt;/pre&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>Javascript</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/70</guid>
      <comments>https://minimilab.tistory.com/70#entry70comment</comments>
      <pubDate>Sat, 25 Sep 2021 16:51:53 +0900</pubDate>
    </item>
    <item>
      <title>프로그래밍 핵심 개념 in javascript</title>
      <link>https://minimilab.tistory.com/69</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;프로그래밍 핵심 개념 in javascirpt-001.jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bM9omt/btrfA1x3LGx/YVUf1qnuKGZ8EtwP6kMKdK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bM9omt/btrfA1x3LGx/YVUf1qnuKGZ8EtwP6kMKdK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bM9omt/btrfA1x3LGx/YVUf1qnuKGZ8EtwP6kMKdK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbM9omt%2FbtrfA1x3LGx%2FYVUf1qnuKGZ8EtwP6kMKdK%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;프로그래밍 핵심 개념 in javascirpt-001.jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;해당 내용은 코드잇 '프로그래밍 핵심 개념 in javascript'을 &lt;br /&gt;보면서 정리한 내용입니다. 문제가 될 시 삭제하겠습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;1. 자료형&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 숫자형&lt;/h2&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;// 나머지
console.log(7 % 3); // 1
// 거듭제곱
consloe.log(2 ** 3); // 8
// 덧셈
console.log(1 + 8); // 9
// 뺄셈
console.log(6 - 7); // -1
// 곱셈
console.log(2 * 2 * 2); // 8
// 나눗셈
console.log(5 / 2); // 2.5
// 사칙연산에 맞게 계산 됨
console.log(2 + 3 * 2); // 8
console.log((2 + 3) * 2); // 10&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 문자열 기본&lt;/h2&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;// 문자열
// 문자열은 같은 따옴표로 작성해야 함 
'코드잇'
&quot;코드잇&quot;
console.log('코드잇');
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 문자열 활용&lt;/h2&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;console.log(&quot;He said \&quot;I'm Iron man\&quot;&quot;);
console.log('He said &quot;I\'m Iron man&quot;');
console.log(`He said &quot;I'm Iron man&quot;`);

console.log('3' + '5'); // 35
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. 불대수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AND OR NOT&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명제 : 참과 거짓이 확실한 문장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AND 연산은 두개가 모두 참이어야 참&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OR 연산은 둘 중 하나만 참이어도 참&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NOT 은 반대로 뒤집는 역할&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. 불린형&lt;/h2&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;console.log(2&amp;gt;1); // True
console.log(2&amp;lt;1); // False
// 등호는 항상 부등호 뒤에 써야 함
console.log(3&amp;gt;=2); // true 
console.log(3&amp;lt;=3); // true
console.log(3===3); //  true
consloe.log(3!==3); // false

consloe.log('Codeit' === 'Codeit'); // true

console.log(true &amp;amp;&amp;amp; true); // true 두 값이 모두 true 여서 true
console.log(true || false); // true
console.log(!true); // false
console.log(!!true); // true&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. typeof 연산자&lt;/h2&gt;
&lt;pre id=&quot;code_1632412572204&quot; class=&quot;html xml&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(type of 101); // number
console.log(type of 'Codeit'); // string 
console.log(type of true); // boolean
function sayHello(){
	console.log('Hello'); 
}
console.log(typeof sayHello); // function&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NaN = not a number&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. 형 변환 1&lt;/h2&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;// String, Number, Boolean
console.log('10' + '5');  // 105
console.log(10 + 5);      // 15

console.log(Number('10') + Number('5'));  // 15
console.log(String(10) + String(5));      // 105

// '', 0, NaN은 boolean 시 false가 나옴 &amp;lt;- falsy 라고 부름

Number(true); // 1
Number(false); // 0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;console.log(4+'2'); // 42 한쪽이 문자열일 경우, 양쪽 다 문자열로 변환하여 문자열 덧셈
console.log(4+2);   // 6
console.log(4-true);   // 3
console.log(4*false);   // 0
console.log(4/'2'); // 2 나누기 연산이기 때문에 2가 숫자로 변환되었다고 함 
console.log('4'** true); // 4 true가 1이어서 
console.log(4%'two') // NaN NaN 값은 어떤 값과 연산해도 NaN으로 나옴 

// 관계비교 연산 (&amp;lt;, &amp;lt;=, &amp;gt;, &amp;gt;=)
console.log(2 &amp;lt; '3'); // true
console.log(2 &amp;gt; true); // true
console.log('2' &amp;lt;= false); // false
console.log('two' &amp;gt;= 1); // false

// 같음 비교 연산 
console.log(1 === '1'); // 일치, 불일치(!==) false
console.log(1 === true);  // false
console.log(1 == '1'); // 동등, 부등(!=) true
console.log(1 == true); // true&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;18. 템플릿 문자열&lt;/h2&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;// template: 일정한 틀, 형식
let year = 2018;
let month = 3;
let day = 11;

console.log('생년월일은 ' + year + '년 ' + month + '월 ' + day + ' 일 입니다.');
console.log(`생년월일은 ${year}년 ${month}월 ${day}일 입니다.`);

// 생년월일은 2018년 3월 11일 입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let myNumber = 3;

function getTwice(x) {
    return x * 2;
}

console.log(`${myNumber}의 두 배는 ${getTwice(myNumber)}입니다.`);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;20. null과 undefined&lt;/h2&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;null : 값이 없다는 것을 의도적으로 표현할 때 사용 (의도적인 없음)
undefined : 값이 없다는 것을 확인하는 값 (처음부터 없음)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let codeit;
console.log(codeit); // undifined

codeit = null;
console.log(codeit) // null

console.log(null == undefined); // true
console.log(null === undefined); // false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 추상화&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 할당 연산자&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;let name = '코드잇';
let x = 5;

x = x - 2 ; // 3&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 복합 할당 연산자&lt;/h2&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;// 다음 두 줄은 같습니다
x = x + 1;
x += 1;

// 다음 두 줄은 같습니다
x = x + 2;
x += 2;

// 다음 두 줄은 같습니다
x = x * 2;
x *= 2;

// 다음 두 줄은 같습니다
x = x - 3;
x -= 3;

// 다음 두 줄은 같습니다
x = x / 2;
x /= 2;

// 다음 두 줄은 같습니다
x = x % 7;
x %= 7;

// 다음 세 줄은 같은 의미입니다.
x = x + 1;
x += 1;
x++;

// 다음 세 줄은 같은 의미입니다.
x = x - 1;
x -= 1;
x--;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 함수의 실행 순서&lt;/h2&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;function sayHello() {
    console.log('Hello');
    console.log('welcome to Codeit!');
}

console.log('함수 호출 전');
console.log(sayHello());
console.log('함수 호출 후');&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. return 문 제대로 이해하기&lt;/h2&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;함수 내부에서 return 이 나오면 함수 중단함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;functino square(x) {
    return x * x;
}

conole.log(square(3));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;07. return 과 console.log의 차이&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function printSquare(x) {
    console.log(x * x);
}

function getSquare(x) {
    return x * x;
}

printSquare(3); // 9
getSquare(3); // 아무것도 출력되지 않음
console.log(getSquare(3)); // 9
console.log(printSquare(3)); // undifiend &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. 옵셔널 파라미터&lt;/h2&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function sayHello(name, age, nationality = '한국') {
    console.log(`제 이름은 ${name}입니다.`);
    console.log(`나이는 ${age}살 입니다.`);
    console.log(`국적은 ${nationality}입니다.`);
}

sayHello('미니미', 3); 
// 제 이름은 미니미입니다.
// 나이는 3살 입니다.
// 국적은 한국입니다.&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;function say(family_name, last_name, age=12, nation=&quot;korea&quot;, city=&quot;seoul&quot;)    # O
function say(family_name, age=12, nation=&quot;korea&quot;, city=&quot;seoul&quot;, last_name)    # X&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 변수의 scope&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;scope : 범위, 영역&lt;/li&gt;
&lt;li&gt;모든 변수에는 scope가 있는데 크게 글로벌 변수, 로컬 변수로 나눌 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// Scope: 범위, 영역
let x = 3; // 글로벌 변수, 전역변수 (어디에서나 유효한 범위)

function myFunction() { // 블록문
    let x = 5;  // 로컬 변수, 지역변수 (블록문 내에서만 유효한 범위)
    console.log(x);
}

myFunction(); // 5
console.log(x); // 3 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. 상수&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상수는 const 로 선언함&lt;/li&gt;
&lt;li&gt;상수의 값을 변경하려고 하면 오류가 남&lt;/li&gt;
&lt;li&gt;변수명은 대문자로 사용 (ex) MY_NUMBER&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 상수 
const PI = 3.14; // 원주율
let radius = 0;    // 반지름

// 원의 넓이를 계산하는 함수
function calculateArea() {
    return PI * radius * radius;
}

// 반지름에 따른 원의 넓이를 출력하는 함수
function printArea() {
    return `반지름이 ${radius}일 때, 원의 넓이는 ${calcaulateArea()}`;
}

radius = 4;
console.log(printArea());

radius = 7;
console.log(printArea());

radius = 8;
console.log(printArea());
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 제어문&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. if문&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;// 파라미터 height을 활용하는 checkHeight 함수를 완성하세요.
function checkHeight(height) {
    // 여기에 코드를 작성해 주세요.
    if (height &amp;gt;= 140){
      console.log('탑승이 가능합니다.')
    }
    else {
      console.log('탑승이 불가능합니다.')
    }
}

// 테스트 코드
checkHeight(141); // 탑승이 가능합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. else if 문&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let temperature = 140;

if (temperature &amp;lt;= 0) {
    console.log('물이 업니다.');
} else {
    if (temperature &amp;lt; 100) {
        console.log('물이 얼지도 끓지도 않습니다.');
    } else {
        console.log('물이 끓습니다.');
    }
}
// 물이 끓습니다.

if (temperature &amp;lt;= 0) {
    console.log('물이 업니다.');
} else if (temperature &amp;lt; 100) {
    console.log('물이 얼지도 끓지도 않습니다.');
} else if (temperature &amp;lt; 150) {
    console.log('물이 끓습니다.');
} else {
    console.log('물이 모두 수증기가 되었습니다.');
}
// 물이 끓습니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. swtich 문&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조건에 일치하는 case를 찾고, break문이 없다면, 해당 조건에 일치하는 case 뒤로 전부 실행이 됨&lt;/li&gt;
&lt;li&gt;break 문이 있다면, 조건을 만나면 뒤의 조건을 실행하지 않고 빠져나옴&lt;/li&gt;
&lt;li&gt;if문과 switch문 모두 특정한 조건에 따라 다르게 동작하는 코드를 만들 수 있지만, 어떤 넓은 범위를 만족하는 조건식을 만들 때는 if문을 활용하는 것이 좀 더 효과적이고 특정한 값에 일치하는 조건을 만들 때는 switch문이 좀 더 효과적임&lt;/li&gt;
&lt;li&gt;switch문은 값들을 비교할 때 자료형을 엄격하게 구분한다는 것과 if문으로 대체할 때는 반드시 등호 3개로 일치비교를 해야한다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;switch (비교할_값) {
    case 조건값_1:
        동작부분;
        break;     // switch 문을 빠져나옴
    case 조건값_2:
        동작부분;
        break;
    default:    // if else에서, else와 같은 의미
        동작부분;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let myChoice = 2;

switch(myChoice) {
    case 1:
        console.log('토끼를 선택한 당신...');
        break;
    case 2:
        console.log('고양이를 선택한 당신...');
        break;
    default:
        console.log('1에서 4사이의 숫자를 선택해 주세요.';
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;09. for문&lt;/h2&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;// 반복문
// 초기화부분은 딱 1번만 실행됨
// 조건부분이 만족되면, 추가동작부분을 실행함

for (초기화부분; 조건부분; 추가동작부분) {
    동작부분
}

for (let i = 1; i &amp;lt;= 10; i++){
    console.log(`${i} 코드잇 최고!`);
}

// 출력결과
// 1 코드잇 최고!
// 2 코드잇 최고!
...
// 10 코드잇 최고!&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;for (let i = 1; i &amp;lt;= 10;) {
  console.log(`${i} 코드잇 최고!`);
  i++;
}&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;let i = 1; 
for (; i &amp;lt;= 10; i++) {
  console.log(`${i} 코드잇 최고!`);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;function printTriangle(height) {
    let stars = '';
    for (let i = 1; i &amp;lt;=height; i ++) {
      stars = stars + '*';
      console.log(stars)
    }
}

// 출력 결과
높이: 1
*
높이: 3
*
**
***
높이: 5
*
**
***
****
*****&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. while 문&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;while (조건부분) {
    동작부분
}

let i = 1;
while (i &amp;lt;= 10) {
    console.log(`${i} minimi 최고!`);
    i ++;
}

for (let i = 1; i &amp;lt;=10; i++) {
    console.log(`${i} minimi 최고!` );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;let i = 30;

while (i % 7 !== 0){ // 조건이 true일 때만 동작하므로, 7의 배수가 되는 순간 동작을 멈춤
    i++;
}

conole.log(i); // 35&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;16. break와 continue&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;break 문을 만나면 반복문을 빠져나옴&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;let i = 1;

while (i &amp;lt;= 10) {
    console.log(i);
    if (i === 7) {
        break;
    }
    i++;
}

for (let i = 1; i &amp;lt;=10; i ++){
    console.log(i);
    if (i === 7){
        break;
    }
}

// 출력결과
1
2
3
4
5
6
7
1
2
3
4
5
6
7&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;continue는 동작을 건너띔&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;for (let i = 1; i &amp;lt;=10; i ++){
    if (i % 2 === 0){
        continue;
    }
    console.log(i);
}

// 출력결과
1
3
5
7
9

let i = 1;
while(i &amp;lt;= 10) {
    if (i % 2 === 0) {
        i ++;
        continue;
    }
    console.log(i);
    i++;

}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Javascript</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/69</guid>
      <comments>https://minimilab.tistory.com/69#entry69comment</comments>
      <pubDate>Fri, 24 Sep 2021 00:56:24 +0900</pubDate>
    </item>
    <item>
      <title>HTTPS 사용 이유와 동작방식</title>
      <link>https://minimilab.tistory.com/68</link>
      <description>&lt;h1&gt;HTTPS 사용 이유와 동작방식&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (4).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2y9um/btrfi3gXMb1/kFCEt97UKYJQkhsJRbBsT1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2y9um/btrfi3gXMb1/kFCEt97UKYJQkhsJRbBsT1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2y9um/btrfi3gXMb1/kFCEt97UKYJQkhsJRbBsT1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2y9um%2Fbtrfi3gXMb1%2FkFCEt97UKYJQkhsJRbBsT1%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (4).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;1. HTTPS를 사용하는 이유&lt;/h1&gt;
&lt;h2&gt;1-1. 웹사이트에서 주고 받는 정보를 암호화합니다.&lt;/h2&gt;
&lt;p&gt;HTTP는 서버에서부터 브라우저로 전송되는 정보가 암호화되지 않습니다.&lt;br&gt;HTTP는 정보를 단순 텍스트로 주고 받기 때문에 네트워크에서 전송 신호를 인터셉트 하는 경우 원하지 않는 데이터 유출이 발생할 수 있습니다.&lt;/p&gt;
&lt;p&gt;예를들어, 네트워크를 공동으로 쓰는 PC방, 회사, 학교 등에서 간단한 스니핑툴로 로그인, 회원가입, 예약 등의 개인정보를 입력할 때 정보를 훔쳐 볼 수 있습니다.&lt;br&gt;하지만 HTTPS 는 통신 시에 정보를 암호화해주기 때문에, 아래 그림에서와 같이 해커가 중간에 정보를 훔쳐보아도 암호화되어 있어 정보를 알 수 없습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;645&quot; data-filename=&quot;이미지 8.jpg&quot; width=&quot;400&quot; height=&quot;297&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3PBb9/btrficrU2NF/XUYxbkpLy6zezV29ZrSQ1K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3PBb9/btrficrU2NF/XUYxbkpLy6zezV29ZrSQ1K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3PBb9/btrficrU2NF/XUYxbkpLy6zezV29ZrSQ1K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3PBb9%2FbtrficrU2NF%2FXUYxbkpLy6zezV29ZrSQ1K%2Fimg.jpg&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;645&quot; data-filename=&quot;이미지 8.jpg&quot; width=&quot;400&quot; height=&quot;297&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;1-2. 접속하는 사이트가 신뢰할 수 있는 사이트인지를 알려줍니다.&lt;/h2&gt;
&lt;p&gt;사이트가 정품인지를 판별할 수 있도록 인증해주는 엄격한 인증과정을 거친 공인된 민간기업을 CA (Certificate Authority) 라고 부릅니다.&lt;br&gt;HTTPS 사이트는 CA (Certificate Authority) 에 인증을 받습니다.&lt;/p&gt;
&lt;p&gt;브라우저 (크롬이나 사파리, 파이어폭스,엣지, 익스플로러 등)에는 CA 의 리스트와 공개키를 보유하고 있어서, 사용하는 사이트의 신원을 보장해주어 신뢰하고 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;참고 : &lt;a href=&quot;https://aws-hyoh.tistory.com/59&quot;&gt;https://aws-hyoh.tistory.com/59&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;1-3. HTTPS 사용 시 검색엔진 최적화(SEO) 에 있어서 혜택을 볼 수 있습니다.&lt;/h2&gt;
&lt;p&gt;사람들이 안전하다고 생각하는 사이트를 더 많이 방문하기도 하고,&lt;br&gt;구글이 HTTPS 웹 사이트 SEO 품질에 더 가산점을 주기 때문에 검색엔진 최적화(SEO)에 있어서 혜택을 볼 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;2. HTTPS 와 비대칭키&lt;/h1&gt;
&lt;p&gt;HTTPS 는 암호화하여 사용할 수 있도록 비대칭키, 또는 공개키라 불리는 시스템을 사용합니다.&lt;br&gt;여기에는 한 쌍으로 이루어진 A키와 B키를 사용합니다.&lt;br&gt;각각의 키가 서로 다르기 때문에 &amp;#39;비대칭키&amp;#39;라고 불립니다.&lt;br&gt;A키로 암호화를 하면 B키로만 복호화할 수 있습니다.&lt;br&gt;반대로 B키로 암호화를 하면 A키로만 풀 수 있습니다.&lt;/p&gt;
&lt;p&gt;이 원리를 적용하여, CA (Certificate Authority) 기업은 공개키와 개인키를 만듭니다.&lt;br&gt;개인키는 웹 서버(ex 네이버 사이트의 서버)에 비밀로 보관하고, 공개키는 브라우저에 공개합니다.&lt;br&gt;사용자는 공개키로 비밀번호를 암호화해서 웹 서버(ex 네이버 사이트의 서버)에 보냅니다.&lt;br&gt;중간에서 해커들이 공개키를 가로채도 안전한 이유는 이 정보를 해독할 수 있는 것은 개인키를 가진 웹 서버(ex 네이버 사이트의 서버) 뿐이기 때문입니다.&lt;/p&gt;
&lt;p&gt;또한 반대로, 웹 서버에서 우리에게 보내는 정보들은 그 일부가 개인키로 암호화가 되어 있습니다.&lt;br&gt;우리가 브라우저에 저장된 CA의 공개키로 풀어서 알아볼 수 있는 것은 웹 서버에서 보낸 개인키와 일치하기 때문이므로 안전하게 사이트를 이용할 수 있습니다.&lt;br&gt;일치하지 않는 다면 이상한 사이트에서 보내는 것이기 때문에 오류가 날 것이기 때문입니다.&lt;/p&gt;
&lt;p&gt;참고 : &lt;a href=&quot;https://www.youtube.com/watch?v=H6lpFRpyl14&quot;&gt;https://www.youtube.com/watch?v=H6lpFRpyl14&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;3. HTTPS 적용 시 통신 흐름&lt;/h1&gt;
&lt;p&gt;1. 어플리케이션 서버(A)를 만든 기업은 HTTPS를 적용하기 위해 개인키와 공개키를 만듭니다.&lt;br&gt;2. A 기업은 신뢰할 수 있는 CA를 선택해 공개키를 관리해달라고 계약합니다.&lt;br&gt;3. CA기업은 CA기업만의 공개키와 개인키를 가지고 있다. CA기업은 CA기업의 이름, A 기업의 공개키, 공개키의 암호화 방법 등의 정보를 담은 인증서를 발급하고, 발급한 인증서를 CA 기업의 개인키로 암호화해서 A 기업에 제공합니다.&lt;br&gt;4. A 기업은 클라이언트로부터 암호화된 HTTPS 요청이 아닌 요청이 들어왔을 때 암호화된 인증서를 전송합니다.&lt;br&gt;5. CA 기업의 공개키는 브라우저가 이미 알고있기 때문에 클라이언트는 CA 기업의 공개키로 서버로부터 전달받은 인증서를 복호화하고, 이를 통해 A 기업의 공개키를 얻을 수 있습니다.&lt;br&gt;6. 그 뒤로는 클라이언트가 A 기업의 서버와 통신할 때는 A 기업의 공개키로 암호화해서 Request를 날릴 수 있게 됩니다.&lt;/p&gt;
&lt;p&gt;출처 : &lt;a href=&quot;https://dev-mb.tistory.com/159&quot;&gt;https://dev-mb.tistory.com/159&lt;/a&gt;&lt;/p&gt;</description>
      <category>Linux</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/68</guid>
      <comments>https://minimilab.tistory.com/68#entry68comment</comments>
      <pubDate>Thu, 16 Sep 2021 23:16:50 +0900</pubDate>
    </item>
    <item>
      <title>Nginx Reverse Proxy 란?</title>
      <link>https://minimilab.tistory.com/67</link>
      <description>&lt;h1&gt;1. Forward Proxy,&amp;nbsp; Reverse Proxy 란?&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (3).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciS7ck/btrfdXANB7g/koowquHPKJlP3d4vtaTVl0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciS7ck/btrfdXANB7g/koowquHPKJlP3d4vtaTVl0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciS7ck/btrfdXANB7g/koowquHPKJlP3d4vtaTVl0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciS7ck%2FbtrfdXANB7g%2FkoowquHPKJlP3d4vtaTVl0%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (3).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-1. Forward Proxy 란?&lt;/p&gt;
&lt;/blockquote&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;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;/li&gt;
&lt;li&gt;직원 온라인 활동 모니터링&lt;/li&gt;
&lt;li&gt;클라이언트의 IP 주소를 위장하고 들어오는 악성 트래픽이 원본 서버에 도달하지 못하도록 차단&lt;/li&gt;
&lt;li&gt;외부 사이트 콘텐츠를 캐싱하여 사용자 경험 개선&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;301&quot; data-filename=&quot;forward.jpg&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzCTJe/btrfc7KtOA9/7Dpte9loFgSlx2qxNJ5QUk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzCTJe/btrfc7KtOA9/7Dpte9loFgSlx2qxNJ5QUk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzCTJe/btrfc7KtOA9/7Dpte9loFgSlx2qxNJ5QUk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzCTJe%2Fbtrfc7KtOA9%2F7Dpte9loFgSlx2qxNJ5QUk%2Fimg.jpg&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;301&quot; data-filename=&quot;forward.jpg&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-2. Reverse Proxy 란?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다수의 서버를 Reverse Proxy 서버 하단부에 위치시켜 두고,&lt;br /&gt;특정 조건(일치하는 도메인 혹은 주소)에 맞는 요청을 적절한 서버에게 전달해주는 역할을 수행하는 것이 Reverse Proxy이다.&lt;br /&gt;클라이언트는 Reverse Proxy 서버에게 요청하기 때문에 실제 서버의 정보를 알 수가 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;296&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F7g3u/btrfcwcB8RQ/fBxYip4o1yg30eebk0pkr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F7g3u/btrfcwcB8RQ/fBxYip4o1yg30eebk0pkr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F7g3u/btrfcwcB8RQ/fBxYip4o1yg30eebk0pkr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF7g3u%2FbtrfcwcB8RQ%2FfBxYip4o1yg30eebk0pkr0%2Fimg.png&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;296&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;2. 적용방법&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-1. Reverse Proxy 적용방법&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;http {
    upstream minimilab{
        server 127.0.0.1:8000 weight=3;
        server 127.0.0.1:8001;
        server 127.0.0.1:8002;
        server 127.0.0.1:8003;
    }

    server {
        listen 80;
        server_name www.minimilab.com;
        location / {
            proxy_pass http://minimilab;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-2. Load balancing methods (부하 부산 규칙)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;round-robin(디폴트) - 돌아가면서 분배한다.&lt;/li&gt;
&lt;li&gt;ip_hash - 같은 방문자로부터 도착한 요청은 항상 같은 업스트림 서버가 처리 할 수 있게 한다.&lt;/li&gt;
&lt;li&gt;random - 랜덤으로 분배한다.&lt;/li&gt;
&lt;li&gt;least_conn - 연결수가 가장 적은 서버를 선택해서 분배한다.&lt;/li&gt;
&lt;li&gt;least_time - 연결수가 가장 적으면서 평균 응답시간이 가장 적은 쪽을 선택해서 분배한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;upstream backend {
    least_conn ;
    server 127.0.0.1:8080;
    server 127.0.0.2:8081;
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-3. option&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;weight=n : 업스트림 서버의 비중을 나타낸다. 이 값을 2로 설정하면 그렇지 않은 서버에 비해 두배 더 자주 선택된다.&lt;/li&gt;
&lt;li&gt;max_fails=n : 서버와의 통신 시도 실패 횟수를 설정한다. n으로 지정한 횟수만큼 fail_timeout 의 시간만큼의 실패가 일어나면 서버가 죽은 것으로 간주한다.&lt;/li&gt;
&lt;li&gt;fail_timeout=n : max_fails가 지정된 상태에서 이 값이 설정만큼 서버가 응답하지 않으면 죽은 것으로 간주한다.&lt;/li&gt;
&lt;li&gt;backup : 메인 서버가 모두 동작하지 않을 때에만 backup으로 지정된 서버를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;upstream backend {
    server backend1.example.com:12345  weight=5;
    server backend2.example.com:12345 backup;
}

server {
    listen 12346;
    proxy_pass backend;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://nginx.org/en/docs/stream/ngx_stream_upstream_module.html&quot;&gt;http://nginx.org/en/docs/stream/ngx_stream_upstream_module.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://opentutorials.org/module/384/4328&quot;&gt;https://opentutorials.org/module/384/4328&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://nginx.org/en/docs/http/ngx_http_proxy_module.html&quot;&gt;http://nginx.org/en/docs/http/ngx_http_proxy_module.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://www.imperva.com/learn/performance/reverse-proxy/&quot;&gt;https://www.imperva.com/learn/performance/reverse-proxy/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Linux</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/67</guid>
      <comments>https://minimilab.tistory.com/67#entry67comment</comments>
      <pubDate>Wed, 15 Sep 2021 21:18:52 +0900</pubDate>
    </item>
    <item>
      <title>Nginx란? 기본 설정 파일 및 사용 방법</title>
      <link>https://minimilab.tistory.com/66</link>
      <description>&lt;h1&gt;Nginx란? 기본 설정 파일 및 사용 방법&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;nginx란_-001.jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zWLJS/btreJn3bkrm/v8y3YjKAQJ2dJo0ZGhata0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zWLJS/btreJn3bkrm/v8y3YjKAQJ2dJo0ZGhata0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zWLJS/btreJn3bkrm/v8y3YjKAQJ2dJo0ZGhata0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzWLJS%2FbtreJn3bkrm%2Fv8y3YjKAQJ2dJo0ZGhata0%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;nginx란_-001.jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;1. Nginx 란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx는 가벼운 고성능의 웹서버로서 높은 트래픽 처리를 위해 만들어졌습니다.&lt;br /&gt;예를들어 Apache의 경우는 접속마다 Process 또는 Thread를 생성하는 구조로, 1만명이 동시접속을 하면 그 만큼 Process or Thread 생성비용이 들 것이고 대용량 요청을 처리할 수 있는 웹서버로서의 한계를 드러냅니다.&lt;br /&gt;하지만 Nginx는 한 개 또는 고정된 프로세스만 생성 하고, 그 프로세스 내부에서 비동기 방식으로 효율적으로 작업을 처리합니다.&lt;br /&gt;따라서 동시 접속 요청이 많아도 Process 또는 Thread 생성 비용이 존재하지 않아서 높은 트래픽 처리에 유리한 웹서버입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h1&gt;2. Nginx 기본 설정 파일 위치&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 설정 파일 명 : nginx.conf&lt;/li&gt;
&lt;li&gt;기본 설정 파일 위치
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ubuntu APT 패키지를 통해서 설치했다면, /etc/nginx 디렉토리에 위치&lt;/li&gt;
&lt;li&gt;컴파일로 설치 했다면, /usr/local/nginx 디렉토리에 위치&lt;/li&gt;
&lt;li&gt;기본 설정파일이 어디에 위치하는지 모르겠다면, find / -name nginx.conf&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h1&gt;3. nginx.conf 파일 설정 방법 및 사용방법&lt;/h1&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;# 3-1. core 모듈 설정
user  nginx nginx;
worker_processes  1;

events {
          # 3-2. events 블록 
          worker_connections 512;
}

http {
            # 3-3. http 블록 
            include /etc/nginx/mime.types;
            default_type application/octet-stream;
            keepalive_timeout                60;
            log_format main '$remote_addr - $remote_user [$time_local] &quot;$request&quot; '
                                            '$status $body_bytes_sent &quot;$http_referer&quot; '
                                            '&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;';
            access_log /var/log/nginx/access.log main;

            server {
                       # 3-4. server 블록 
                       . . .
                            location {
                                           # 3-5. location 블록 
                                           . . .
                            }
            }

            include /etc/nginx/conf.d/*.conf;

}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3-1. C&lt;b&gt;ore 모듈 설정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 파일 최상단에 위치하며 nginx의 프로세스 관리, 보안과 같은 기본적인 동작 방식을 정의합니다.&lt;br /&gt;core 모듈의 다양한 지시어는 &lt;a href=&quot;http://nginx.org/en/docs/ngx_core_module.html&quot;&gt;http://nginx.org/en/docs/ngx_core_module.html&lt;/a&gt; 에서 확인할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;user&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업자 프로세스가 어떤 user, group으로 실행되는지에 대한 설정입니다. user root root; 로 할 경우 작업자 프로세스가 파일 시스템의 모든 권한을 사용하게 되므로 보안상 위험합니다.&lt;br /&gt;별도의 사용자 계정(ex : user nginx nginx;)를 만드는 것이 좋습니다.&lt;br /&gt;아래의 Syntax 예시에서 [group]을 생략할 수 있으며, 생략하면 user가 대신 사용됩니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Syntax:    user user [group];
Default:  user nobody nobody;&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;worker_process&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업자 프로세스(worker process)의 수를 정의합니다. (Nginx는 하나의 master process와 여러개의 worker process로 구성되어 실행됩니다. master process는 설정파일을 읽고, worker process를 유지 및 관리합니다. 모든 요청은 worker process에서 처리합니다. master process에서는 어떤 클라이언트 요청도 처리하지 않습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 CPU 코어 수 만큼 할당하는 것이 좋으며, 확실하지 않은 경우 auto 를 입력하여 자동 감지를 시도할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;scss&quot;&gt;&lt;code&gt;Syntax:    worker_processes number | auto;
Default:  worker_processes 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 : CentOS 에서는 cat /proc/cpuinfo | grep processor 로 cpu core 수를 확인할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3-2. &lt;b&gt;events 블록&lt;/b&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;worker_connections&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한개의 작업자 프로세스(worker process)가 동시에 처리할 수 있는 커넥션의 수를 말합니다.&lt;br /&gt;작업자 프로세스(worker process)가 4개라면, worker_process(4) X worker_connections(512) = 2048 로 총 2048개 커넥션이 최대 동시에 처리할 수 있습니다.&lt;br /&gt;이 숫자에는 클라이언트와의 연결 뿐만 아니라 프록시 서버와의 연결 등도 포함된다는 점에 유의해야 합니다.&lt;/p&gt;
&lt;pre class=&quot;scss&quot;&gt;&lt;code&gt;Syntax:    worker_connections number;
Default:  worker_connections 512;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3-3. &lt;b&gt;http 블록&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http 블록은 server, location 의 루트 블록입니다. http 블록에서 설정된 내용은 server의 기본값이 되고, server의 지시어는 location의 기본값이 됩니다.&lt;br /&gt;http블록 안에 한 개 이상의 server 블록을 선언할 수 있으며, server 블록 안에서 한 개 이상의 location 블럭을 삽입할 수 있습니다.&lt;br /&gt;그리고 하위의 블록에서 선언된 지시어는 상위의 선언을 무시하고 적용됩니다.&lt;br /&gt;http 블록은 여러개를 사용할 수 있지만 관리상의 이슈로 한번만 사용하는 것을 권장됩니다.&lt;br /&gt;http 관련된 지시어는 &lt;a href=&quot;http://nginx.org/en/docs/http/ngx_http_core_module.html#tcp_nopush&quot;&gt;http://nginx.org/en/docs/http/ngx_http_core_module.html&lt;/a&gt; 에서 확인할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;include&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http 블록에서 include 지시어를 사용할 수 있으며, include는 특정 파일을 포함하는 기능을 수행합니다. include 지시어가 있는 위치에 해당 파일 내용이 삽입됩니다.&lt;br /&gt;include 된 파일 안에서 또 다른 파일을 include할 수 있으며, 순차적으로 처리됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;default_type&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 웹서버의 기본 Content-Type을 설정합니다. octet-stream은 바이너리 형태의 타입을 의미합니다. 일반적으로 nginx에서 해석할 수 없는 타입이라면 요청을 기본 타입으로 요청을 받도록 설정됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;keepalive_timeout&lt;/li&gt;
&lt;/ul&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;log_format&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그 포맷을 설정합니다. $로 시작하는 것은 변수고 변수와 관련된 내용은 &lt;a href=&quot;http://nginx.org/en/docs/varindex.html&quot;&gt;http://nginx.org/en/docs/varindex.html&lt;/a&gt; 확인할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;access_log&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;access 로그를 저장할 파일을 지정합니다.&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;access_log logs/access.log [context];
# access_log logs/access.log main;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3-4. &lt;b&gt;server 블록&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 서버(한 개의 ip)에서 각각의 도메인에 따라서 서로 다른 페이지를 서비스할 수 있습니다.&lt;br /&gt;예를들어, 서로 다른 도메인 (minimilab-zzang.com과 minimilab.com) 을 한 서버에서 서로 다른 페이지를 서비스 하도록 할 수 있습니다.&lt;br /&gt;minimilab-zzang.com 도메인으로 요청이 들어오면 /var/www/minimilab-zzang.com 위치의 페이지를 서비스 하도록 하며,&lt;br /&gt;minimilab.com 도메인으로 요청이 들어오면 /var/www/minimilab.com 위치에서 페이지를 서비스 합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;server {
    server_name  minimilab-zzang.com;
    root /var/www/minimilab-zzang.com
}

server {
    server_name  minimilab.com
    root /var/www/minimilab.com
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;include는 지시어는 server 블록 내에서도 사용할 수 있습니다.&lt;br /&gt;server 블록은 여러개 사용이 가능하며, 와일드카드(*) 와 정규식 사용이 가능합니다.&lt;br /&gt;server 블록을 여러개 사용할 경우 다음과 같은 우선순위에 따라서 선택됩니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정확한 이름&lt;/li&gt;
&lt;li&gt;별표로 시작하는 가장 긴 와일드카드 이름(예: *.example.org)&lt;/li&gt;
&lt;li&gt;별표로 끝나는 가장 긴 와일드카드 이름(예: example.*)&lt;/li&gt;
&lt;li&gt;첫 번째 일치하는 정규식(구성 파일에 나타나는 순서대로)
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt; server {
     listen       80;
     server_name  example.org  www.example.org;
     ...
 }

 server {
     listen       80;
     server_name  *.example.org;
     ...
 }

 server {
     listen       80;
     server_name  mail.*;
     ...
 }

 server {
     listen       80;
     server_name  ~^(?&amp;lt;user&amp;gt;.+)\.example\.net$;
     ...
 }&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;정규식을 사용하려면 server_name이 ~ 로 시작해야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server_name 관련 내용은 &lt;a href=&quot;https://nginx.org/en/docs/http/server_names.html&quot;&gt;https://nginx.org/en/docs/http/server_names.html&lt;/a&gt; 에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 : &lt;a href=&quot;https://deeplify.dev/server/web/nginx-configuration&quot;&gt;https://deeplify.dev/server/web/nginx-configuration&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3-5. &lt;b&gt;location 블록&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;location 블록은 server 블록 안에서 사용하며, 여러개를 사용할 수 있습니다.&lt;br /&gt;location 블록에도 정규식으로 사용할 수 있으며 ~ 문자가 올 경우 정규식을 사용하며, 대소문자를 구분합니다. 대소문자 구분없이 사용하려면 ~* 를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://minimilab.com&quot;&gt;http://minimilab.com&lt;/a&gt; 으로 요청이 들어오면, nginx 가 기본적으로 설치된 /etc/nginx/ 위치에 더해 root 설정인 html 과 index 설정을 더해 /etc/nginx/html/inex.html 의 내용을 보여줍니다.&lt;br /&gt;&lt;a href=&quot;http://minimilab.com&quot;&gt;http://minimilab.com&lt;/a&gt;/something/test/ 로 요청이 들어오면, root에 설정되어 있는 /home/test 의 내용을 보여줍니다.&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;server {
        listen 80;
        server_name  minimilab.com

        location / {
            root html;
            index index.html index.htm;
        }

        location ~* ^/(.*)/test/ {
            root /home/test;
        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 : &lt;a href=&quot;https://architectophile.tistory.com/12&quot;&gt;https://architectophile.tistory.com/12&lt;/a&gt;&lt;/p&gt;</description>
      <category>Linux</category>
      <category>nginx</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/66</guid>
      <comments>https://minimilab.tistory.com/66#entry66comment</comments>
      <pubDate>Sun, 12 Sep 2021 17:37:44 +0900</pubDate>
    </item>
    <item>
      <title>Swap 이란? Swap 설정방법</title>
      <link>https://minimilab.tistory.com/65</link>
      <description>&lt;h1&gt;Swap 이란? Swap 설정방법&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001.jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0YMAG/btreJwL9IYG/Kagk7TyVAzcwd8hpB8WeKk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0YMAG/btreJwL9IYG/Kagk7TyVAzcwd8hpB8WeKk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0YMAG/btreJwL9IYG/Kagk7TyVAzcwd8hpB8WeKk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0YMAG%2FbtreJwL9IYG%2FKagk7TyVAzcwd8hpB8WeKk%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001.jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Swap 이란?&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;swap 이란 메모리가 부족할 경우 하드 디스크의 여유 공간을 활용하여 RAM 처럼 사용할 수 있도록 만드는 것을 말합니다.&lt;/li&gt;
&lt;li&gt;디스크를 SSD 를 사용한다고 하더라도, RAM보다는 속도가 느리므로 swap 을 사용하게 되면 처리속도가 떨어집니다.&lt;/li&gt;
&lt;li&gt;swap 영역은 메모리가 부족한 경우 하드디스크에서 사용하게 되므로, 이 때문에 불필요한 I/O가 생겨 시스템의 성능이 저하될 수 있습니다.&lt;/li&gt;
&lt;li&gt;swap 영역의 크기를 동적으로 조정할 수 없어 하드디스크의 공간을 차지하게 됩니다.&lt;/li&gt;
&lt;li&gt;swap영역을 사용한다는 것은 시스템의 메모리가 부족하다는 의미이며, 이는 프로세스의 메모리 누수이거나 실제로 필요한 메모리가 부족하다는 뜻입니다.
&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;평상시에는 사용하는 메모리의 양이 일정 수준을 유지하고 있다가 순간적으로 요청이 증가하면서 메모리의 사용량이 폭증해서 swap을 사용하게 된는 경우에는 swap을 사용하는 것도 방법이 될 수 있습니다. 안정적인 서비스를 위해서는 사용한 메모리의 최대치를 계산해서 메모리를 증설을 생각해볼 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Swap 설정방법&lt;/h2&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;# ubuntu 20.04 에서 swap 설정방법

# swap 을 8GB로 조정
~# fallocate -l 8G /swapfile

# swapfile 권한 설정
~# chmod 600 /swapfile

# swap file 만들기
~# mkswap /swapfile

# swap file 활성화 : 리부팅하지 않아도 swap file이 활성화
~# swapon /swapfile

# /etc/fstab 을 수정해서 swap file을 마운트 
~# vi /etc/fstab 을 열어서 내용 추가  
swapfile none swap sw 0 0

# swap total 에 지정이 제대로 되었는지 확인
~# free -m&lt;/code&gt;&lt;/pre&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;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jihooyim1.gitbooks.io/linuxbasic/content/contents/05.html&quot;&gt;https://jihooyim1.gitbooks.io/linuxbasic/content/contents/05.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://kibua20.tistory.com/40&quot;&gt;https://kibua20.tistory.com/40&lt;/a&gt;&lt;/p&gt;</description>
      <category>Linux</category>
      <category>swap</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/65</guid>
      <comments>https://minimilab.tistory.com/65#entry65comment</comments>
      <pubDate>Sat, 11 Sep 2021 11:46:54 +0900</pubDate>
    </item>
    <item>
      <title>Redis cannot allocate memory</title>
      <link>https://minimilab.tistory.com/64</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Redis cannot allocate memory&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; data-filename=&quot;redis-logo.png&quot; width=&quot;300&quot; height=&quot;225&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mazM5/btrdOYb2tIP/feAdJS3NvdFM71ygfyUDX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mazM5/btrdOYb2tIP/feAdJS3NvdFM71ygfyUDX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mazM5/btrdOYb2tIP/feAdJS3NvdFM71ygfyUDX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmazM5%2FbtrdOYb2tIP%2FfeAdJS3NvdFM71ygfyUDX0%2Fimg.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; data-filename=&quot;redis-logo.png&quot; width=&quot;300&quot; height=&quot;225&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 에러 상황&lt;/h2&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;12:M 27 Aug 16:20:23.500 * Starting BGSAVE for SYNC with target: disk
12:M 27 Aug 16:20:23.500 # Can't save in background: fork: Cannot allocate memory
12:M 27 Aug 16:20:23.500 # BGSAVE for replication failed
12:M 27 Aug 16:20:29.083 * 1 changes in 900 seconds. Saving...
12:M 27 Aug 16:20:29.084 # Can't save in background: fork: Cannot allocate memory
12:M 27 Aug 16:20:35.094 * 1 changes in 900 seconds. Saving...
12:M 27 Aug 16:20:35.095 # Can't save in background: fork: Cannot allocate memory
12:M 27 Aug 16:20:41.009 * 1 changes in 900 seconds. Saving...
12:M 27 Aug 16:20:41.009 # Can't save in background: fork: Cannot allocate memory&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 에러 발생이유 및 해결방법&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2-1. 에러 발생 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis는 In-memory database 여서, data를 memory 에 저장한다.&lt;br /&gt;사용 가능한 memory 대비 data가 커지면 위와 같은 에러가 발생했다.&lt;br /&gt;저장되는 data 크기를 줄이거나, memory 크기를 늘려서 해결하는 것이 좋다.&lt;br /&gt;여건이 안될 때는 vm.overcommit_memory 설정을 줄 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2-2. vm.overcommit_memory 옵션 의미&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0 : 기본값
&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;메모리가 부족한 상황이라면 서비스를 OOM(out of memory)으로 Kill 하는 편이 좋다고 판단될 경우, 프로세스를 종료시켜 여유 메모리를 확보함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;1：항상 overcommit함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;overcommit을 제한하지 않는다.&lt;/li&gt;
&lt;li&gt;메모리가 부족한 상황속에서 다소 느리더라도 서비스가 계속 되어야 하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;2 : overcommit 하지 않음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;swap총량 + 물리메모리총량 * vm.overcommit_ratio/100&lt;/code&gt; 의 값을 계산하여 메모리가 이보다 넘어설 경우 메모리 할당을 거부한다.&lt;/li&gt;
&lt;li&gt;vm.overcommit_ratio 를 설정해서 메모리를 얼마까지 사용할 것인지 지정할 수 있다. 기본 값을 50이며 /etc/sysctl.conf 에서 설정 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2-3. 적용방법&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ sudo vi /etc/sysctl.conf
vm.overcommit_memory = 1&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;sysctl vm.overcommit_memory=1&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://linux.systemv.pe.kr/redis-%EC%9A%B4%EC%98%81%EC%97%90-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9E%A1%EC%A7%80%EC%8B%9D%EB%93%A4/&quot;&gt;https://linux.systemv.pe.kr/redis-운영에-필요한-잡지식들/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://jinhokwon.github.io/redis/redis-optimize/&quot;&gt;https://jinhokwon.github.io/redis/redis-optimize/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://charsyam.wordpress.com/2021/04/14/%EC%9E%85-%EA%B0%9C%EB%B0%9C-redis%EA%B0%80-maxmemory-%EB%B3%B4%EB%8B%A4-%EB%8D%94-%EC%8D%BC%EB%8B%A4%EA%B0%80-oom-%EC%97%90%EB%9F%AC%EB%A5%BC-%EB%8D%98%EC%A0%B8%EC%9A%94/&quot;&gt;https://charsyam.wordpress.com/2021/04/14/입-개발-redis가-maxmemory-보다-더-썼다가-oom-에러를-던져요/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://jujupapa.tistory.com/37&quot;&gt;https://jujupapa.tistory.com/37&lt;/a&gt;&lt;/p&gt;</description>
      <category>Rabbitmq,Redis</category>
      <category>Redis</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/64</guid>
      <comments>https://minimilab.tistory.com/64#entry64comment</comments>
      <pubDate>Thu, 2 Sep 2021 22:59:47 +0900</pubDate>
    </item>
    <item>
      <title>Rabbitmq memory resource limit alarm</title>
      <link>https://minimilab.tistory.com/63</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;238&quot; data-filename=&quot;images.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lg5LC/btrdOwk6b6D/jraHky5twYAOz0yONXO971/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lg5LC/btrdOwk6b6D/jraHky5twYAOz0yONXO971/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lg5LC/btrdOwk6b6D/jraHky5twYAOz0yONXO971/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flg5LC%2FbtrdOwk6b6D%2FjraHky5twYAOz0yONXO971%2Fimg.png&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;238&quot; data-filename=&quot;images.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Rabbitmq memory resource limit alarm&lt;/h1&gt;
&lt;h1&gt;1. 에러상황&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;**********************************************************

=WARNING REPORT==== 08-Aug-2021::01:45:05 ===
memory resource limit alarm cleared on node 'rabbit@rabbitmq'

=WARNING REPORT==== 08-Aug-2021::01:45:05 ===
memory resource limit alarm cleared across the cluster

=WARNING REPORT==== 08-Aug-2021::01:45:06 ===
memory resource limit alarm set on node 'rabbit@rabbitmq'.

**********************************************************
*** Publishers will be blocked until this alarm clears ***
**********************************************************&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;2. 해당 에러나는 이유 (Memory Threshold)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RabbitMQ 서버는 시작할 때 컴퓨터에 설치된 RAM의 총량을 감지합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 RabbitMQ 가 RAM의 사용가능한 40% 이상을 넘어갈 때 memory alaram 이 발생하며, 모든 publishing 된 messages connections 를 block 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 알람이 해제(e.g. due to the server paging messages to disk or delivering them to clients that consume and acknowledge the deliveries)되면 정상적인 서비스로 다시 시작됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 메모리의 임계값은 설치된 RAM의 40%로 설정됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 RabbitMQ 서버가 40% 이상을 사용하는 것을 제한하는 것은 아니며, 최악의 경우 사용되는 메모리 양의 두 배(기본적으로 RAM의 80%)를 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 OS SWAP 이나 page files 를 가능하게 하는 것이 권고됩니다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;3. Memory Threshold 설정파일 변경하는 방법&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RAM 의 비율로 설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;60%로 설정&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-jsx&quot;&gt;vm_memory_high_watermark.relative = 0.6&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RAM 의 고정값으로 설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;6GB로 설정&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-jsx&quot;&gt;vm_memory_high_watermark.absolute = 6GB&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;1024MiB로 설정&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-jsx&quot;&gt;vm_memory_high_watermark.absolute = 1024MiB&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;4. Rabbitmq docker 에 적용&lt;/h1&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;docker exec -it rabbitmq rabbitmqctl set_vm_memory_high_watermark 0.7&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;https://www.rabbitmq.com/memory.html&lt;br /&gt;https://www.rabbitmq.com/configure.html#configuration-file&lt;br /&gt;https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&amp;amp;blogId=parkjy76&amp;amp;logNo=220826990472&lt;/p&gt;</description>
      <category>Rabbitmq,Redis</category>
      <category>rabbitmq</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/63</guid>
      <comments>https://minimilab.tistory.com/63#entry63comment</comments>
      <pubDate>Wed, 1 Sep 2021 22:02:42 +0900</pubDate>
    </item>
    <item>
      <title>Fluentd 설치방법 (서버에 설치, docker로 설치)</title>
      <link>https://minimilab.tistory.com/62</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot; data-filename=&quot;fluentd logo2.jpg&quot; width=&quot;200&quot; height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4K57D/btrdz7TAy2x/Hwe4pTxjbLDlbqOS2lyEtk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4K57D/btrdz7TAy2x/Hwe4pTxjbLDlbqOS2lyEtk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4K57D/btrdz7TAy2x/Hwe4pTxjbLDlbqOS2lyEtk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4K57D%2Fbtrdz7TAy2x%2FHwe4pTxjbLDlbqOS2lyEtk%2Fimg.jpg&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot; data-filename=&quot;fluentd logo2.jpg&quot; width=&quot;200&quot; height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Fluentd&amp;nbsp;설치방법&amp;nbsp;(서버에&amp;nbsp;설치,&amp;nbsp;docker로&amp;nbsp;설치)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fluentd 설치 방법을 두가지 버전으로 나누어서 설명하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째는 ubuntu 20.04 서버에 직접 설치하는 방법&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;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. 서버에 직접설치 방법&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서에 따르면 Fluentd 를 설치하기 전에 권장사항을 따를 것을 권고합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 : &lt;a href=&quot;https://docs.fluentd.org/installation/before-install&quot;&gt;https://docs.fluentd.org/installation/before-install&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NTP 설정 (NTP 데몬 설정, 정확한 현재 타임스탬프 설정)&lt;/li&gt;
&lt;li&gt;최대 File Descriptors 로 늘리기&lt;/li&gt;
&lt;li&gt;네트워크 커널 매개변수 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1-1.&lt;/b&gt; &lt;b&gt;File Descriptors 확인&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;$ ulimit -n
1024&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;값이 1024인 경우, 아래 파일에 내용 추가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;systemd 서비스 사용중인 os는 'LimitNOFILE=65536' 도 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ vi /etc/security/limits.conf

root soft nofile 65536
root hard nofile 65536
* soft nofile 65536
* hard nofile 65536&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ sudo reboot&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;$ ulimit -n
65536&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1-2. 네트워크 커널 매개 변수 최적화&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Fluentd 인스턴스가 많은 고부하의 환경에 사용&lt;/li&gt;
&lt;li&gt;아래 파일에 내용 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;$ sudo vi /etc/sysctl.conf

net.core.somaxconn = 1024
net.core.netdev_max_backlog = 5000
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_wmem = 4096 12582912 16777216
net.ipv4.tcp_rmem = 4096 12582912 16777216
net.ipv4.tcp_max_syn_backlog = 8096
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 10240 65535

$ sudo sysctl -p&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1-3. Fluentd 설치&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 버전에 대한 설치 프로세스를 자동화하기 위해 Fluentd 설치 쉘 스크립트가 제공됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 : &lt;a href=&quot;https://docs.fluentd.org/installation/install-by-deb&quot;&gt;https://docs.fluentd.org/installation/install-by-deb&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-focal-td-agent4.sh | sh&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1-4. Fluentd 실행&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Fluentd 실행 후 실행되었는지 확인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stop, restart 명령어도 사용가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;$ systemctl start td-agent
$ systemctl status td-agent&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1713&quot; data-origin-height=&quot;612&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zlaPL/btrdqRkeObv/NvqS7sN0AZTGQ9SrPR8n6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zlaPL/btrdqRkeObv/NvqS7sN0AZTGQ9SrPR8n6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zlaPL/btrdqRkeObv/NvqS7sN0AZTGQ9SrPR8n6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzlaPL%2FbtrdqRkeObv%2FNvqS7sN0AZTGQ9SrPR8n6k%2Fimg.png&quot; data-origin-width=&quot;1713&quot; data-origin-height=&quot;612&quot; data-filename=&quot;Untitled.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1-5. 샘플 테스트&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;$ curl -X POST -d 'json={&quot;json&quot;:&quot;message&quot;}' http://localhost:8888/debug.test

$ tail -n 1 /var/log/td-agent/td-agent.log
2021-08-30 11:09:50.308226287 +0000 debug.test: {&quot;json&quot;:&quot;message&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1-6. &lt;span style=&quot;color: #222222;&quot;&gt;Fluentd &lt;/span&gt;파일 위치&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Fluentd 설정파일&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;/etc/td-agent/td-agent.conf&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;Fluentd 로그 파일&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;/var/log/td-agent/td-agent.log&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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. Docker로 Fluentd 설치&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 는 깔려 있는 것을 전제로 Fluentd 를 설치하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 : &lt;a href=&quot;https://docs.fluentd.org/container-deployment/install-by-docker&quot;&gt;https://docs.fluentd.org/container-deployment/install-by-docker&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2-1. Fluentd Docker 이미지 pull&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;docker pull fluent/fluentd:edge-debian&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2-2. Fluentd 설정파일 생성&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ mkdir tmp
$ cd tmp
$ vi fluentd.conf
&amp;lt;source&amp;gt;
  @type http
  port 9880
  bind 0.0.0.0
&amp;lt;/source&amp;gt;

&amp;lt;match **&amp;gt;
  @type stdout
&amp;lt;/match&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2-3. Fluentd Docker container 실행 및 테스트&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ sudo docker run -d --name fluentd -p 9880:9880 -v $(pwd)/tmp:/fluentd/etc fluent/fluentd:edge-debian -c /fluentd/etc/fluentd.conf

$ curl -X POST -d 'json={&quot;json&quot;:&quot;message&quot;}' http://127.0.0.1:9880/sample.test

$ sudo docker logs -f fluentd
fluentd -c /fluentd/etc/fluentd.conf
2021-08-30 11:52:56 +0000 [info]: parsing config file is succeeded path=&quot;/fluentd/etc/fluentd.conf&quot;
2021-08-30 11:52:56 +0000 [info]: gem 'fluentd' version '1.14.0'
2021-08-30 11:52:56 +0000 [warn]: define &amp;lt;match fluent.**&amp;gt; to capture fluentd logs in top level is deprecated. Use &amp;lt;label @FLUENT_LOG&amp;gt; instead
2021-08-30 11:52:56 +0000 [info]: using configuration file: &amp;lt;ROOT&amp;gt;
  &amp;lt;source&amp;gt;
    @type http
    port 9880
    bind &quot;0.0.0.0&quot;
  &amp;lt;/source&amp;gt;
  &amp;lt;match **&amp;gt;
    @type stdout
  &amp;lt;/match&amp;gt;
&amp;lt;/ROOT&amp;gt;
2021-08-30 11:52:56 +0000 [info]: starting fluentd-1.14.0 pid=7 ruby=&quot;2.6.8&quot;
2021-08-30 11:52:56 +0000 [info]: spawn command to main:  cmdline=[&quot;/usr/local/bin/ruby&quot;, &quot;-Eascii-8bit:ascii-8bit&quot;, &quot;/usr/local/bundle/bin/fluentd&quot;, &quot;-c&quot;, &quot;/fluentd/etc/fluentd.conf&quot;, &quot;--plugin&quot;, &quot;/fluentd/plugins&quot;, &quot;--under-supervisor&quot;]
2021-08-30 11:52:57 +0000 [info]: adding match pattern=&quot;**&quot; type=&quot;stdout&quot;
2021-08-30 11:52:57 +0000 [info]: adding source type=&quot;http&quot;
2021-08-30 11:52:57 +0000 [warn]: #0 define &amp;lt;match fluent.**&amp;gt; to capture fluentd logs in top level is deprecated. Use &amp;lt;label @FLUENT_LOG&amp;gt; instead
2021-08-30 11:52:57 +0000 [info]: #0 starting fluentd worker pid=16 ppid=7 worker=0
2021-08-30 11:52:57 +0000 [info]: #0 fluentd worker is now running worker=0
2021-08-30 11:52:57.457512925 +0000 fluent.info: {&quot;pid&quot;:16,&quot;ppid&quot;:7,&quot;worker&quot;:0,&quot;message&quot;:&quot;starting fluentd worker pid=16 ppid=7 worker=0&quot;}
2021-08-30 11:52:57.459779701 +0000 fluent.info: {&quot;worker&quot;:0,&quot;message&quot;:&quot;fluentd worker is now running worker=0&quot;}
2021-08-30 11:53:14.422464593 +0000 sample.test: {&quot;json&quot;:&quot;message&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Fluentd</category>
      <category>fluentd</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/62</guid>
      <comments>https://minimilab.tistory.com/62#entry62comment</comments>
      <pubDate>Mon, 30 Aug 2021 21:08:59 +0900</pubDate>
    </item>
    <item>
      <title>Fluentd란? Fluentd 사용법</title>
      <link>https://minimilab.tistory.com/61</link>
      <description>&lt;h1&gt;Fluentd란? Fluentd 사용법&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot; data-filename=&quot;fluentd logo2.jpg&quot; width=&quot;200&quot; height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zzYA8/btrdruvAtlK/SgmW5o5cQDamCE2rFhyBa1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zzYA8/btrdruvAtlK/SgmW5o5cQDamCE2rFhyBa1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zzYA8/btrdruvAtlK/SgmW5o5cQDamCE2rFhyBa1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzzYA8%2FbtrdruvAtlK%2FSgmW5o5cQDamCE2rFhyBa1%2Fimg.jpg&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot; data-filename=&quot;fluentd logo2.jpg&quot; width=&quot;200&quot; height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;1. Fluentd 란 ?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 수집할 수 있는 로그 수집기 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fluentd에서는 서버에 쌓이고 있는 log 파일을 지정하여 로그를 수집하도록 할 수 있습니다. 또는 http, tcp 통신하여 Fluentd로 직접 전송하는 방식도 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Fluentd에서 수집한 로그를 가공(로그에 값 추가 혹은 삭제, 필터 등) 할 수 있으며, 이를 파일이나 데이터베이스로 저장하거나 전송할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. Fluentd 사용방법&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fluentd는 Input, Parser, Engine, Filter, Buffer, Ouput, Formatter 7개의 컴포넌트로 구성이 되어있습니다.&lt;br /&gt;7개의 컴포넌트중 Engine을 제외한 나머지 6개는 플러그인 형태로 제공이 되서 사용자가 설정이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 흐름은 Input &amp;rarr; Engine &amp;rarr; Output 의 흐름으로 이루어 지고, Parser, Buffer, Filter, Formatter 등은 Optional 하여 필요에 따라 사용할수도 있고, 사용하지 않을 수도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;940&quot; data-filename=&quot;Untitled.png&quot; width=&quot;500&quot; height=&quot;428&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccoJ8N/btrdqinfnM3/82BVY53yLqplNO5OMc8wCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccoJ8N/btrdqinfnM3/82BVY53yLqplNO5OMc8wCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccoJ8N/btrdqinfnM3/82BVY53yLqplNO5OMc8wCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccoJ8N%2FbtrdqinfnM3%2F82BVY53yLqplNO5OMc8wCk%2Fimg.png&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;940&quot; data-filename=&quot;Untitled.png&quot; width=&quot;500&quot; height=&quot;428&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1. Input&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수집할 log를 &amp;lt;source&amp;gt;&amp;lt;/source&amp;gt; 내부에서 input plugin(tail, forward, http등)을 사용해서 가져옵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@tail&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;path 에 지정한 log를 읽어서 사용합니다. 리눅스 tail 명령어와 같이, 파일의 끝부분을 지속적으로 읽습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;&amp;lt;source&amp;gt;
  @type tail
  path /var/log/httpd-access.log
  pos_file /var/log/td-agent/httpd-access.log.pos
  tag apache.access
  &amp;lt;parse&amp;gt;
    @type apache2
  &amp;lt;/parse&amp;gt;
&amp;lt;/source&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@forward&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;데이터를 전달받기 위해 사용하며, 서버간에 TCP로 로그 데이터를 수신할 수 있습니다.&lt;/li&gt;
&lt;li&gt;forward로 전달되는 데이터는 json 이나 messagepack 형식으로 되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;&amp;lt;source&amp;gt;
  @type forward
  port 24224
  bind 0.0.0.0
&amp;lt;/source&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@http&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;curl 같은 명령어로 로그데이터를 http 요청으로 받을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;&amp;lt;source&amp;gt;
  @type http
  port 9880
  bind 0.0.0.0
  body_size_limit 32m
  keepalive_timeout 10s
&amp;lt;/source&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;2-2. filter (Optional)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;filter 를 통해 특정 데이터만 지정해서 output으로 보내거나, 데이터에 필드 값을 추가하거나 삭제할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&amp;lt;filter&amp;gt;&amp;lt;/filter&amp;gt; 내부에서 filter plugin(record_transformer, grep 등)을 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@record_transformer&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;output으로 보내기 전에 source 의 log에 hostname을 key 로, #{Socket.gethostname} 를 value 로 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gherkin&quot;&gt;&lt;code&gt;&amp;lt;filter foo.bar&amp;gt;
  @type record_transformer
  &amp;lt;record&amp;gt;
    hostname &quot;#{Socket.gethostname}&quot;
  &amp;lt;/record&amp;gt;
&amp;lt;/filter&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@grep&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;&amp;lt;source&amp;gt; 에서 tar가 foo.bar 로 설정되어 읽어온 log 중에,&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;message filed의 값에 cool 이 있는 경우 만 grep 해서 output으로 보냅니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;hostname field 값이 web.example.com 과 일치하는 경우에만 output으로 보냅니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;message field 값에 uncool이 없는 경우에만 output으로 보냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;&amp;lt;filter foo.bar&amp;gt;
  @type grep

  &amp;lt;regexp&amp;gt;
    key message
    pattern /cool/
  &amp;lt;/regexp&amp;gt;

  &amp;lt;regexp&amp;gt;
    key hostname
    pattern /^web\d+\.example\.com$/
  &amp;lt;/regexp&amp;gt;

  &amp;lt;exclude&amp;gt;
    key message
    pattern /uncool/
  &amp;lt;/exclude&amp;gt;
&amp;lt;/filter&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@parser&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;expression 의 정규식에 일치하는 log가 있는 경우 오른쪽 정규식 내용으로 변경해서 output 으로 보냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;&amp;lt;filter foo.bar&amp;gt;
  @type parser
  key_name log
  &amp;lt;parse&amp;gt;
    @type regexp
    expression /^(?&amp;lt;host&amp;gt;[^ ]*) [^ ]* (?&amp;lt;user&amp;gt;[^ ]*) \[(?&amp;lt;time&amp;gt;[^\]]*)\] &quot;(?&amp;lt;method&amp;gt;\S+)(?: +(?&amp;lt;path&amp;gt;[^ ]*) +\S*)?&quot; (?&amp;lt;code&amp;gt;[^ ]*) (?&amp;lt;size&amp;gt;[^ ]*)$/
    time_format %d/%b/%Y:%H:%M:%S %z
  &amp;lt;/parse&amp;gt;
&amp;lt;/fil&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;2-3. buffer (Optional)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;match&amp;gt;&amp;lt;/match&amp;gt; 에서 &amp;lt;buffer&amp;gt;&amp;lt;/buffer&amp;gt;를 사용하여 input 에서 들어온 log를 특정데이터 크기 제한까지 도달하면 output으로 보내도록 할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;552&quot; data-filename=&quot;Untitled 1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D58Ae/btrdr42Qcao/0UNtpWFnVAVRlxFkts9Rk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D58Ae/btrdr42Qcao/0UNtpWFnVAVRlxFkts9Rk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D58Ae/btrdr42Qcao/0UNtpWFnVAVRlxFkts9Rk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD58Ae%2Fbtrdr42Qcao%2F0UNtpWFnVAVRlxFkts9Rk0%2Fimg.png&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;552&quot; data-filename=&quot;Untitled 1.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 : &lt;a href=&quot;https://blog.daum.net/art_code/678219&quot;&gt;https://blog.daum.net/art_code/678219&lt;/a&gt;, &lt;a href=&quot;https://docs.fluentd.org/configuration/buffer-section&quot;&gt;https://docs.fluentd.org/configuration/buffer-section&lt;/a&gt;, &lt;a href=&quot;https://bcho.tistory.com/1115&quot;&gt;https://bcho.tistory.com/1115&lt;/a&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;2-4. output&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출력할 log를 &amp;lt;match&amp;gt;&amp;lt;/match&amp;gt; 내부에서 output plugin(file, stdout, forward등)을 사용해서 출력합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@file&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;log를 지정한 path 에 gzip 으로 압축하여 출력합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;&amp;lt;match pattern&amp;gt;
  @type file
  path /var/log/fluent/myapp
  compress gzip
  &amp;lt;buffer&amp;gt;
    timekey 1d
    timekey_use_utc true
    timekey_wait 10m
  &amp;lt;/buffer&amp;gt;
&amp;lt;/match&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@stdout&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Fluentd 에서 표준출력(stdout)으로 출력합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;&amp;lt;match **&amp;gt;
    @type stdout
&amp;lt;/match&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@forward&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 Fluentd 노드로 로그를 전달할 때 사용되며, 반드시 1개 이상을 포함해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;&amp;lt;match **&amp;gt;
  @type forward

  &amp;lt;server&amp;gt;
    name another.fluentd1
    host 127.0.0.1
    port 24224
    weight 60   # 로드밸런싱 가중치 설정 
  &amp;lt;/server&amp;gt;
  &amp;lt;server&amp;gt;
    name another.fluentd2
    host 127.0.0.1
    port 24225
    weight 40
  &amp;lt;/server&amp;gt;
&amp;lt;/match&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;2-5 Parser (Optional)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;source&amp;gt;&amp;lt;source&amp;gt;, &amp;lt;match&amp;gt;&amp;lt;match&amp;gt;, &amp;lt;filter&amp;gt;&amp;lt;/filter&amp;gt; 안에서 &amp;lt;pasre&amp;gt;&amp;lt;/parse&amp;gt; 형식으로 사용합니다.&lt;/li&gt;
&lt;li&gt;전달받은 데이터를 파싱하기 위해서 @type 파라미터로 regexp, apache2, apache_error, nginx, syslog, csv, tsv, ltsv, json, multiline, none 과 같은 Parser plugin을 사용합니다.&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;2-6. Formatter (Optional)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;match&amp;gt;&amp;lt;/match&amp;gt; 안에서 &amp;lt;format&amp;gt;&amp;lt;/format&amp;gt; 형식으로 사용합니다.&lt;/li&gt;
&lt;li&gt;출력 형식을 변경 할 수 있습니다. @type 파라미터로 out_file, json, ltsv, csv, msgpack, hash, single_value, tsv 와 같은 Formatter plugin 을 사용합니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Fluentd</category>
      <category>fluentd</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/61</guid>
      <comments>https://minimilab.tistory.com/61#entry61comment</comments>
      <pubDate>Fri, 27 Aug 2021 23:29:54 +0900</pubDate>
    </item>
    <item>
      <title>python flask ajax 예제 사용방법</title>
      <link>https://minimilab.tistory.com/60</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (2).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9l4Pq/btreJiglpXM/7B7lyrP25fjwO8fkKV2TI0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9l4Pq/btreJiglpXM/7B7lyrP25fjwO8fkKV2TI0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9l4Pq/btreJiglpXM/7B7lyrP25fjwO8fkKV2TI0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9l4Pq%2FbtreJiglpXM%2F7B7lyrP25fjwO8fkKV2TI0%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;제목을 입력해주세요_-001 (2).jpg&quot; width=&quot;300&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;br /&gt;item-img 클래스 클릭 시 색상 변경 되고, python flask api 를 통해 DB 에 update, delete 하는 코드&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. python flask api method 생성&lt;/blockquote&gt;
&lt;pre id=&quot;code_1614172661750&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@app.route('/post/add_items', methods=['POST'])
def add_items():
    data = json.loads(request.data)
    user_id = data.get('user_id')
    subject = data.get('subject')
    items = data.get('items')

    user_db = db.MongoDB('user')
    user_db.add_item(user_id, subject, items)
    return items

@app.route('/delete/delete_items', methods=['DELETE'])
def delete_items():
    data = json.loads(request.data)
    user_id = data.get('user_id')
    subject = data.get('subject')
    items = data.get('items')

    user_db = db.MongoDB('user')
    user_db.delete_item(user_id, subject, items)
    return items&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;2. html &amp;lt;script&amp;gt; 태그에 ajax 함수 삽입&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* item-img 클래스에 id 를 지정해 주어야 함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* dataType은 응답 받는 형식(text, json 등)을 지정. api return 값과 형식이 일치해야 함&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1614172760469&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;style&amp;gt;
.item-img.active {
  background-color: cornflowerblue;
}
&amp;lt;/style&amp;gt;
&amp;lt;script&amp;gt;
        $(&quot;.item-img&quot;).on('click', itemClick);

        function itemClick(event){
            var targetId = event.currentTarget.id;
            data = {user_id:'a', subject:'housewares', items:targetId }

            if($('#'+targetId).hasClass('active')){
                $.ajax({
                    type:'DELETE',
                    contentType: 'application/json',
                    url:'/delete/delete_items',
                    data:JSON.stringify(data),
                    dataType: 'text',
                    success: function(response){
                        console.log(response)
                    },
                    error : function(xtr, status, error){
                            alert(xtr +&quot;:&quot;+status+&quot;:&quot;+error);
                    }
                });
            }
            else {
                $.ajax({
                type:'POST',
                contentType: 'application/json',
                url:'/post/add_items',
                data:JSON.stringify(data),
                dataType: 'text',
                success: function(response){
                    console.log(response)
                },
                error : function(xtr, status, error){
                        alert(xtr +&quot;:&quot;+status+&quot;:&quot;+error);
                }
                });

            }
            $('#'+targetId).toggleClass('active');
        }

&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/60</guid>
      <comments>https://minimilab.tistory.com/60#entry60comment</comments>
      <pubDate>Wed, 24 Feb 2021 22:26:22 +0900</pubDate>
    </item>
    <item>
      <title>MongoDB Docker 내장기능으로 백업하기</title>
      <link>https://minimilab.tistory.com/59</link>
      <description>&lt;p&gt;&lt;span style=&quot;color: #000000; font-size: 1.62em; letter-spacing: -1px;&quot;&gt;MongoDB Docker 백업하기&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;MongoDB 를 백업하려면 mongodump 명령어를 사용해야 한다.&lt;br /&gt;MongoDB 도커에 exec 로 접속해서 mongodump 명령어를 사용할 수 있다.&lt;br /&gt;매번 접속해서 명령어를 날리기 불편하므로, 도커 컨테이너 밖에서 사용할 수 있는 sh -c 명령어를 통해서 /bin/bash 로 도커 안으로 접속하지 않고도 사용할 수 있도록 명령어를 작성했다.&lt;br /&gt;해당 명령어를 crontab 에 작성해놓아도 잘 실행된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;1. mongodb volume 설정&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;docker run 컨테이너 실행 시 -v 옵션으로 volume 설정을 한다.&lt;/li&gt;
&lt;li&gt;mongodump 결과물을 저장하고 싶은 곳으로 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1608216993688&quot; class=&quot;python&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ex) -v /backup/tmp:/backup/tmp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;2. docker exec 명령어 실행&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;mongod-server : docker container 이름&lt;/li&gt;
&lt;li&gt;-u 0 : root 로 실행&lt;/li&gt;
&lt;li&gt;DBNAME, USERNAME, PASSWORD 에 mongodump 할 mongodb 계정정보 입력&lt;/li&gt;
&lt;li&gt;-o : mongodb 백업 파일을 저장할 위치
&lt;ul&gt;
&lt;li&gt;-v 옵션으로 volume 설정한 위치로 지정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1608217090703&quot; class=&quot;python&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -u 0  mongod-server sh -c &quot;mongodump --db DBNAME --username USERNAME --password PASSWORD -o /backup/tmp&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Docker</category>
      <category>MongoDB</category>
      <category>mongodump</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/59</guid>
      <comments>https://minimilab.tistory.com/59#entry59comment</comments>
      <pubDate>Fri, 18 Dec 2020 00:04:50 +0900</pubDate>
    </item>
    <item>
      <title>Python __dict__ 용도 및 활용</title>
      <link>https://minimilab.tistory.com/58</link>
      <description>&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. __dict__ 용도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;클래스 객체의 속성 정보를 확인하기 위해 사용&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;객체가 가진 여러가지 속성들을 딕셔너리 형태로 편하게 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. __dict__ 활용 방법&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;객체의 변수를 dict형태로 변경할 수 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;dictionary 형태로 만들어 두면, 편하게 속성 값들을 가져올 수 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1608050022147&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Test:
	def __init__(self, name):
		self.name = name
		self.test_dict = {'a':1, 'b':2}
		self.test_list = ['1','2','3']
	
# Test 객체 생성		
test_object = Test(&quot;minimi&quot;)

# __dict__ 메소드를 이용해보면 type이 dict인 것을 확인 할 수 있다.
print(type(test_object.__dict__)) # &amp;lt;class 'dict'&amp;gt;

# print 해보면, 객체에 선언한 변수들이 key,value로 들어간 것을 확인할 수 있다.
print(test_object.__dict__)  # {'name': 'minimi', 'test_dict': {'a': 1, 'b': 2}, 'test_list': ['1', '2', '3']}

# dict 형태이기 때문에 key 값으로 조회시 바로 value를얻을 수 있다.
print(test_object.__dict__['name']) # minimi

# 번외 : dictionary의 key, value를 얻을 수 있는 items() 로 dict로 재변경
print(test_object.__dict__.items()) # dict_items([('name', 'minimi'), ('test_dict', {'a': 1, 'b': 2}), ('test_list', ['1', '2', '3'])])
print(type(test_object.__dict__.items())) # &amp;lt;class 'dict_items'&amp;gt;
object_dict = dict(x for x in test_object.__dict__.items()) # {'name': 'minimi', 'test_dict': {'a': 1, 'b': 2}, 'test_list': ['1', '2', '3']}
print(type(object_dict)) # &amp;lt;class 'dict'&amp;gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/58</guid>
      <comments>https://minimilab.tistory.com/58#entry58comment</comments>
      <pubDate>Wed, 16 Dec 2020 01:38:19 +0900</pubDate>
    </item>
    <item>
      <title>CHAPTER 4 데이터 집합: 배열 다루기</title>
      <link>https://minimilab.tistory.com/57</link>
      <description>&lt;h1&gt;php&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://phptester.net/&quot;&gt;http://phptester.net/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;$this 의 의미는 현재 자신을 나타내는 표현이고, &lt;/p&gt;
&lt;p&gt;→ 의 의미는 객체 내의 속성이나 메소드를 가르킬 때 사용합니다. &lt;/p&gt;
&lt;p&gt;$this→shape은 현재 객체 내의 shape 이라는 속성을 가르킵니다. &lt;/p&gt;
&lt;h2&gt;Chapter 1 ~ 20&lt;/h2&gt;
&lt;h1&gt;Chapter 1. 오리엔테이션과 첫걸음&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;프린트 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

print &amp;#39;test&amp;#39;;

?&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 1-2) 데이터를 제출하는 HTML 폼&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;form method=&amp;quot;POST&amp;quot; action=&amp;quot;sayhello.php&amp;quot;&amp;gt;
이름: &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;user&amp;quot; /&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;button type=&amp;quot;submit&amp;quot;&amp;gt;인사&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 1-3) 동적데이터&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$_POST에는 폼 매개변수로 제출된 값이 담긴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
print &amp;quot;hello.&amp;quot;;
print $_POST[&amp;#39;user&amp;#39;];
print &amp;quot;!&amp;quot;;
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1-4) 폼 출력&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;lt;&amp;lt;&amp;lt;&lt;em&gt;HTML_과 _HTML&lt;/em&gt; 사이에 있는 모든 내용을 print 명령에 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
print &amp;lt;&amp;lt;&amp;lt;_HTML_
&amp;lt;form method=&amp;quot;post&amp;quot; action=&amp;quot;$_SERVER[PHP_SELF]&amp;quot;&amp;gt;
이름: &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;user&amp;quot; /&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;button type=&amp;quot;submit&amp;quot;&amp;gt;인사&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
_HTML_;
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1-5) 환영인사와 폼 출력&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
if ($_POST[&amp;#39;user&amp;#39;]) {
        print &amp;quot;hello.&amp;quot;;
        print $_POST[&amp;#39;user&amp;#39;];
        print &amp;quot;!&amp;quot;;

} else {
        print &amp;lt;&amp;lt;&amp;lt;_HTML_
        &amp;lt;form method=&amp;quot;post&amp;quot; action=&amp;quot;$_SERVER[PHP_SELF]&amp;quot;&amp;gt;
        이름: &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;user&amp;quot; /&amp;gt;
        &amp;lt;br/&amp;gt;
        &amp;lt;button type=&amp;quot;submit&amp;quot;&amp;gt;인사&amp;lt;/button&amp;gt;
        &amp;lt;/form&amp;gt;
        _HTML_;
}
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1-6) 형식화된 숫자 출력&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php print &amp;quot;한국의 대략적인 인구: &amp;quot;;
    print number_format(584989);
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;출력 값
한국의 대략적인 인구: 50,801,405&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1-7) 데이터베이스에서 정보를 가져와 표시하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
//SQLite 데이터베이스 파일에 접속하도록 지시
$db = new PD0(&amp;#39;sqlite:dinner.db&amp;#39;);
$meals = array(&amp;#39;아침&amp;#39;,&amp;#39;점심&amp;#39;,&amp;#39;저녁&amp;#39;);

if (in_array($_POST[&amp;#39;meal&amp;#39;], $meals)) {
    $stmt = $db-&amp;gt;prepare(&amp;#39;SELECT dish, price FROM meals WHERE meal LIKE ?&amp;#39;);
  $stmt-&amp;gt;execute(array($_POST[&amp;#39;meal&amp;#39;])));
    $rows = $stmt-&amp;gt;fetchAll();
    if (count($rows) ==) {
        print &amp;quot;가능한 요릭 없습니다.&amp;quot;;
    } else {
        print &amp;#39;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;요리 &amp;#39;;
        foreach ($rows as $row) {
            print &amp;quot;&amp;lt;tr&amp;gt;&amp;quot;;
        }
    }
}
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1-8) 여러 쌍의 시작 태그와 종료 태그&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;?php ?&gt; 시작태그와 종료태그 php 엔진은 이 바깥쪽 태그는 완전히 무시한다. php 파일 맨 마지막 종료태그는 생략할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;주석&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;/* */
//
#&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;문자열 출력&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;print &amp;#39;&amp;quot;나 지금 저녁 식사중이라고&amp;quot; 그가 으르렁 거렸다.&amp;#39;;
print &amp;#39;we\&amp;#39;ll each have a bowlof soup.&amp;#39;;
print &amp;#39;we\\&amp;#39;; -&amp;gt; 
# we\ 출력

print &amp;#39;&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;소고기 볶음&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;chapter2 데이터:텍스트와 숫자 다루기&lt;/h1&gt;
&lt;h3&gt;2-1) 큰따옴표 문자열 안에서 사용할 수 있는 특수 문자&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;php%201ef9f18778a54b718ea7fa9fbe17dbd2/Untitled.png&quot; alt=&quot;php%201ef9f18778a54b718ea7fa9fbe17dbd2/Untitled.png&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;작은따옴표 : 변수명이 그대로 출력&lt;/p&gt;
&lt;p&gt;ex) &amp;#39;Hi $user&amp;#39; → Hi $user&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;큰 따옴표 : 대치가 일어남&lt;/p&gt;
&lt;p&gt;ex) Hi Bill&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HTMLBLOCK이 구분자 단어로 쓰였다. 구분자의 첫 글자는 반드시 알파벳이나 밑줄문자여야 한다. here 문서의 시작 지점을 시각적으로 알 수 있도록 대문자로 쓰는 것이 좋다. here 문서를 종료할 때 쓰는 구분자는 해당 줄에 홀로 존재해야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;&amp;lt;&amp;lt;HTMLBLOCK
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;메뉴&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;/html&amp;gt;
HTMLBLOCK&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;예외적으로 구분자 뒤에 ; 를 사용할 수 있지만, 그 뒤에 아무것도 없어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;&amp;lt;&amp;lt;HTMLBLOCK
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;메뉴&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;/html&amp;gt;
HTMLBLOCK;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;chapter 3 (로직: 조건 판단과 반복 수행)&lt;/h1&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$price = $quantity = 5;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.2 조건 판단&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;if ($logged_in) {
    print &amp;quot;환영합니다 정회원님.&amp;quot;;
}

if ($logged_in) {
    print &amp;quot;환영합니다 정회원님.&amp;quot;;
} else {
    print &amp;quot;반갑습니다 방문자님&amp;quot;;
}

if ($logged_in) {
    print &amp;quot; 환영합니다 정회원님.&amp;quot;;
} elseif ($new_messages) {
    print &amp;quot;방문자님,새로운 메세지가 있습니다.&amp;quot;;
} elseif ($emergency) {
    print &amp;quot;방문자님,새로운 메세지는 없습니다만, 긴급 상황입니다.&amp;quot;;
} else {
    print &amp;quot; 누구? &amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.3 비교연산자&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;1. 같다 ==
2. 다르다 !=
3. &amp;gt;, &amp;gt;= &amp;lt;=
4. 절대값 abs()&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;php에서는 문자열 비교 시, 숫자로 변환해 비교한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;strcmp() 함수를이용하면 문자를 숫자로 변환 비교하여 큰지 작은지 판단할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$x = strcmp(&amp;quot;x54321&amp;quot;, &amp;quot;x5678&amp;quot;);
if ($x &amp;gt; 0) {
    print &amp;quot;test&amp;quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;CHAPTER 4 데이터 집합: 배열 다루기&lt;/h1&gt;
&lt;h2&gt;4.1 배열 기초&lt;/h2&gt;
&lt;h3&gt;4.1.1 배열 생성&lt;/h3&gt;
&lt;p&gt;키와 값 구분 : ⇒&lt;/p&gt;
&lt;p&gt;키/값 쌍 목록 구분 : , (쉼표)&lt;/p&gt;
&lt;h3&gt;예제 4-1) 배열 생성하기&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;문자열은 따옴표로 감싸고, 수는 그대로 쓴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$vegetables = array(&amp;#39;corn&amp;#39; =&amp;gt; &amp;#39;노랑&amp;#39;,
                                        &amp;#39;beet&amp;#39; =&amp;gt; &amp;#39;빨강&amp;#39;,
                                      &amp;#39;carrot&amp;#39; =&amp;gt; &amp;#39;주황&amp;#39;,);

$dinner = array(0 =&amp;gt; &amp;#39;스위트콘&amp;#39;,
                                1 =&amp;gt; &amp;#39;레몬 치킨&amp;#39;,
                                2 =&amp;gt; &amp;#39;삶은 망태버섯&amp;#39;);

$computers = array(&amp;#39;nintendo&amp;#39; =&amp;gt; &amp;#39;닌텐도&amp;#39;,
                                1 =&amp;gt; &amp;#39;레몬 치킨&amp;#39;,
                                &amp;#39;saturn&amp;#39; =&amp;gt; &amp;#39;삶은 망태버섯&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-2) 단축 배열 문법으로 배열 선언하기&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;array() 구조는 대괄호 쌍으로 축약할 수 있다.&lt;/li&gt;
&lt;li&gt;이를 단축 배열 문법이라고 한다.&lt;/li&gt;
&lt;li&gt;단축배열 문법은 PHP 5.4에서 도입 되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$vegetables = [&amp;#39;corn&amp;#39; =&amp;gt; &amp;#39;노랑&amp;#39;,&amp;#39;beet&amp;#39; =&amp;gt; &amp;#39;빨강&amp;#39;, &amp;#39;carrot&amp;#39; =&amp;gt;&amp;#39;주황&amp;#39; ];

$dinner = [0 =&amp;gt; &amp;#39;스위트콘&amp;#39;,
                     1 =&amp;gt; &amp;#39;레몬치킨&amp;#39;,
                     2 =&amp;gt; &amp;#39;삶은 망태버섯&amp;#39;];

$computers= [&amp;#39;nintendo&amp;#39; =&amp;gt; &amp;#39;닌텐도&amp;#39;, 1 =&amp;gt; &amp;#39;레몬 치킨&amp;#39;, &amp;#39;saturn&amp;#39; =&amp;gt;&amp;#39;삶은 망태버섯&amp;#39; ];
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-3) 원소를 하나씩 추가해 배열 생성하기&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;배열명 다음에 나오는 대괄호는 배열에 지정할 키를 나타낸다. 이 키에 값을 할당하면 배열에 원소가 추가된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$vegetables[&amp;#39;corn&amp;#39;] = &amp;#39;노랑&amp;#39;;
$vegetables[1] = &amp;#39;레몬치킨&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.1.2 적절한 배열명&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;배열 ↔ 스칼라변수는 값을 할 당할 때마다 이 전에 있던 값이 지워지고 이후의 값으로 바뀐다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.1.3 숫자 키 배열&lt;/h3&gt;
&lt;h3&gt;예제 4-5) array()로 숫자 키 배열 생성하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$dinner = array(&amp;#39;스위트콘&amp;#39;,
                                &amp;#39;레몬&amp;#39;,
                                &amp;#39;버섯&amp;#39;);
print &amp;quot;$dinner[0] 그리고 $dinner[1] 주세요&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;출력 값 : 스위트콘 그리고 레몬 주세요&lt;/p&gt;
&lt;h3&gt;예제 4-6) []로 배열 원소 추가하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$lunch[] = &amp;#39;test&amp;#39;;
$lunch[] = &amp;#39;22&amp;#39;;
$lunch = array(&amp;#39;abc&amp;#39;,
                &amp;#39;def&amp;#39;,
                &amp;#39;ghr&amp;#39;);
print($lunch[0]);
print($lunch[1]);
print($lunch[2]);

abcdefghr&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.1.4 배열 크기 구하기&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;count() 함수를 이용해서 배열 원소가 몇 개 인지 알 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;예제 4-7 배열의 크기 구하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$lunch = array(&amp;#39;abc&amp;#39;,
                &amp;#39;def&amp;#39;,
                &amp;#39;ghr&amp;#39;);
$test = count($lunch);
print &amp;quot;총 메뉴 개수 : $test&amp;quot;; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;출력 : 총 메뉴 개수 : 3&lt;/p&gt;
&lt;h2&gt;4.2 배열 원소 순회&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;foreach()를 이용하여 배열의 각 원소를 순회할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;예제 4-8) foreach() 반복문&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$meal 배열의 각 원소에 대해 $key 변수에 키를, $value 변수에 값을 복사한 뒤 중괄호 내부의 코드를 실행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$meal = array(
&amp;#39;brakfast&amp;#39; =&amp;gt; &amp;#39;호두 번&amp;#39;,
&amp;#39;lunch&amp;#39; =&amp;gt; &amp;#39;캐슈너트와 양송이 버섯&amp;#39;,
&amp;#39;snack&amp;#39; =&amp;gt; &amp;#39;말린 오디&amp;#39;,
&amp;#39;diner&amp;#39; =&amp;gt; &amp;#39;치리 소스 가지볶음&amp;#39;);

print &amp;quot;&amp;lt;table&amp;gt;\n&amp;quot;;
foreach ($meal as $key =&amp;gt; $value) {
    print &amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;$key&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$value&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot;;
}
print &amp;#39;&amp;lt;/table&amp;gt;&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;brakfast    호두 번
lunch    캐슈너트와 양송이 버섯
snack    말린 오디
diner    치리 소스 가지볶음&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-9) foreach() 반복문&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$row_styles = array(&amp;#39;even&amp;#39;, &amp;#39;odd&amp;#39;);
$style_index = 0;
$meal = array(&amp;#39;breakfast&amp;#39; =&amp;gt; &amp;#39;호두 번&amp;#39;,
        &amp;#39;lunch&amp;#39; =&amp;gt; &amp;#39;캐슈넛&amp;#39;,
        &amp;#39;snack&amp;#39; =&amp;gt; &amp;#39;말린오디&amp;#39;,
        &amp;#39;dinner&amp;#39; =&amp;gt; &amp;#39;칠리소스 가지볶음&amp;#39;);
print &amp;quot;&amp;lt;table&amp;gt;\n&amp;quot;;
foreach ($meal as $key =&amp;gt; $value) {
    print &amp;#39;&amp;lt;tr lass=&amp;quot;&amp;#39; . $row_styles[$style_index] . &amp;#39;&amp;quot;&amp;gt;&amp;#39;;
    print &amp;quot;&amp;lt;td&amp;gt;$key&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$value&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\n&amp;quot;;
    $style_index = 1 -$style_index;    
};
print &amp;#39;&amp;lt;/table&amp;gt;&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;table&amp;gt;
&amp;lt;tr lass=&amp;quot;even&amp;quot;&amp;gt;&amp;lt;td&amp;gt;breakfast&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;호두 번&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr lass=&amp;quot;odd&amp;quot;&amp;gt;&amp;lt;td&amp;gt;lunch&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;캐슈넛&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr lass=&amp;quot;even&amp;quot;&amp;gt;&amp;lt;td&amp;gt;snack&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;말린오디&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr lass=&amp;quot;odd&amp;quot;&amp;gt;&amp;lt;td&amp;gt;dinner&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;칠리소스 가지볶음&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-10) foreach()로 배열 수정하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$meals = array(&amp;#39;walnut Bun&amp;#39; =&amp;gt; 1,
                &amp;#39;Cashew Nuts and White Mushromos&amp;#39; =&amp;gt; 4.95,
                &amp;#39;Dried Mulberries&amp;#39; =&amp;gt; 3.00,
                &amp;#39;Eggplant with Chili sauce&amp;#39; =&amp;gt; 6.50);

foreach ($meals as $dish =&amp;gt; $price) {
    $meals[$dish] = $meals[$dish] *2;
}

foreach ($meals as $dish =&amp;gt; $price) {
    printf(&amp;quot;%s 메뉴의 변경된 가격은 \$%.2f입니다.\n&amp;quot;, $dish, $price);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;walnut Bun 메뉴의 변경된 가격은 $2.00입니다.
Cashew Nuts and White Mushromos 메뉴의 변경된 가격은 $9.90입니다.
Dried Mulberries 메뉴의 변경된 가격은 $6.00입니다.
Eggplant with Chili sauce 메뉴의 변경된 가격은 $13.00입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-11) foreach()에서 숫자 키 배열 사용하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$dinner = array(&amp;#39;스위트콘과 아스파라거스&amp;#39;,
                                &amp;#39;레몬 치킨&amp;#39;,
                                &amp;#39;삶은 망태버섯&amp;#39;);

foreach ($dinner as $dish) {
    print &amp;quot;주문가능 메뉴 : $dish\n&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;주문가능 메뉴 : 스위트콘과 아스파라거스
주문가능 메뉴 : 레몬 치킨
주문가능 메뉴 : 삶은 망태버섯&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-12) for()로 숫자 키 배열 순회하기&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;숫자 키 배열을 순회하는 동안 현재 원소가 무엇인지 알려면 foreach() 대신 for()를 써야함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$dinner = array(&amp;#39;스위트콘과 아스파라거스&amp;#39;,
                                &amp;#39;레몬 치킨&amp;#39;,
                                &amp;#39;삶은 망태버섯&amp;#39;);
for ($i = 0, $num_dishes = count($dinner); $i &amp;lt; $num_dishes; $i++) {
    print &amp;quot;메뉴 번호 $i: $dinner[$i]\n&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;메뉴 번호 0: 스위트콘과 아스파라거스
메뉴 번호 1: 레몬 치킨
메뉴 번호 2: 삶은 망태버섯&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-13) for()로 테이블 행의 클래스명 번갈아 출력하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$row_styles = array(&amp;#39;even&amp;#39;,&amp;#39;odd&amp;#39;);
$dinner = array(&amp;#39;스위트콘&amp;#39;,
&amp;#39;레몬치킨&amp;#39;,
&amp;#39;삶은 망태버섯&amp;#39;
);
print &amp;#39;&amp;lt;table&amp;gt;&amp;#39;;

for ($i =0, $num_dishes = count($dinner); $i &amp;lt; $num_dishes; $i++ ){
    print &amp;#39;&amp;lt;tr class=&amp;quot;&amp;#39; . $row_styles[$i %2] . &amp;#39;&amp;quot;&amp;gt;&amp;#39;;
    print &amp;quot;&amp;lt;td&amp;gt;원소 $i&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$dinner[$i]&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\n&amp;quot;;
}

print &amp;#39;&amp;lt;/table&amp;gt;&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;table&amp;gt;
&amp;lt;tr class=&amp;quot;even&amp;quot;&amp;gt;&amp;lt;td&amp;gt;원소 0&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;스위트콘&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr class=&amp;quot;odd&amp;quot;&amp;gt;&amp;lt;td&amp;gt;원소 1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;레몬치킨&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr class=&amp;quot;even&amp;quot;&amp;gt;&amp;lt;td&amp;gt;원소 2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;삶은 망태버섯&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-14) 배열 원소 순서와 foreach()&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$letters[0] = &amp;#39;A&amp;#39;;
$letters[1] = &amp;#39;B&amp;#39;;
$letters[3] = &amp;#39;D&amp;#39;;
$letters[2] = &amp;#39;C&amp;#39;;

foreach ($letters as $letter) {
    print $letter;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;ABDC&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-15) 특정 키에 해당하는 원소가 있는지 확인하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$meals = array(&amp;#39;walnut bun&amp;#39; =&amp;gt; 1,
&amp;#39;cashew nut&amp;#39; =&amp;gt; 4.95,
&amp;#39;dried Mulberries&amp;#39; =&amp;gt; 3.00,
&amp;#39;eggplant with chili sauce&amp;#39; =&amp;gt; 6.50,
&amp;#39;shrimp puffs&amp;#39; =&amp;gt; 0);

$books = array(&amp;#39;이용객을위한 A급 중국어 안내&amp;#39;,
&amp;#39;중국의 요리 방식고 식사 문화&amp;#39;);

if (array_key_exists(&amp;#39;walnut bun&amp;#39;, $meals)) {
    print &amp;quot;네,Shirmp puffs 메뉴도 가능합니다.&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-16) 배열 원소 중 특정 값이 있는지 확인하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$meals = array(&amp;#39;walnut bun&amp;#39; =&amp;gt; 1,
&amp;#39;cashew nut&amp;#39; =&amp;gt; 4.95,
&amp;#39;dried Mulberries&amp;#39; =&amp;gt; 3.00,
&amp;#39;eggplant with chili sauce&amp;#39; =&amp;gt; 6.50,
&amp;#39;shrimp puffs&amp;#39; =&amp;gt; 0);

$books = array(&amp;#39;이용객을위한 A급 중국어 안내&amp;#39;,
&amp;#39;중국의 요리 방식고 식사 문화&amp;#39;);

if (in_array(3, $meals)) {
    print &amp;#39;가격이 $3인 메뉴가 있습니다.&amp;#39;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-17) 배열 원소 중 특정 값 찾기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$meals = array(&amp;#39;walnut bun&amp;#39; =&amp;gt; 1,
&amp;#39;cashew nut&amp;#39; =&amp;gt; 4.95,
&amp;#39;dried Mulberries&amp;#39; =&amp;gt; 3.00,
&amp;#39;eggplant with chili sauce&amp;#39; =&amp;gt; 6.50,
&amp;#39;shrimp puffs&amp;#39; =&amp;gt; 0);

$dish = array_search(6.50, $meals);
if ($dish) {
    print &amp;quot;$dish 메뉴의 가격은 \$6.50입니다.&amp;quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;eggplant with chili sauce 메뉴의 가격은 $6.50입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;배열의 원소를 제거하려면 unset()을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;unset($dishes[&amp;#39;Roast Duck&amp;#39;]);&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예제 4-21) implode()로 배열에서 문자열 생성하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$dimsum = array(&amp;#39;닭고기 번&amp;#39;, &amp;#39;오리발 구이&amp;#39;,&amp;#39;순무 케이크&amp;#39;);
$menu = implode(&amp;#39;, &amp;#39;, $dimsum);
print $menu;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;닭고기 번, 오리발 구이, 순무 케이크&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$letters = array(&amp;#39;A&amp;#39;, &amp;#39;B&amp;#39;, &amp;#39;C&amp;#39;, &amp;#39;D&amp;#39;);
print implode(&amp;#39;&amp;#39;, $letters);&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;ABCD&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4-22. implode()로 HTML  테이블행 출력하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$dimsum = array(&amp;#39;닭고기 번&amp;#39;, &amp;#39;오리발 구이&amp;#39;, &amp;#39;순무 케이크&amp;#39;);
print &amp;#39;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;#39; . implode(&amp;#39;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;#39;, $dimsum), &amp;#39;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4-23. explode()로 문자열에서 배열 생성하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$fish = &amp;#39;농어, 잉어, 꼬치고기, 가자미&amp;#39;;
$fish_list = explode(&amp;#39;, &amp;#39;,$fish);
print &amp;quot;두 번째 물고기는 $fish_list[1]입니다.&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;두 번째 물고기는 잉어입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4-24. sort()를 이용한 정렬&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$dinner = array(
&amp;#39;Sweet Corn and Asparagus&amp;#39;,
&amp;#39;Lemon Chicken&amp;#39;,
&amp;#39;Braised Bamboo Fungus&amp;#39;
);

$meal = array(
&amp;#39;brrakfast&amp;#39; =&amp;gt; &amp;#39;Walnut Bun&amp;#39;,
&amp;#39;lunch&amp;#39; =&amp;gt; &amp;#39;Cashew Nuts and White Mushrooms&amp;#39;,
&amp;#39;snack&amp;#39; =&amp;gt; &amp;#39;Dried Mulberries&amp;#39;,
&amp;#39;dinner&amp;#39; =&amp;gt; &amp;#39;Eggplant with Chili Sauce&amp;#39;);

foreach ($dinner as $key =&amp;gt; $value) {
    print &amp;quot;\$dinnder : $key $value\n&amp;quot;;
}

foreach ($meal as $key =&amp;gt; $value) {
    print &amp;quot;\$meal : $key $value\n&amp;quot;;
}

sort($dinner);
sort($meal);

foreach ($dinner as $key =&amp;gt; $value) {
    print &amp;quot;\$dinndr : $key $value\n&amp;quot;;
}

foreach ($meal as $key =&amp;gt; $value) {
    print &amp;quot;\$meal : $key $value\n&amp;quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$dinner : 0 Sweet Corn and Asparagus 
$dinner : 1 Lemon Chicken 
$dinner : 2 Braised Bamboo Fungus 

$meal : brrakfast Walnut Bun 
$meal : lunch Cashew Nuts and White Mushrooms 
$meal : snack Dried Mulberries 
$meal : dinner Eggplant with Chili Sauce 

$dinndr : 0 Braised Bamboo Fungus 
$dinndr : 1 Lemon Chicken 
$dinndr : 2 Sweet Corn and Asparagus 

$meal : 0 Cashew Nuts and White Mushrooms 
$meal : 1 Dried Mulberries
$meal : 2 Eggplant with Chili Sauce
$meal : 3 Walnut Bunwalnut : 호두나무, 호두, 호두나무 재목, 호두 빛깔, 다갈색&lt;/code&gt;&lt;/pre&gt;</description>
      <category>PHP</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/57</guid>
      <comments>https://minimilab.tistory.com/57#entry57comment</comments>
      <pubDate>Mon, 15 Jun 2020 21:36:52 +0900</pubDate>
    </item>
    <item>
      <title>세탁특공대 자세한 이용 후기 및 이용 방법</title>
      <link>https://minimilab.tistory.com/53</link>
      <description>&lt;h1 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세탁특공대 자세한 이용 후기 및 방법 &lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;BIG Fashion Sale (1).png&quot; width=&quot;334&quot; height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cy8DNt/btqzfGu6EHG/NQKqE79TH15nOm84rabMf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cy8DNt/btqzfGu6EHG/NQKqE79TH15nOm84rabMf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cy8DNt/btqzfGu6EHG/NQKqE79TH15nOm84rabMf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcy8DNt%2FbtqzfGu6EHG%2FNQKqE79TH15nOm84rabMf1%2Fimg.png&quot; data-filename=&quot;BIG Fashion Sale (1).png&quot; width=&quot;334&quot; height=&quot;334&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;제가 사는 지역에서 세탁을 맡기러 가려면 15분정도를 걸어가야하는데,&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가까운데가&amp;nbsp;없나&amp;nbsp;찾아보다가&amp;nbsp;세탁특공대를&amp;nbsp;발견하게&amp;nbsp;되었습니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세탁특공대가 어플이라서 반신반의 했습니다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정말&amp;nbsp;신청하면&amp;nbsp;오는건가..&amp;nbsp;하면서&amp;nbsp;보았는데&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;첫 주문은 단 1장도 무료&lt;/span&gt;!라고 써있어서 신청을&amp;nbsp;했습니다. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;신청하는&amp;nbsp;것도&amp;nbsp;너무&amp;nbsp;간단합니다.&amp;nbsp;몇번의&amp;nbsp;클릭과&amp;nbsp;날짜,&amp;nbsp;시간을&amp;nbsp;지정하면&amp;nbsp;끝&amp;nbsp;!&amp;nbsp; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;IMG_0154-17640734-04e3-439e-9f01-ca0802450366.jpg&quot; width=&quot;500&quot; height=&quot;1081&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o43R4/btqzgotM6SG/gt6Az9agSwFOGkLixjEbK1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o43R4/btqzgotM6SG/gt6Az9agSwFOGkLixjEbK1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o43R4/btqzgotM6SG/gt6Az9agSwFOGkLixjEbK1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo43R4%2FbtqzgotM6SG%2Fgt6Az9agSwFOGkLixjEbK1%2Fimg.jpg&quot; data-filename=&quot;IMG_0154-17640734-04e3-439e-9f01-ca0802450366.jpg&quot; width=&quot;500&quot; height=&quot;1081&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;신청이&amp;nbsp;완료되면&amp;nbsp;아래와&amp;nbsp;같이&amp;nbsp;메세지를&amp;nbsp;받을&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메세지를&amp;nbsp;받은&amp;nbsp;어플&amp;nbsp;안에서&amp;nbsp;문의도&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있어서&amp;nbsp;매우&amp;nbsp;편리합니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;접수가&amp;nbsp;너무&amp;nbsp;쉬워서&amp;nbsp;접수가&amp;nbsp;잘&amp;nbsp;된&amp;nbsp;것이&amp;nbsp;맞는지&amp;nbsp;확인문의를&amp;nbsp;보냈는데,&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1분만에&amp;nbsp;대답이와서&amp;nbsp;안심할&amp;nbsp;수&amp;nbsp;있었습니다.&amp;nbsp; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled-12497067-c428-4276-ac2a-facd0d9ae18e.png&quot; width=&quot;503&quot; height=&quot;1089&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A0yte/btqzeZVZPoQ/NEwike0K9iQaySGp5h17VK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A0yte/btqzeZVZPoQ/NEwike0K9iQaySGp5h17VK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A0yte/btqzeZVZPoQ/NEwike0K9iQaySGp5h17VK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA0yte%2FbtqzeZVZPoQ%2FNEwike0K9iQaySGp5h17VK%2Fimg.png&quot; data-filename=&quot;Untitled-12497067-c428-4276-ac2a-facd0d9ae18e.png&quot; width=&quot;503&quot; height=&quot;1089&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아쉬웠던 점은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;수거,반납 시간이 4시간으로 너무 길다&lt;/span&gt;는 것..&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공동현관이&amp;nbsp;아닌&amp;nbsp;집은&amp;nbsp;문고리에&amp;nbsp;걸어놓으면&amp;nbsp;되니,&amp;nbsp;큰&amp;nbsp;불편함이&amp;nbsp;없을&amp;nbsp;것&amp;nbsp;같습니다. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만&amp;nbsp;저희&amp;nbsp;집은&amp;nbsp;공동현관이&amp;nbsp;키로&amp;nbsp;열려서&amp;nbsp;무조건&amp;nbsp;대면으로&amp;nbsp;주어야&amp;nbsp;해서&amp;nbsp;수거해가는&amp;nbsp;시간의&amp;nbsp;범위가&amp;nbsp;넓어서&amp;nbsp;주인기다리는&amp;nbsp;강아지마냥&amp;nbsp;세탁특공대를&amp;nbsp;기다렸습니다&amp;nbsp;ㅠㅠ&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;도로 사정으로 인해 조금 늦어진다고 메세지가와서 12시 30분에 수거해갔습니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;늦는다고&amp;nbsp;미리&amp;nbsp;메세지를&amp;nbsp;주셔서&amp;nbsp;딱히&amp;nbsp;불만은&amp;nbsp;없지만..&amp;nbsp;기다림이&amp;nbsp;더욱&amp;nbsp;길게&amp;nbsp;느껴졌습니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;처음에 신청하면 1개도 수거배달 무료이지만,&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저는&amp;nbsp;맡기는&amp;nbsp;김에&amp;nbsp;블라우스&amp;nbsp;1개&amp;nbsp;바지&amp;nbsp;4개를&amp;nbsp;맡겼습니다. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;블라우스&amp;nbsp;개당&amp;nbsp;2,900&amp;nbsp;원&amp;nbsp;,&amp;nbsp;바지&amp;nbsp;개당&amp;nbsp;2,900원&lt;/span&gt;으로&amp;nbsp;합리적인&amp;nbsp;가격인&amp;nbsp;것&amp;nbsp;같습니다. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요금을&amp;nbsp;살짝&amp;nbsp;살펴보자면&amp;nbsp;아래와&amp;nbsp;같습니다. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개인적으로&amp;nbsp;이불이&amp;nbsp;무거워서&amp;nbsp;세탁하기&amp;nbsp;어려운데,&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세탁특공대를&amp;nbsp;이용하면&amp;nbsp;알아서&amp;nbsp;수거해가니&amp;nbsp;편리할&amp;nbsp;것&amp;nbsp;같습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;IMG_0145-2eef6dff-6db3-4bcd-a83a-2a13b20a4413.png&quot; width=&quot;500&quot; height=&quot;1083&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uOPeq/btqzfED5pB8/9woslZkkwdIf6vue4wE0e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uOPeq/btqzfED5pB8/9woslZkkwdIf6vue4wE0e0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uOPeq/btqzfED5pB8/9woslZkkwdIf6vue4wE0e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuOPeq%2FbtqzfED5pB8%2F9woslZkkwdIf6vue4wE0e0%2Fimg.png&quot; data-filename=&quot;IMG_0145-2eef6dff-6db3-4bcd-a83a-2a13b20a4413.png&quot; width=&quot;500&quot; height=&quot;1083&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;IMG_0146-db409cfa-5041-4edb-89eb-8d129a37d549.png&quot; width=&quot;500&quot; height=&quot;1083&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEKCuS/btqzgpGaJqL/MoLbTI0AwX8H9UhNT77oK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEKCuS/btqzgpGaJqL/MoLbTI0AwX8H9UhNT77oK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEKCuS/btqzgpGaJqL/MoLbTI0AwX8H9UhNT77oK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEKCuS%2FbtqzgpGaJqL%2FMoLbTI0AwX8H9UhNT77oK0%2Fimg.png&quot; data-filename=&quot;IMG_0146-db409cfa-5041-4edb-89eb-8d129a37d549.png&quot; width=&quot;500&quot; height=&quot;1083&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;IMG_0147-eae77fe2-ab11-49ae-86cd-63d49fee9596.png&quot; width=&quot;501&quot; height=&quot;1085&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzjDif/btqzhgWjy0f/UciSNexacmZ9wqLKkFxSHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzjDif/btqzhgWjy0f/UciSNexacmZ9wqLKkFxSHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzjDif/btqzhgWjy0f/UciSNexacmZ9wqLKkFxSHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzjDif%2FbtqzhgWjy0f%2FUciSNexacmZ9wqLKkFxSHK%2Fimg.png&quot; data-filename=&quot;IMG_0147-eae77fe2-ab11-49ae-86cd-63d49fee9596.png&quot; width=&quot;501&quot; height=&quot;1085&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;수거를 해간 후에 세탁특공대에서 검수를 합니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그리고&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;검수하는&amp;nbsp;장면을&amp;nbsp;동영상&lt;/span&gt;으로 찍어서 올려주고, 제가 볼 수 있습니다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;신기방기&amp;nbsp;+.+ &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;IMG_0148-9317ec4f-9bbf-41c2-8088-7db033cb0bbf.png&quot; width=&quot;499&quot; height=&quot;1081&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ds3jUe/btqzf5BbJZu/k6Bo3Rl4a4EQZZ1vXF0EGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ds3jUe/btqzf5BbJZu/k6Bo3Rl4a4EQZZ1vXF0EGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ds3jUe/btqzf5BbJZu/k6Bo3Rl4a4EQZZ1vXF0EGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fds3jUe%2Fbtqzf5BbJZu%2Fk6Bo3Rl4a4EQZZ1vXF0EGk%2Fimg.png&quot; data-filename=&quot;IMG_0148-9317ec4f-9bbf-41c2-8088-7db033cb0bbf.png&quot; width=&quot;499&quot; height=&quot;1081&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; width=&quot;583&quot; height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oTYCF/btqzhrJ4fW9/aMt0n13VWtM11IkkCAR5Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oTYCF/btqzhrJ4fW9/aMt0n13VWtM11IkkCAR5Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oTYCF/btqzhrJ4fW9/aMt0n13VWtM11IkkCAR5Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoTYCF%2FbtqzhrJ4fW9%2FaMt0n13VWtM11IkkCAR5Ck%2Fimg.png&quot; data-filename=&quot;blob&quot; width=&quot;583&quot; height=&quot;312&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;어플에서 위에 동영상버튼을 클릭하면 위의 사진처럼 검수하는 장면을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세탁이 진행되고, 돌려주기 전에 결제를 하게 됩니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아래와&amp;nbsp;같이&amp;nbsp;14,500원을&amp;nbsp;결제했습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;IMG_0150-97adf81d-a123-424d-b8ce-7eb073b31054.png&quot; width=&quot;502&quot; height=&quot;1087&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhhyn/btqzgSuCx3J/QIiIiFYK4CmSQcqAZPzKI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhhyn/btqzgSuCx3J/QIiIiFYK4CmSQcqAZPzKI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhhyn/btqzgSuCx3J/QIiIiFYK4CmSQcqAZPzKI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flhhyn%2FbtqzgSuCx3J%2FQIiIiFYK4CmSQcqAZPzKI0%2Fimg.png&quot; data-filename=&quot;IMG_0150-97adf81d-a123-424d-b8ce-7eb073b31054.png&quot; width=&quot;502&quot; height=&quot;1087&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;보통 맡기고 이틀 뒤에 받아볼 수 있는 것 같습니다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저의&amp;nbsp;배송&amp;nbsp;예정일은&amp;nbsp;6일이었는데,&amp;nbsp;블라우스가&amp;nbsp;세탁이&amp;nbsp;늦어져&amp;nbsp;7일에&amp;nbsp;배달해준다고&amp;nbsp;연락이&amp;nbsp;왔습니다&amp;nbsp;ㅠ.ㅠ&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;바지는&amp;nbsp;다음날&amp;nbsp;필요했어서,&amp;nbsp;먼저&amp;nbsp;배달&amp;nbsp;받을&amp;nbsp;수&amp;nbsp;있는지&amp;nbsp;물어봤는데,&amp;nbsp;흔쾌히&amp;nbsp;두번&amp;nbsp;배송해주셨습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled-830e2be1-afad-4f45-b28a-757974c8776f.png&quot; width=&quot;502&quot; height=&quot;1087&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mhpiz/btqzicTcXsw/2GpKIU9oCHi8qhU0zksHN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mhpiz/btqzicTcXsw/2GpKIU9oCHi8qhU0zksHN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mhpiz/btqzicTcXsw/2GpKIU9oCHi8qhU0zksHN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmhpiz%2FbtqzicTcXsw%2F2GpKIU9oCHi8qhU0zksHN1%2Fimg.png&quot; data-filename=&quot;Untitled-830e2be1-afad-4f45-b28a-757974c8776f.png&quot; width=&quot;502&quot; height=&quot;1087&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저는 세탁특공대가 직접 세탁시설?을 구비해놓고 픽업을 알바생을 써서 하는 것이라고 생각했는데,&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세탁특공대가&amp;nbsp;처음&amp;nbsp;생겼을&amp;nbsp;때의&amp;nbsp;기사를&amp;nbsp;보니&amp;nbsp;반대였습니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;픽업을 세탁특공대가하고, 세탁시설은 동네 세탁소를 이용&lt;/span&gt;하는 것이었습니다 !!!&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;동네 세탁소 매출이 세탁특공대 덕분에 3배가 늘어난 곳도 있다고 하니, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서로가&amp;nbsp;윈윈할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;아주&amp;nbsp;좋은&amp;nbsp;서비스&amp;nbsp;인것&amp;nbsp;같습니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세탁특공대 광고에 반납할 때 주는 봉투를 쓰레기 봉투로 쓸 수 있는 것 처럼 광고하던데..&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;제가&amp;nbsp;잘못본&amp;nbsp;것인지&amp;nbsp;쓰레기&amp;nbsp;봉투는&amp;nbsp;아니어서&amp;nbsp;의아했습니다.&amp;nbsp;??&amp;nbsp;혹시&amp;nbsp;아시는&amp;nbsp;분? &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이용해보면서 불편한 점이 몇가지 있었지만..&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1.&amp;nbsp;약속시간을&amp;nbsp;잘&amp;nbsp;못지킨다.&amp;nbsp;(수거&amp;nbsp;30분&amp;nbsp;지각,&amp;nbsp;반납&amp;nbsp;1일&amp;nbsp;지각)&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2.&amp;nbsp;수거,&amp;nbsp;반납&amp;nbsp;시간이&amp;nbsp;4시간&amp;nbsp;범위어서&amp;nbsp;언제&amp;nbsp;오는지&amp;nbsp;명확하지&amp;nbsp;않아&amp;nbsp;오래&amp;nbsp;기다려야&amp;nbsp;한다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(출입할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;공동현관이면&amp;nbsp;상관없을&amp;nbsp;듯) &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;무거운&amp;nbsp;세탁물을&amp;nbsp;들고&amp;nbsp;세탁소까지&amp;nbsp;가는&amp;nbsp;고생을&amp;nbsp;하고&amp;nbsp;싶지&amp;nbsp;않고, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;늦더라도&amp;nbsp;미리미리&amp;nbsp;메세지로&amp;nbsp;알려주기&amp;nbsp;때문에, &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;다음&amp;nbsp;번에도&amp;nbsp;100&amp;nbsp;%&amp;nbsp;재&amp;nbsp;사용&amp;nbsp;의사&lt;/span&gt;가&amp;nbsp;있습니다.&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이상 세탁특공대를 직접 사용해보고 작성한 자세한 후기였습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>어플추천</category>
      <category>세탁 어플</category>
      <category>세탁특공대</category>
      <category>세탁특공대 사용 후기</category>
      <category>세탁특공대 어플</category>
      <category>세탁특공대 이용후기</category>
      <category>세탁특공대 후기</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/53</guid>
      <comments>https://minimilab.tistory.com/53#entry53comment</comments>
      <pubDate>Wed, 23 Oct 2019 21:56:36 +0900</pubDate>
    </item>
    <item>
      <title>시간, 습관 관리 유용한 애플워치 어플 추천 4가지 (1)</title>
      <link>https://minimilab.tistory.com/52</link>
      <description>&lt;p&gt;애플워치를 구매한지 세달이 조금 넘어가고 있습니다.&lt;br /&gt;구매하기 전에는 내가 과연 잘 쓸까? 라는 의문을 가지고 샀는데, 굉장히 만족하고 있습니다.&lt;/p&gt;
&lt;p&gt;애플워치를 유용하게 사용하고 싶어서, 이것저것 어플들을 많이 사용해보았습니다.&lt;br /&gt;그 결과 시간관리, 습관관리, 운동을 할 때 매우 유용하게 사용하고 있습니다.&lt;br /&gt;제가 직접 사용해보고, 지금까지도 계속 쓰고 있는 유용한 어플들을 공유하려고 합니다.&lt;/p&gt;
&lt;p&gt;작성하다보니 내용이 길어져, 이번 블로그 포스팅에는 유료로 사용하고 있는 어플을 소개하고&lt;br /&gt;다음 포스팅에는 무료 어플을 소개하고자 합니다.&lt;/p&gt;
&lt;h1 style=&quot;text-align: center;&quot;&gt;시간, 습관 관리 유용한 애플워치 어플 추천 4가지&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;Things&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;애플워치를 시계를 쳐다보았을 때 ,&lt;span style=&quot;background-color: #ffc9af;&quot;&gt; 내가 오늘 해야할 일&lt;/span&gt;이 무엇인지를 알려주면 좋을 것 같았습니다.&lt;br /&gt;그래서 그런 어플이 있는지 엄청 찾아보았는데, Things 어플이 제가 딱 원하는 어플이었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1282F752-5F9B-4456-BCBA-7E1CC06B5AF8-335a0e83-210e-4315-8094-941892975b79.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cb3ucH/btqzelj0UQI/6b6JIyOy7aaKKjDUa97xp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cb3ucH/btqzelj0UQI/6b6JIyOy7aaKKjDUa97xp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cb3ucH/btqzelj0UQI/6b6JIyOy7aaKKjDUa97xp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcb3ucH%2Fbtqzelj0UQI%2F6b6JIyOy7aaKKjDUa97xp0%2Fimg.png&quot; data-filename=&quot;1282F752-5F9B-4456-BCBA-7E1CC06B5AF8-335a0e83-210e-4315-8094-941892975b79.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위와 같은 식으로 애플워치 컴플리케이션 중앙에 해야할 일들을 노출할 수 있습니다.&lt;br /&gt;3개까지 노출할 수 있으며 클릭 시 어플로 들어가집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;047CE1CE-1546-4803-9AFE-388CDBD579E4-189473ca-26a2-4bb8-831d-72c16002c7d6.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byY4QN/btqzfPYxZn1/b3W7ZEclxdKk27Lw5cdWt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byY4QN/btqzfPYxZn1/b3W7ZEclxdKk27Lw5cdWt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byY4QN/btqzfPYxZn1/b3W7ZEclxdKk27Lw5cdWt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyY4QN%2FbtqzfPYxZn1%2Fb3W7ZEclxdKk27Lw5cdWt0%2Fimg.png&quot; data-filename=&quot;047CE1CE-1546-4803-9AFE-388CDBD579E4-189473ca-26a2-4bb8-831d-72c16002c7d6.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;클릭 했을 때 어플이 실행된 모습입니다.&lt;br /&gt;체크박스 버튼 클릭 시 처리완료 한 것으로 간주하여 LogBook 에 기록을 남기고 화면에서 사라집니다.&lt;br /&gt;&lt;br /&gt;정말 단순하지만 직관적인 할일 관리 어플입니다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;아래 사진이 아이폰 어플에서의 화면이며, &lt;br /&gt;어플에서 LogBook을 볼 수 있고 + 버튼을 눌러 할일을 추가할 수 있습니다.&lt;br /&gt;물론 애플워치에서도 음성인식으로 할일을 추가할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; width=&quot;329&quot; height=&quot;712&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTEhbB/btqzexLh4bd/k0S3HwW73Gci0NKCojdZm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTEhbB/btqzexLh4bd/k0S3HwW73Gci0NKCojdZm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTEhbB/btqzexLh4bd/k0S3HwW73Gci0NKCojdZm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTEhbB%2FbtqzexLh4bd%2Fk0S3HwW73Gci0NKCojdZm1%2Fimg.png&quot; data-filename=&quot;blob&quot; width=&quot;329&quot; height=&quot;712&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;또한 upcoming 에 할일을 작성해놓으면, &lt;br /&gt;지정해 놓은 날 당일에 할일이 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;자동으로 today todo list 에 추가&lt;/span&gt;됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;F9BA572C-2BBC-487F-AD58-51DC2C757B22-deab6523-adf0-44f2-8ee8-0cb9c1335569.png&quot; width=&quot;266&quot; height=&quot;575&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJ3Y77/btqze00w6xw/PKYgwUpvFr4DLXVRbdeUK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJ3Y77/btqze00w6xw/PKYgwUpvFr4DLXVRbdeUK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJ3Y77/btqze00w6xw/PKYgwUpvFr4DLXVRbdeUK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJ3Y77%2Fbtqze00w6xw%2FPKYgwUpvFr4DLXVRbdeUK0%2Fimg.png&quot; data-filename=&quot;F9BA572C-2BBC-487F-AD58-51DC2C757B22-deab6523-adf0-44f2-8ee8-0cb9c1335569.png&quot; width=&quot;266&quot; height=&quot;575&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;Atracker&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Atracker 앱은 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;시간을 어떻게 쓰고 있는지를 기록&lt;/span&gt;할 수 있고, 보고서 형태로 볼 수 있는 앱입니다.&lt;/p&gt;
&lt;p&gt;내가 시간을 사용하는 리스트를 만들어 놓고, 시간을 측정하고 싶을 때 그 항목을 클릭하면 시간 기록이 시작됩니다.&lt;br /&gt;한번 더 누르면 해당 시간까지 그 일을 한 것으로 기록이 됩니다.&lt;/p&gt;
&lt;p&gt;아래는 Atracker 애플워치 앱을 실행한 화면으로, 아이폰에서 생성해 놓은 목록을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;7C2817AA-276F-49B8-8F9E-F9556556A2DD-41093a3f-a832-45d5-9808-9b90f369685c.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5BIUm/btqzdyKGTbY/xCZJg9gakyjMtJtnd0gkU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5BIUm/btqzdyKGTbY/xCZJg9gakyjMtJtnd0gkU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5BIUm/btqzdyKGTbY/xCZJg9gakyjMtJtnd0gkU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5BIUm%2FbtqzdyKGTbY%2FxCZJg9gakyjMtJtnd0gkU0%2Fimg.png&quot; data-filename=&quot;7C2817AA-276F-49B8-8F9E-F9556556A2DD-41093a3f-a832-45d5-9808-9b90f369685c.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;목록을 한번 누르면 시간 측정이 시작됩니다.&lt;br /&gt;어플 내에서도 시간이 얼만큼 흘렀는지 확인할 수 있고, 애플워치 메인화면 컴플레케이션 중앙에 설정해놓으면&amp;nbsp;&lt;br /&gt;메인화면에서도 아래와 같이 시간이 얼마나 흘렀는지 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1ABE39F4-2DBB-4FFB-BFCF-D3C2706885BC-1fe0580f-891a-40d8-93a7-5f631d356cb3.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYGBzt/btqzeywGdkT/LvSN6k6TFNWCpwGxPKMurK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYGBzt/btqzeywGdkT/LvSN6k6TFNWCpwGxPKMurK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYGBzt/btqzeywGdkT/LvSN6k6TFNWCpwGxPKMurK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYGBzt%2FbtqzeywGdkT%2FLvSN6k6TFNWCpwGxPKMurK%2Fimg.png&quot; data-filename=&quot;1ABE39F4-2DBB-4FFB-BFCF-D3C2706885BC-1fe0580f-891a-40d8-93a7-5f631d356cb3.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;또 한가지 좋은 점은 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;보고서 형태&lt;/span&gt;로 내가 시간을 어떻게 썼는지 볼 수 있다는 점입니다.&lt;br /&gt;하루, 주간, 월간 특정 일을 얼마나 했는지 평균시간도 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; width=&quot;263&quot; height=&quot;567&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfWPFh/btqzeZHkUMs/PvcNCJzl4iwk5sbn9OkB4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfWPFh/btqzeZHkUMs/PvcNCJzl4iwk5sbn9OkB4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfWPFh/btqzeZHkUMs/PvcNCJzl4iwk5sbn9OkB4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfWPFh%2FbtqzeZHkUMs%2FPvcNCJzl4iwk5sbn9OkB4K%2Fimg.png&quot; data-filename=&quot;blob&quot; width=&quot;263&quot; height=&quot;567&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;MultiTimer&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;MultiTimer 는 어플이름 그대로 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;여러개의 타이머&lt;/span&gt;를 동시에 실행시킬 수 있는 애플워치 어플입니다.&lt;br /&gt;좋은 점은 모든 타이머가 다 있습니다.&lt;/p&gt;
&lt;p&gt;포모도로, 카운트 다운, 카운트 업, 스탑워치, 시간 각격 조절, 횟수 카운터, 시계 등 &lt;br /&gt;다양한 타이머를 만들어서 사용할 수 있고, 원하는 시간을 지정할 수 있습니다.&lt;/p&gt;
&lt;p&gt;또한 내가 재고 있는 시간이 동기화되어 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;애플워치, 아이폰은 물론 웹사이트에서도&amp;nbsp;&lt;/span&gt;실시간&lt;/span&gt;으로 볼 수 있습니다. &lt;br /&gt;여러명이 같은 시간을 재야하는 경우에도 유용하게 사용할 수 있을 것 같습니다.&lt;/p&gt;
&lt;p&gt;아래 사진과 같이 애플워치에서 여러개를 볼 수 있고, 동시에 실행할 수도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;E3E21ECF-08CE-417B-A447-D45EEA610FB1-44803a39-1557-4d0a-a405-51c0d8cc6082.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjcqfo/btqzfF2TaJW/cRbSRJKQziHr5YiJKEDmfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjcqfo/btqzfF2TaJW/cRbSRJKQziHr5YiJKEDmfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjcqfo/btqzfF2TaJW/cRbSRJKQziHr5YiJKEDmfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcjcqfo%2FbtqzfF2TaJW%2FcRbSRJKQziHr5YiJKEDmfk%2Fimg.png&quot; data-filename=&quot;E3E21ECF-08CE-417B-A447-D45EEA610FB1-44803a39-1557-4d0a-a405-51c0d8cc6082.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;한번 더 클릭을 하면 아래와 같이 크 화면으로 남은 시간과 진행상황을 보여줍니다.&amp;nbsp;&lt;br /&gt;종료가 되면 진동과 함께 시간이 다되었다고 알려줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;B2E6D6DF-2952-45C3-BC35-C5ECD49E8B78-cd1f5f12-32b6-417b-a3b3-9638399f7476.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b38yom/btqzej7AdZi/634mUHr7LM4FX1gdIOUOv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b38yom/btqzej7AdZi/634mUHr7LM4FX1gdIOUOv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b38yom/btqzej7AdZi/634mUHr7LM4FX1gdIOUOv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb38yom%2Fbtqzej7AdZi%2F634mUHr7LM4FX1gdIOUOv1%2Fimg.png&quot; data-filename=&quot;B2E6D6DF-2952-45C3-BC35-C5ECD49E8B78-cd1f5f12-32b6-417b-a3b3-9638399f7476.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;Streaks&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;streaks 는 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;습관관리 앱&lt;/span&gt;으로 유명한 앱입니다. 굉장히 직관적이고 사용하기 쉬운 앱입니다.&lt;/p&gt;
&lt;p&gt;아래 사진처럼 습관을 만들고 싶은 목록들을 추가하고, 수행을 한 후 클릭하여 완료했다고 표시할 수 있습니다.&lt;br /&gt;시간 단위로도 습관을 지정을 해놓을 수 있습니다.&lt;/p&gt;
&lt;p&gt;예를들어 블로그 글쓰기를 15분으로 지정하였습니다.&lt;br /&gt;블로그 글쓰기를 클릭하여 시작하면, 15분이 흐르는 것이 앱에 표시가 되며, 시간이 다되면 완료 표기가 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;0FF481B6-702B-4837-95A8-05E74A7BAD57-ecc7adae-269e-4ef8-b28b-b67f4a9213c5.png&quot; width=&quot;303&quot; height=&quot;656&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR5SDi/btqzdy4Yrr8/Xr2PM02rK2B8ltYM3pxlCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR5SDi/btqzdy4Yrr8/Xr2PM02rK2B8ltYM3pxlCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR5SDi/btqzdy4Yrr8/Xr2PM02rK2B8ltYM3pxlCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR5SDi%2Fbtqzdy4Yrr8%2FXr2PM02rK2B8ltYM3pxlCK%2Fimg.png&quot; data-filename=&quot;0FF481B6-702B-4837-95A8-05E74A7BAD57-ecc7adae-269e-4ef8-b28b-b67f4a9213c5.png&quot; width=&quot;303&quot; height=&quot;656&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;완료표시는 아래 사진의 비타민 먹기처럼 하얀색으로 표시되는 것입니다.&amp;nbsp;&lt;br /&gt;애플워치에서 streaks 를 실행하면 아래처럼 간단한 아이콘 모양으로 표시가 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ECCE7DAB-8C87-4E9B-9E2D-073E3400F630-21074343-cf85-43e4-8d21-37e89e14a239.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqpBHG/btqzeK4GOGN/Hftw1OvkwpDEYKQ7iyZihK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqpBHG/btqzeK4GOGN/Hftw1OvkwpDEYKQ7iyZihK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqpBHG/btqzeK4GOGN/Hftw1OvkwpDEYKQ7iyZihK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqpBHG%2FbtqzeK4GOGN%2FHftw1OvkwpDEYKQ7iyZihK%2Fimg.png&quot; data-filename=&quot;ECCE7DAB-8C87-4E9B-9E2D-073E3400F630-21074343-cf85-43e4-8d21-37e89e14a239.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;애플워치 메인화면에서는 가운데 중앙과 같이 표시가 되고,&lt;br /&gt;완료한 것은 흰색으로 표시가 되어 내가 오늘 하려고 했던 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;습관을 완료했는지의 여부&lt;/span&gt;를 쉽게 파악할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1F7ECF1D-8F3A-4081-8E01-55E0CEA6F93B-a55d3359-7cf4-4483-90c5-07d147d172c8.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1RRel/btqzfGtZWkD/Ogf6fpC4OasZk3Q1d3V78K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1RRel/btqzfGtZWkD/Ogf6fpC4OasZk3Q1d3V78K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1RRel/btqzfGtZWkD/Ogf6fpC4OasZk3Q1d3V78K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1RRel%2FbtqzfGtZWkD%2FOgf6fpC4OasZk3Q1d3V78K%2Fimg.png&quot; data-filename=&quot;1F7ECF1D-8F3A-4081-8E01-55E0CEA6F93B-a55d3359-7cf4-4483-90c5-07d147d172c8.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>책.영화.정보</category>
      <category>apple watch 앱 추천</category>
      <category>애플워치 생산성</category>
      <category>애플워치 습관 어플</category>
      <category>애플워치 시간 어플</category>
      <category>애플워치 앱 추천</category>
      <category>애플워치 어플 추천</category>
      <category>애플워치 유용한 어플</category>
      <category>애플워치 활용</category>
      <category>애플워치 활용팁</category>
      <category>애플워치5 어플 추천</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/52</guid>
      <comments>https://minimilab.tistory.com/52#entry52comment</comments>
      <pubDate>Tue, 22 Oct 2019 22:18:10 +0900</pubDate>
    </item>
    <item>
      <title>AngularJS directive 지시자</title>
      <link>https://minimilab.tistory.com/51</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span&gt;inflearn 의 Start Google Angular.js 앵귤러&amp;nbsp;과정&amp;nbsp;강좌를&amp;nbsp;보고&amp;nbsp;정리한&amp;nbsp;내용입니다.&lt;/span&gt;&lt;br /&gt;&lt;a href=&quot;https://www.inflearn.com/course/angular-js&quot;&gt;https://www.inflearn.com/course/angular-js&lt;/a&gt;&lt;/blockquote&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;지시자란 ?&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;AngularJS 애플리케이션에서 HTML 문서 구성을 위해 필요한 다양한 설정과 기능들을 의미합니다.&lt;br /&gt;ng-app : Angular JS 애플리케이션에 대한 초기 설정&lt;br /&gt;ng-init : Angular JS 애플리케이션에서 사용할 데이터 설정&lt;br /&gt;ng-model : HTML에서의 입력 요소들을 컨트롤 하기 위한 지시자&lt;br /&gt;ng-repeat :지정된 태그를 배열에 들어 있는 요소 만큼 반복하여 출력한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;AngularJS directive&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;directive 함수를 통해 지시자를 만들 수 있으며 새롭게 만든 지시자를 이용해 HTMl 원하는 곳에 코드를 삽입할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1571548487780&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.directive(&quot;directive1&quot;, function(){
		return {
			restrict : &quot;E&quot;,
			template : &quot;사용자 정의 지시자1&quot;
		}
	})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;restrict 속성을 이용해 적용할 요소를 선택할 수 있습니다.&lt;/p&gt;
&lt;p&gt;E : 태그&lt;br /&gt;A : 속성&lt;br /&gt;C : class 속성&lt;br /&gt;M : 주석&lt;br /&gt;생략 시 EA 로 설정됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1571548537401&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
&amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&amp;gt;
&amp;lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;script&amp;gt;
	var app = angular.module(&quot;test_app&quot;, [])
	
	app.directive(&quot;directive1&quot;, function(){
		return {
			restrict : &quot;E&quot;,
			template : &quot;사용자 정의 지시자1&quot;
		}
	})
	app.directive(&quot;directive2&quot;, function(){
		return {
			restrict : &quot;A&quot;,
			template : &quot;사용자 정의 지시자2&quot;
		}
	})
	app.directive(&quot;directive3&quot;, function(){
		return {
			restrict : &quot;C&quot;,
			template : &quot;사용자 정의 지시자3&quot;
		}
	})
	app.directive(&quot;directive4&quot;, function(){
		return {
			restrict : &quot;M&quot;,
			replace : true,
			template : &quot;&amp;lt;p&amp;gt;사용자 지시자 4 : 사용자 정의 지시자4&amp;lt;/p&amp;gt;&quot;
		}
	})
	
	app.directive(&quot;directive5&quot;, function(){
		return {
			restrict : &quot;EC&quot;,
			template : &quot;사용자 정의 지시자5&quot;
		}
	})
&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div ng-app=&quot;test_app&quot; ng-init=&quot;data1=100;data2='문자열';data3='red';data4=[100, 200, 300]&quot;&amp;gt;
	&amp;lt;p&amp;gt;data1 : {{data1}}&amp;lt;/p&amp;gt;
	&amp;lt;p&amp;gt;data2 : {{data2}}&amp;lt;/p&amp;gt;
	&amp;lt;p&amp;gt;data3 : {{data3}}&amp;lt;/p&amp;gt;
	&amp;lt;p style=&quot;color:{{data3}}&quot;&amp;gt;문자열&amp;lt;/p&amp;gt;
	&amp;lt;p ng-repeat=&quot;a1 in data4&quot;&amp;gt;{{a1}}&amp;lt;/p&amp;gt;
	&amp;lt;p&amp;gt;사용자 정의 지시자 1 : &amp;lt;directive1&amp;gt;&amp;lt;/directive1&amp;gt;&amp;lt;/p&amp;gt;
	&amp;lt;p&amp;gt;사용자 정의 지시자 2 : &amp;lt;span directive2&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
	&amp;lt;p&amp;gt;사용자 정의 지시자 3 : &amp;lt;span class=&quot;directive3&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
	&amp;lt;!-- directive: directive4 --&amp;gt;
	&amp;lt;p&amp;gt;사용자 정의 지시자 5 : &amp;lt;directive5&amp;gt;&amp;lt;/directive5&amp;gt;&amp;lt;/p&amp;gt;
	&amp;lt;p&amp;gt;사용자 정의 지시자 6 : &amp;lt;span class=&quot;directive5&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sqOwZ/btqzbWXI73d/xlfUATgYptaqZ6muxNl3rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sqOwZ/btqzbWXI73d/xlfUATgYptaqZ6muxNl3rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sqOwZ/btqzbWXI73d/xlfUATgYptaqZ6muxNl3rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsqOwZ%2FbtqzbWXI73d%2FxlfUATgYptaqZ6muxNl3rk%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;angularjs 관련 다른 글 ▼&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/47&quot;&gt;angular js 예제, 강의 정리 (module, controller, service, factory)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/48&quot;&gt;angularjs ng-model 이란?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/49&quot;&gt;angular js scope와 rootscope 의 차이&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/50&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;angularjs table 예제&lt;/a&gt;&lt;/p&gt;</description>
      <category>Front-end</category>
      <category>AngularJS directive</category>
      <category>angularjs directive example</category>
      <category>angularjs directive 강의</category>
      <category>angularjs directive 예제</category>
      <category>angularjs restrict</category>
      <category>angularjs 지시자</category>
      <category>angularjs 지시자란</category>
      <category>앵귤러js 지시자</category>
      <category>지시자</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/51</guid>
      <comments>https://minimilab.tistory.com/51#entry51comment</comments>
      <pubDate>Mon, 21 Oct 2019 07:00:42 +0900</pubDate>
    </item>
    <item>
      <title>angularjs table 예제</title>
      <link>https://minimilab.tistory.com/50</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span&gt;inflearn 의 Start Google Angular.js 앵귤러&amp;nbsp;과정&amp;nbsp;강좌를&amp;nbsp;보고&amp;nbsp;정리한&amp;nbsp;내용입니다.&lt;/span&gt;&lt;br /&gt;&lt;a href=&quot;https://www.inflearn.com/course/angular-js#&quot;&gt;https://www.inflearn.com/course/angular-js&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;angularjs&amp;nbsp;table&amp;nbsp;예제&lt;/h2&gt;
&lt;p&gt;app.controller 에서 선언한 data1 변수 내의 값을 &amp;lt;tr ng-repeat=&quot;obj in data1&quot;&amp;gt;로 접근합니다.&lt;br /&gt;ng-repeat 은 for 문으로 생각하면되고, obj.name, obj.age 로 data1 에서 선언한 변수에 접근할 수 있습니다.&lt;br /&gt;&amp;lt;tr&amp;gt; 태그는 테이블의 행을 만드는 html 태그로 &amp;lt;tr&amp;gt; 태그 내에 열을 만드는 &amp;lt;td&amp;gt; 태그에 &lt;span style=&quot;color: #333333;&quot;&gt;obj.name, obj.age&lt;span&gt; 데이터를 출력하면서 테이블을 만드는 예제입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1571495623421&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
&amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&amp;gt;
&amp;lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;script&amp;gt;
	var app = angular.module(&quot;test_app&quot;, [])
	
	app.controller(&quot;controller1&quot;, function($scope, $http){
		$scope.data1 = [
							{
								name : &quot;홍길동&quot;,
								age : 20
							},
							{
								name : &quot;강길동&quot;,
								age : 21
							},
							{
								name : &quot;최길동&quot;,
								age : 22
							}
		               ]
		var http = $http.get(&quot;data1.html&quot;)
		
		http.then(function(response){
			$scope.data2 = response.data
		})
	})
&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div ng-app=&quot;test_app&quot; ng-controller=&quot;controller1&quot;&amp;gt;
	&amp;lt;table border=&quot;1&quot;&amp;gt;
		&amp;lt;tr ng-repeat=&quot;obj in data1&quot;&amp;gt;
			&amp;lt;td&amp;gt;{{$index + 1}}&amp;lt;/td&amp;gt;
			&amp;lt;td ng-if=&quot;$odd&quot; style=&quot;color:red&quot;&amp;gt;{{obj.name}}&amp;lt;/td&amp;gt;
			&amp;lt;td ng-if=&quot;$even&quot; style=&quot;color:black&quot;&amp;gt;{{obj.name}}&amp;lt;/td&amp;gt;
			&amp;lt;td&amp;gt;{{obj.age}}&amp;lt;/td&amp;gt;
		&amp;lt;/tr&amp;gt;
	&amp;lt;/table&amp;gt;
	&amp;lt;hr/&amp;gt;
	&amp;lt;table border=&quot;1&quot;&amp;gt;
		&amp;lt;tr ng-repeat=&quot;obj in data2&quot;&amp;gt;
			&amp;lt;td&amp;gt;{{$index + 1}}&amp;lt;/td&amp;gt;
			&amp;lt;td ng-if=&quot;$odd&quot; style=&quot;color:red&quot;&amp;gt;{{obj.name}}&amp;lt;/td&amp;gt;
			&amp;lt;td ng-if=&quot;$even&quot; style=&quot;color:black&quot;&amp;gt;{{obj.name}}&amp;lt;/td&amp;gt;
			&amp;lt;td&amp;gt;{{obj.age}}&amp;lt;/td&amp;gt;
		&amp;lt;/tr&amp;gt;
	&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;IMG_1250.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daaAkF/btqy9GoKxjn/85EaiBMBtIJJ0DUAZlCBh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daaAkF/btqy9GoKxjn/85EaiBMBtIJJ0DUAZlCBh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daaAkF/btqy9GoKxjn/85EaiBMBtIJJ0DUAZlCBh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaaAkF%2Fbtqy9GoKxjn%2F85EaiBMBtIJJ0DUAZlCBh1%2Fimg.png&quot; data-filename=&quot;IMG_1250.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;angularjs 관련 다른 글 ▼&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/47&quot;&gt;angular js 예제, 강의 정리 (module, controller, service, factory)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/48&quot;&gt;angularjs ng-model 이란?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/49&quot;&gt;angular js scope와 rootscope 의 차이&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end</category>
      <category>angular table</category>
      <category>angular table example</category>
      <category>angularjs table example</category>
      <category>angularjs table 예제</category>
      <category>angularjs 강의</category>
      <category>angularjs 테이블</category>
      <category>angularjs 테이블 예제</category>
      <category>html 테이블 만들기</category>
      <category>앵귤러js 강의</category>
      <category>앵귤러js 테이블</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/50</guid>
      <comments>https://minimilab.tistory.com/50#entry50comment</comments>
      <pubDate>Sun, 20 Oct 2019 01:05:30 +0900</pubDate>
    </item>
    <item>
      <title>angular js scope와 rootscope 의 차이</title>
      <link>https://minimilab.tistory.com/49</link>
      <description>&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;inflearn 의 Start Google Angular.js 앵귤러&amp;nbsp;과정&amp;nbsp;강좌를&amp;nbsp;보고&amp;nbsp;정리한&amp;nbsp;내용입니다.&lt;br /&gt;&lt;a href=&quot;https://www.inflearn.com/course/angular-js#&quot;&gt;https://www.inflearn.com/course/angular-js&lt;/a&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;angular&amp;nbsp;js&amp;nbsp;scope와&amp;nbsp;rootscope&amp;nbsp;의&amp;nbsp;차이&lt;/h2&gt;
&lt;blockquote data-ke-size=&quot;size23&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;angularjs scope란?&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;scope 는 controller를 적용한 태그 내에서 사용할 변수나 함수를 저장해 놓을 수 있는 객체입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRddY5/btqzbaPMsSj/uCBvseWOBA5c7i9eZhzru0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRddY5/btqzbaPMsSj/uCBvseWOBA5c7i9eZhzru0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRddY5/btqzbaPMsSj/uCBvseWOBA5c7i9eZhzru0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRddY5%2FbtqzbaPMsSj%2FuCBvseWOBA5c7i9eZhzru0%2Fimg.png&quot; data-filename=&quot;1.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;angularjs rootscope란?&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;rootScope 는 문서 전체에서 사용할 변수나 함수를 저장해 놓는 객체입니다.&lt;br /&gt;$rootScope 를 지정한 app.run() 함수는 angularjs module 객체가 생성되면 실행되는 함수입니다.&lt;br /&gt;따라서 app module 객체가 생성되면 문서 전체에서 사용할 수 있는 data1, data2 변수가 생성됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dflXMj/btqza9QP317/KYgvWkrWOQvJeYKwha3vHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dflXMj/btqza9QP317/KYgvWkrWOQvJeYKwha3vHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dflXMj/btqza9QP317/KYgvWkrWOQvJeYKwha3vHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdflXMj%2Fbtqza9QP317%2FKYgvWkrWOQvJeYKwha3vHk%2Fimg.png&quot; data-filename=&quot;2.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;3.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNyYrb/btqzaZAUI7M/K2LN8hYIkfZfKjEbjgXku0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNyYrb/btqzaZAUI7M/K2LN8hYIkfZfKjEbjgXku0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNyYrb/btqzaZAUI7M/K2LN8hYIkfZfKjEbjgXku0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNyYrb%2FbtqzaZAUI7M%2FK2LN8hYIkfZfKjEbjgXku0%2Fimg.png&quot; data-filename=&quot;3.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;$rootScope 를 지정한 run 함수는 angularjs module 객체가 생성되면 실행되는 함수입니다.&lt;br /&gt;따라서 app 모듈 객체가 생성되면 data1 = 100, data2 = 200이 할당됩니다.&lt;br /&gt;먼저 선언된 $rootScope 보다 뒤에 선언된 controller의 data1 = 1000 에 따라 최종적으로 data1 에는 1000이 할당됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;4.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqaHSz/btqzbaWu2a5/l7eJ88c39rmHJj7z6cbr41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqaHSz/btqzbaWu2a5/l7eJ88c39rmHJj7z6cbr41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqaHSz/btqzbaWu2a5/l7eJ88c39rmHJj7z6cbr41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqaHSz%2FbtqzbaWu2a5%2Fl7eJ88c39rmHJj7z6cbr41%2Fimg.png&quot; data-filename=&quot;4.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;controller 에서 data2에는 값을 재할당하지 않았으므로,&lt;br /&gt;$rootScope 에서 설정한 200이 할당되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;5.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cplxmI/btqzb9WEBaO/wnNuRTQ6wcSveR6EcvgKkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cplxmI/btqzb9WEBaO/wnNuRTQ6wcSveR6EcvgKkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cplxmI/btqzb9WEBaO/wnNuRTQ6wcSveR6EcvgKkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcplxmI%2Fbtqzb9WEBaO%2FwnNuRTQ6wcSveR6EcvgKkK%2Fimg.png&quot; data-filename=&quot;5.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;controller 를 여러개 만들고, controller 마다 사용하는 data 변수를 다르게 지정해줄 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;6.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bskLv9/btqzbVYCP5v/fdnpjqhHMv22zEfcJQhOI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bskLv9/btqzbVYCP5v/fdnpjqhHMv22zEfcJQhOI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bskLv9/btqzbVYCP5v/fdnpjqhHMv22zEfcJQhOI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbskLv9%2FbtqzbVYCP5v%2FfdnpjqhHMv22zEfcJQhOI1%2Fimg.png&quot; data-filename=&quot;6.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;angularjs 관련 다른 글 ▼&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/47&quot;&gt;angular js 예제, 강의 정리 (module, controller, service, factory)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/48&quot;&gt;angularjs ng-model 이란?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/49&quot;&gt;angular js scope와 rootscope 의 차이&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/50&quot;&gt;angularjs table 예제&lt;/a&gt;&lt;/p&gt;</description>
      <category>Front-end</category>
      <category>angular js 스코프</category>
      <category>angular rootscope</category>
      <category>angularjs $rootscope</category>
      <category>angularjs rootscope 예제</category>
      <category>angularjs scope</category>
      <category>angularjs scope rootscope</category>
      <category>angularjs 강의</category>
      <category>앵귤러JS</category>
      <category>앵귤러js rootscope</category>
      <category>앵귤러js scope</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/49</guid>
      <comments>https://minimilab.tistory.com/49#entry49comment</comments>
      <pubDate>Sun, 20 Oct 2019 00:01:15 +0900</pubDate>
    </item>
    <item>
      <title>angularjs ng-model 이란?</title>
      <link>https://minimilab.tistory.com/48</link>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;inflearn 의 Start Google Angular.js 앵귤러&amp;nbsp;과정&amp;nbsp;강좌를&amp;nbsp;보고&amp;nbsp;정리한&amp;nbsp;내용입니다.&lt;br /&gt;&lt;a href=&quot;https://www.inflearn.com/course/angular-js#&quot;&gt;https://www.inflearn.com/course/angular-js#&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;angularjs&amp;nbsp;ng-model&amp;nbsp;이란?&lt;/h2&gt;
&lt;p&gt;ng-model 은 input, select, textarea 등의 태그에 ng-model을 지정하여 사용하며, &lt;br /&gt;UI에서 변경된 값을 인지하고, 변경된 값을 가져와 사용할 수 있는 지시어 입니다. &lt;br /&gt;화면에 보이는 데이터와 브라우저 메모리에 있는 데이터를 일치시킬 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TSd7c/btqzbFaDSDS/i5o633QIY1wZ3ZSw2ki4e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TSd7c/btqzbFaDSDS/i5o633QIY1wZ3ZSw2ki4e0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TSd7c/btqzbFaDSDS/i5o633QIY1wZ3ZSw2ki4e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTSd7c%2FbtqzbFaDSDS%2Fi5o633QIY1wZ3ZSw2ki4e0%2Fimg.png&quot; data-filename=&quot;1.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;ng-model=&quot;data1&quot; 로 input 에 지정을 해주었고,&lt;br /&gt;이에 따라 input 에 데이터를 입력하면 {{data1}} 표현식에 입력한 데이터가 출력됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;3.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvv2y9/btqzasDzIiL/dkVNuKNJ04MtKFzCvgIJ31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvv2y9/btqzasDzIiL/dkVNuKNJ04MtKFzCvgIJ31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvv2y9/btqzasDzIiL/dkVNuKNJ04MtKFzCvgIJ31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcvv2y9%2FbtqzasDzIiL%2FdkVNuKNJ04MtKFzCvgIJ31%2Fimg.png&quot; data-filename=&quot;3.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;input 창에 입력한 abcd, 116666 값이 출력되는 것을 확인하실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;4.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NzIqY/btqy917hP9U/tWJp3obgGlxuOeMlYKqiw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NzIqY/btqy917hP9U/tWJp3obgGlxuOeMlYKqiw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NzIqY/btqy917hP9U/tWJp3obgGlxuOeMlYKqiw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNzIqY%2Fbtqy917hP9U%2FtWJp3obgGlxuOeMlYKqiw1%2Fimg.png&quot; data-filename=&quot;4.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;input 에 입력한 값이 숫자이거나 email 형식의 주소가 아닌 경우에,&lt;br /&gt;$error 라는 지시어를 활용하여 어떤 데이터 타입을 입력하였는지 확인할 수 있습니다.&lt;br /&gt;이에 따라 &quot;숫자 입력 오류&quot;, &quot;이메일 입력 오류&quot; 라는 메세지를 출력할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;5.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OLl11/btqy9FpNiOb/WmkiFXKAawkuKANuDXljc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OLl11/btqy9FpNiOb/WmkiFXKAawkuKANuDXljc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OLl11/btqy9FpNiOb/WmkiFXKAawkuKANuDXljc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOLl11%2Fbtqy9FpNiOb%2FWmkiFXKAawkuKANuDXljc0%2Fimg.png&quot; data-filename=&quot;5.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;6.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2O8Qe/btqy9GoIA5c/9QSpo0sNsFflvLYrfPM0I0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2O8Qe/btqy9GoIA5c/9QSpo0sNsFflvLYrfPM0I0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2O8Qe/btqy9GoIA5c/9QSpo0sNsFflvLYrfPM0I0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2O8Qe%2Fbtqy9GoIA5c%2F9QSpo0sNsFflvLYrfPM0I0%2Fimg.png&quot; data-filename=&quot;6.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;7.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cD94X8/btqzaZU9VCk/XsUCtw6REZVccxOp8D1PAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cD94X8/btqzaZU9VCk/XsUCtw6REZVccxOp8D1PAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cD94X8/btqzaZU9VCk/XsUCtw6REZVccxOp8D1PAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcD94X8%2FbtqzaZU9VCk%2FXsUCtw6REZVccxOp8D1PAk%2Fimg.png&quot; data-filename=&quot;7.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;10.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVikDG/btqzbaoFPuY/TXQa8ifWpFQTwGH9Y6C080/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVikDG/btqzbaoFPuY/TXQa8ifWpFQTwGH9Y6C080/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVikDG/btqzbaoFPuY/TXQa8ifWpFQTwGH9Y6C080/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVikDG%2FbtqzbaoFPuY%2FTXQa8ifWpFQTwGH9Y6C080%2Fimg.png&quot; data-filename=&quot;10.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;16.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dox9oS/btqzbEQks3b/MkKs5dmR3lpMdUABo10Xx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dox9oS/btqzbEQks3b/MkKs5dmR3lpMdUABo10Xx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dox9oS/btqzbEQks3b/MkKs5dmR3lpMdUABo10Xx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdox9oS%2FbtqzbEQks3b%2FMkKs5dmR3lpMdUABo10Xx0%2Fimg.png&quot; data-filename=&quot;16.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1571493672716&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
&amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&amp;gt;
&amp;lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;style&amp;gt;
	/* 비여있을 경우 */
	.test_css.ng-empty{
		background-color : aqua;
	}
	/* 입력이 되어 있을 경우 */
	.test_css.ng-not-empty {
		background-color : fuchsia;
	}
	/* 클릭한 적이 있을 경우 */
	.test_css.ng-touched{
		width : 200px;
	}
	/* 클릭하기 전 */
	.test_css.ng-untouched{
		width : 1000px;
	}
	/* 유효한 값이 들어 있을 때 */
	.test_css.ng-valid{
		height:200px;
	}
	/* 유효하지 않은 값이 들어 있을 때 */
	.test_css.ng-invalid{
		height:100px;
	}
	/*최초에 입력된 값과 다른 값이 입력된 경우 */
	.test_css.ng-dirty{
		color : white;
	}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div ng-app=&quot;&quot;&amp;gt;
	data1 : &amp;lt;input type=&quot;text&quot; ng-model=&quot;data1&quot;/&amp;gt;&amp;lt;br/&amp;gt;
	data2 : &amp;lt;input type=&quot;texT&quot; ng-model=&quot;data2&quot;/&amp;gt;&amp;lt;br/&amp;gt;
	&amp;lt;hr/&amp;gt;
	data1 : {{data1}}&amp;lt;br/&amp;gt;
	data2 : {{data2}}&amp;lt;br/&amp;gt;
	&amp;lt;hr/&amp;gt;
	&amp;lt;form ng-app=&quot;&quot; name=&quot;myForm&quot;&amp;gt;
		&amp;lt;input type=&quot;number&quot; name=&quot;number1&quot; ng-model=&quot;number1&quot;/&amp;gt;&amp;lt;br/&amp;gt;
		&amp;lt;span ng-show=&quot;myForm.number1.$error.number&quot;&amp;gt;숫자 입력 오류&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
		
		&amp;lt;input type=&quot;email&quot; name=&quot;email1&quot; ng-model=&quot;email1&quot;/&amp;gt;&amp;lt;br/&amp;gt;
		&amp;lt;span ng-show=&quot;myForm.email1.$error.email&quot;&amp;gt;이메일 입력 오류&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
		&amp;lt;button type=&quot;submit&quot;&amp;gt;확인&amp;lt;/button&amp;gt;
	&amp;lt;/form&amp;gt;
	&amp;lt;hr/&amp;gt;
	&amp;lt;form ng-app=&quot;&quot; name=&quot;myForm2&quot;&amp;gt;
		&amp;lt;input type=&quot;email&quot; name=&quot;email2&quot; ng-model=&quot;email2&quot;/&amp;gt;
	&amp;lt;/form&amp;gt;
	&amp;lt;p&amp;gt;vaild(유효한 값일 true) : {{myForm2.email2.$valid}}&amp;lt;/p&amp;gt;
	&amp;lt;p&amp;gt;dirty(초기값에서 변경되었을 때 true) : {{myForm2.email2.$dirty}}&amp;lt;/p&amp;gt;
	&amp;lt;p&amp;gt;Touched(포커스를 잃었을 경우 true) : {{myForm2.email2.$touched}}&amp;lt;/p&amp;gt;
	
	&amp;lt;input type=&quot;email&quot; name=&quot;email3&quot; class=&quot;test_css&quot; ng-model=&quot;email3&quot;/&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;/body&amp;gt;

&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;angularjs 관련 다른 글 ▼&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/47&quot;&gt;angular js 예제, 강의 정리 (module, controller, service, factory)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/48&quot;&gt;angularjs ng-model 이란?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/49&quot;&gt;angular js scope와 rootscope 의 차이&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/50&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;angularjs table 예제&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end</category>
      <category>AngularJS</category>
      <category>angularjs model</category>
      <category>angularjs ngmodel 사용법</category>
      <category>angularjs 데이터 바인딩</category>
      <category>angularjs 데이터바인딩</category>
      <category>angularjs 예제</category>
      <category>ng-model 사용법</category>
      <category>ng-model 예제</category>
      <category>ng-model 이란</category>
      <category>ngmodel 이란</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/48</guid>
      <comments>https://minimilab.tistory.com/48#entry48comment</comments>
      <pubDate>Sat, 19 Oct 2019 22:10:33 +0900</pubDate>
    </item>
    <item>
      <title>angular js 예제, 강의 정리 (module, controller, service, factory)</title>
      <link>https://minimilab.tistory.com/47</link>
      <description>&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;인프런의&amp;nbsp;Start&amp;nbsp;Google&amp;nbsp;&lt;a href=&quot;Angular.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Angular.js&lt;/a&gt;&amp;nbsp;앵귤러&amp;nbsp;과정&amp;nbsp;강좌를&amp;nbsp;보고&amp;nbsp;정리한&amp;nbsp;내용입니다. &lt;br /&gt;&lt;a href=&quot;https://www.inflearn.com/course/angular-js#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.inflearn.com/course/angular-js#&lt;/a&gt;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;factory&amp;nbsp;는&amp;nbsp;아래&amp;nbsp;유투브를&amp;nbsp;참고하였습니다. &lt;br /&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=UXu9xmSIhRs&amp;amp;list=PLYxzS__5yYQmX2bItSRCqwiQZn5dIL1gt&amp;amp;index=24&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/watch?v=UXu9xmSIhRs&amp;amp;list=PLYxzS__5yYQmX2bItSRCqwiQZn5dIL1gt&amp;amp;index=24&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;angular js 예제, 강의 정리&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;표현식,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;module(&lt;/span&gt;모듈),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;controller(&lt;/span&gt;컨트롤러),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;service(&lt;/span&gt;서비스),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;factory(&lt;/span&gt;팩토리)&lt;/h1&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;표현식&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;원하는 곳에 원하는 데이터를 출력하는 구문으로 {{출력값}} 형식으로 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vaMcF/btqy6dEK623/U0cWi6Y435yIJoEBkaiic0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vaMcF/btqy6dEK623/U0cWi6Y435yIJoEBkaiic0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vaMcF/btqy6dEK623/U0cWi6Y435yIJoEBkaiic0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvaMcF%2Fbtqy6dEK623%2FU0cWi6Y435yIJoEBkaiic0%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;ng-init 에 변수 data1을 만든 후 100 값을 넣었습니다.&lt;br /&gt;{{}} 안에 변수명인 data1 을 넣어 100이 출력되도록 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rT32z/btqy6eDFHD1/KGMqk9RMcZlWl290JUEyK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rT32z/btqy6eDFHD1/KGMqk9RMcZlWl290JUEyK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rT32z/btqy6eDFHD1/KGMqk9RMcZlWl290JUEyK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrT32z%2Fbtqy6eDFHD1%2FKGMqk9RMcZlWl290JUEyK0%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;여러개의 변수(str, dict, array) 와 값을 ng-init 에 넣어서 출력할 수 있습니다.&lt;br /&gt;참고 : ng-init 이 너무 길어질 경우, controller 를 사용하여 데이터를 제어하는 것이 용이합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh5xA4/btqy32LnJxa/eTKmUvrr9K5kwD70mmQxbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh5xA4/btqy32LnJxa/eTKmUvrr9K5kwD70mmQxbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh5xA4/btqy32LnJxa/eTKmUvrr9K5kwD70mmQxbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbh5xA4%2Fbtqy32LnJxa%2FeTKmUvrr9K5kwD70mmQxbk%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block; text-align: center;&quot; data-ad-layout=&quot;in-article&quot; data-ad-format=&quot;fluid&quot; data-ad-client=&quot;ca-pub-5170996487649025&quot; data-ad-slot=&quot;1473138310&quot;&gt;&lt;/ins&gt;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;module(모듈)&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;지시자 설정, 함수 정의 등을 할 수 있는 angular js 의 객체형태입니다.&lt;br /&gt;controller, service, factory 등 모듈에 다양한 설정을 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/21rtK/btqy4rKHasW/dqOH1orLEW11L9Utky26fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/21rtK/btqy4rKHasW/dqOH1orLEW11L9Utky26fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/21rtK/btqy4rKHasW/dqOH1orLEW11L9Utky26fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F21rtK%2Fbtqy4rKHasW%2FdqOH1orLEW11L9Utky26fk%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;app 이라는 변수에 test_app 이라는 angular 모듈을 선언합니다.&lt;br /&gt;test_app 의 이름으로 선언한 모듈은 div 태그 안에 ng-app=&quot;test_app&quot;의 형식으로 설정하였습니다.&lt;br /&gt;test_app 모듈에 요소들(controller, service, 지시자 등)을 설정하면 div 태&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;그 내에서 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;* 참고 : 지시자&lt;br /&gt;ng-app : Angular js 애플리케이션에 대한 초기 설정&lt;br /&gt;ng-init : 애플리케이션에서 사용할 데이터 설정&lt;br /&gt;ng-model : HTML 에서의 입력 요소(input)들을 컨트롤하기 위한 지시자&lt;br /&gt;ng-repeat : 지정된 태그를 배열에 들어 있는 요소만큼 반복하여 출력한다.&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block; text-align: center;&quot; data-ad-layout=&quot;in-article&quot; data-ad-format=&quot;fluid&quot; data-ad-client=&quot;ca-pub-5170996487649025&quot; data-ad-slot=&quot;1473138310&quot;&gt;&lt;/ins&gt;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;controller(컨트롤러)&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;컨트롤러는 html 파일의 div 태그 안에서 사용할 멤버 및 데이터들을 통제하기 위해 사용합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUY969/btqy29RykwR/ZCHW851YcwIP47klzxSukK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUY969/btqy29RykwR/ZCHW851YcwIP47klzxSukK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUY969/btqy29RykwR/ZCHW851YcwIP47klzxSukK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUY969%2Fbtqy29RykwR%2FZCHW851YcwIP47klzxSukK%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;모듈을 생성한 app 변수에 app.controller() 형식으로 컨트롤러를 설정할 수 있습니다.&lt;br /&gt;컨트롤러는 div 안에서 사용할 멤버들을 정의합니다.&lt;br /&gt;모듈에 설정한 test_controller를 div 태그 안에 ng-controller 에 적용함으로써, app.controller() 안에서 적용했던 변수들을 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beJujg/btqy4dTw9mZ/i1TFj0zYdJkwf1SlhDrr30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beJujg/btqy4dTw9mZ/i1TFj0zYdJkwf1SlhDrr30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beJujg/btqy4dTw9mZ/i1TFj0zYdJkwf1SlhDrr30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeJujg%2Fbtqy4dTw9mZ%2Fi1TFj0zYdJkwf1SlhDrr30%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;컨트롤러에서 함수도 설정할수 있습니다.&lt;br /&gt;값 변경을 클릭 시, input 에 입력한 data1, data2 가 br 태그 앞에 노출되도록 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7pC1e/btqy3aJGNBG/YP6gBaw2dNp1nyZEP7yWOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7pC1e/btqy3aJGNBG/YP6gBaw2dNp1nyZEP7yWOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7pC1e/btqy3aJGNBG/YP6gBaw2dNp1nyZEP7yWOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7pC1e%2Fbtqy3aJGNBG%2FYP6gBaw2dNp1nyZEP7yWOk%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block; text-align: center;&quot; data-ad-layout=&quot;in-article&quot; data-ad-format=&quot;fluid&quot; data-ad-client=&quot;ca-pub-5170996487649025&quot; data-ad-slot=&quot;1473138310&quot;&gt;&lt;/ins&gt;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;service(서비스)&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;angular js 에서 제공하고 있는 다양한 기능들을 가지고 있는 객체들을 의미합니다.&lt;br /&gt;필요하면 서비스를 만들어서 사용할 수 있습니다.&lt;br /&gt;만든 서비스 객체는 controller 에 추가하여 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mcN5u/btqy5DYeu78/1Yby9Ca7OQwb9chpDpLaS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mcN5u/btqy5DYeu78/1Yby9Ca7OQwb9chpDpLaS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mcN5u/btqy5DYeu78/1Yby9Ca7OQwb9chpDpLaS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmcN5u%2Fbtqy5DYeu78%2F1Yby9Ca7OQwb9chpDpLaS0%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;myService 를 정의 후, controller 에 등록했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8qUMF/btqy6ejmG1T/2l6k1T3Zhc5NyYO8VQPpO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8qUMF/btqy6ejmG1T/2l6k1T3Zhc5NyYO8VQPpO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8qUMF/btqy6ejmG1T/2l6k1T3Zhc5NyYO8VQPpO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8qUMF%2Fbtqy6ejmG1T%2F2l6k1T3Zhc5NyYO8VQPpO1%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;등록한 myService 에 add, subtract 함수가 선언되어 있는데,&lt;br /&gt;해당 함수들을 controller 안에서 myService.add(), myService.subtract() 와 같은 형식으로 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고&lt;/b&gt;&lt;br /&gt;$scope 도 서비스 객체의 한 종류입니다.&lt;br /&gt;$location 객체 : 주소 창의 주소를 관리합니다.&lt;br /&gt;$get : ajax 통신을 통해 다른 파일의 응답 결과를 가져옵니다.&lt;br /&gt;$timeout : javascript 의 timeout&lt;br /&gt;$interval : javascript 의 interval&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block; text-align: center;&quot; data-ad-layout=&quot;in-article&quot; data-ad-format=&quot;fluid&quot; data-ad-client=&quot;ca-pub-5170996487649025&quot; data-ad-slot=&quot;1473138310&quot;&gt;&lt;/ins&gt;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;factory (팩토리)&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;service 는 싱글턴 패턴으로 객체를 하나만 사용할 수 있습니다.&lt;br /&gt;다양한 형태의 객체를 controller 에서 사용할 수 있도록 하는 요소가 factory 입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A5Qqx/btqy4dzaIlV/1S2zEfrX0Qg6uNYO77MTf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A5Qqx/btqy4dzaIlV/1S2zEfrX0Qg6uNYO77MTf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A5Qqx/btqy4dzaIlV/1S2zEfrX0Qg6uNYO77MTf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA5Qqx%2Fbtqy4dzaIlV%2F1S2zEfrX0Qg6uNYO77MTf0%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;factory 를 사용할 때는 this 대신 새롭게 만든 객체를 사용하고 return 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;angularjs 관련 다른 글 ▼&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/47&quot;&gt;angular js 예제, 강의 정리 (module, controller, service, factory)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/48&quot;&gt;angularjs ng-model 이란?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/49&quot;&gt;angular js scope와 rootscope 의 차이&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/50&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;angularjs table 예제&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end</category>
      <category>angularjs controller</category>
      <category>angularjs factory</category>
      <category>angularjs module</category>
      <category>angularjs service</category>
      <category>angularjs 강의</category>
      <category>angularjs 강좌</category>
      <category>angularjs 모듈</category>
      <category>angularjs 서비스</category>
      <category>angularjs 예제</category>
      <category>angularjs 팩토리</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/47</guid>
      <comments>https://minimilab.tistory.com/47#entry47comment</comments>
      <pubDate>Wed, 16 Oct 2019 01:09:46 +0900</pubDate>
    </item>
    <item>
      <title>python requests _ssl.c:510: error:14090086:SSL routines:SSL3 error 해결 방법</title>
      <link>https://minimilab.tistory.com/45</link>
      <description>&lt;p&gt;파이썬에서 requests.get() 사용 시 ssl3 error(에러)가 나는 경우가 있다.&lt;br /&gt;가장 좋은 방법은 필요한 인증서와 호스트명을 넣고 올바른 SSL 통신을 하는 것이지만&lt;br /&gt;간단하게 해결할 수 있는 3가지 해결 방법을 기록한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;verify=false 사용하기&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;가장 간단한 방법으로 인증서 인증을 하지 않는다는 의미로 requests.get 실행 시 verify=false 를 넣어준다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;response = requests.get(URL, verify=false)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;urllib2 사용하기&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;requests 대신 urllib2 를 사용하는 방법으로,&lt;br /&gt;requests.get()에서는 에러가 나도 urllib2.urlopen()으로는 에러가 나지 않는 경우가 많다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;response = urllib2.urlopen(URL).read()&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;업데이트 한 후 실행하기&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;pre id=&quot;code_1568735545181&quot; class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pip install --upgrade setuptools
$ pip install -U requests[security]&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python</category>
      <category>certificate verify</category>
      <category>CERTIFICATE_VERIFY_FAILED</category>
      <category>python requests ssl</category>
      <category>requests ssl</category>
      <category>requests verify false</category>
      <category>ssl 인증서 오류</category>
      <category>ssl.c</category>
      <category>ssl3</category>
      <category>ssl3 error</category>
      <category>ssl3 에러</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/45</guid>
      <comments>https://minimilab.tistory.com/45#entry45comment</comments>
      <pubDate>Wed, 18 Sep 2019 00:55:29 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 선형탐색(Linear Search), 이진탐색(Binary Search)</title>
      <link>https://minimilab.tistory.com/44</link>
      <description>&lt;blockquote&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum BarunGothic';&quot;&gt;&lt;b&gt;선형 탐색(Linear Search)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum BarunGothic';&quot;&gt;리스트의 처음부터 끝까지 순서대로 하나씩 탐색을 진행하는 알고리즘&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def linear_search(element, some_list):
    for i in range(len(some_list)):
        if element == some_list[i]:
            return i
    return None

print(linear_search(2, [2, 3, 5, 7, 11]))
print(linear_search(0, [2, 3, 5, 7, 11]))
print(linear_search(5, [2, 3, 5, 7, 11]))
print(linear_search(3, [2, 3, 5, 7, 11]))
print(linear_search(11, [2, 3, 5, 7, 11]))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum BarunGothic';&quot;&gt;&lt;b&gt;이진 탐색(Binary Search)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum BarunGothic';&quot;&gt;이진탐색은 정렬된 리스트를 전제로 하며, 1회 비교를 할 때마다 탐색 범위가 절반(시간복잡도 : logn)으로 줄어든다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum BarunGothic';&quot;&gt;리스트의 첫 번째 인덱스와 마지막 인덱스의 값을 합하여 2로 나눈 후, 중간 인덱스로 지정한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum BarunGothic';&quot;&gt;구하고자 하는 숫자가, 중간 인덱스보다 적은 경우 중간 이후 값은 검색 범위에서 제외한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum BarunGothic';&quot;&gt;구하고자 하는 숫자가, 중간 인덱스보다 큰 경우 중간 이전 값은 범위에서 제외한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum BarunGothic';&quot;&gt;&lt;b&gt;반복문 사용 Version&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def binary_search(element, some_list):
    start_index = 0
    end_index = len(some_list) - 1

    while start_index &amp;lt;= end_index:
        # start_index 가 커지는 경우가 있으므로 (start_index + end_index) // 2
        mid_index = (start_index + end_index) // 2

        # element 가 mid_index 값과 같으면 return mid_index    
        if element == some_list[mid_index]:
            return mid_index

        # element 가 mid_index 값보다 적으면 end_index = mid_index - 1
        elif element &amp;lt; some_list[mid_index]:
            end_index = mid_index - 1

        # element 가 mid_index 값보다 크면 start_index = mid_index + 1
        else:
            start_index = mid_index + 1

    # 위의 조건에 만족하지 않는 경우(element가 list에 없는 경우) return None
    return None

print(binary_search(2, [2, 3, 5, 7, 11]))
print(binary_search(0, [2, 3, 5, 7, 11]))
print(binary_search(5, [2, 3, 5, 7, 11]))
print(binary_search(3, [2, 3, 5, 7, 11]))
print(binary_search(11, [2, 3, 5, 7, 11]))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum BarunGothic';&quot;&gt;&lt;b&gt;재귀 사용 Version&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def binary_search(element, some_list, start_index=0, end_index=None):
    # end_index가 따로 주어지지 않은 경우에는 리스트의 마지막 인덱스
    if end_index == None:
        end_index = len(some_list) - 1

    # 중간 인덱스 구하기
    mid_index = (start_index + end_index) // 2

    # start_index가 end_index보다 크면 some_list안에 element는 없다
    if start_index &amp;gt; end_index:
        return None

    # element 가 mid_index 값과 같으면 return mid_index    
    if element == some_list[mid_index]:
        return mid_index

    # element 가 mid_index 값보다 적으면 end_index = mid_index - 1
    elif element &amp;lt; some_list[mid_index]:
        return binary_search(element, some_list, start_index, mid_index-1)

    # element 가 mid_index 값보다 크면 start_index = mid_index + 1
    elif element &amp;gt; some_list[mid_index]:
        return binary_search(element, some_list, mid_index+1, end_index)


print(binary_search(2, [2, 3, 5, 7, 11]))
print(binary_search(0, [2, 3, 5, 7, 11]))
print(binary_search(5, [2, 3, 5, 7, 11]))
print(binary_search(3, [2, 3, 5, 7, 11]))
print(binary_search(11, [2, 3, 5, 7, 11]))&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <category>binary search</category>
      <category>liniear search</category>
      <category>python binary search</category>
      <category>python linear search</category>
      <category>python 선형탐색</category>
      <category>python 이진탐색</category>
      <category>파이썬 리스트 검색</category>
      <category>파이썬 선형탐색</category>
      <category>파이썬 알고리즘</category>
      <category>파이썬 이진탐색</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/44</guid>
      <comments>https://minimilab.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 16 Sep 2019 22:47:29 +0900</pubDate>
    </item>
    <item>
      <title>Mongodb 몽고디비 데이터 조회(find), collection 생성 삽입 query 명령어</title>
      <link>https://minimilab.tistory.com/43</link>
      <description>&lt;h1&gt;Mongodb 데이터 조회(find), collection 생성, document 삽입 query 명령어&lt;/h1&gt;
&lt;p&gt;Mongodb 사용법에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;Mongodb 사용 시 빈번하게 사용하는 Collection create, Document insert,&lt;/p&gt;
&lt;p&gt;다양하게 활용가능한 find(조회) query(명령어) 에 대해서 살펴봅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;9923593359840EC50A (1).png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSESBx/btqxN5DmvI2/GW0kGqz3s6XXvgixzJ25q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSESBx/btqxN5DmvI2/GW0kGqz3s6XXvgixzJ25q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSESBx/btqxN5DmvI2/GW0kGqz3s6XXvgixzJ25q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSESBx%2FbtqxN5DmvI2%2FGW0kGqz3s6XXvgixzJ25q0%2Fimg.png&quot; data-filename=&quot;9923593359840EC50A (1).png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;h3&gt;&lt;b&gt;Mongodb Collection 생성 및 Document 삽입&lt;/b&gt;&lt;/h3&gt;
&lt;/blockquote&gt;
&lt;h2&gt;wow라는 이름의 collection 생성&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;db.createCollection(&quot;wow&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;1개 document insert&lt;/h2&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;db.wow.insertOne({ &quot;korean&quot; : &quot;사이즈&quot;, &quot;english&quot;:&quot;size&quot; } )&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;여러개 document insert&lt;/h2&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;db.wow.insertMany(
[ 
{ &quot;korean&quot; : &quot;사이즈&quot;, &quot;english&quot; : &quot;size&quot;},
{ &quot;korean&quot; : &quot;코튼&quot;, &quot;english&quot; : &quot;cotton&quot;},
{ &quot;korean&quot; : &quot;색상&quot;, &quot;english&quot; : &quot;color&quot;}
])&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;h3&gt;&lt;b&gt;mongodb find 조회&lt;/b&gt;&lt;/h3&gt;
&lt;/blockquote&gt;
&lt;h2&gt;collection 전체 조회&lt;/h2&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;db.wow.find({})&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;ObjectId로 조회&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;db.getCollection('wow').find({_id:ObjectId('5bee16ac39ab840015adbec3')})&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;특정 값 조회&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;db.getCollection('wow').find({&quot;korean&quot;:&quot;사이즈&quot;})&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;조건 여러개로 조회&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;db.getCollection('wow').find({&quot;korean&quot;:&quot;사이즈&quot;,&quot;english&quot; : &quot;size&quot; })&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;특정 조회 값의 특정 필드만 조회&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;english 필드만 노출&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;_id는 0으로 설정하지 않으면 항상 노출됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1567086571061&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;db.getCollection('wow').find({&quot;korean&quot;:&quot;사이즈&quot;},{_id:0, &quot;english&quot;:1})&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;OR 쿼리&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;korean 이 사이즈이거나, english가 color인 것 조회&lt;/p&gt;
&lt;p&gt;db.getCollection('wow').find({&lt;/p&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;  $or: [
  {&quot;korean&quot;: &quot;사이즈&quot;}, 
  {&quot;english&quot;:&quot;color&quot;}
  ]
})&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;AND 쿼리&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;korean 이 사이즈이고, english가 size인 것 조회&lt;/p&gt;
&lt;p&gt;db.getCollection('wow').find({&lt;/p&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;  $and : [
  {&quot;korean&quot;:&quot;사이즈&quot;},
  {&quot;english&quot;: &quot;size&quot;}
  ]
})&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;기간 조회&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$gte : 이상&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$lte : 이하&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$gt : 초과&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$lt : 미만&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;created_at key는 추가된 상태어야 함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1567086581591&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;db.getCollection('wow').find({created_at:{$gte:ISODate(&quot;2019-08-27T14:00:35.386Z&quot;),$lte:ISODate(&quot;2019-08-29T14:00:35.386Z&quot;) }})&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;정규식 활용 조회&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;english 가 s로 시작하지 않는 것 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;db.products.find({english: { $not: /^s*/ }})&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;code 가 특정글자(code_)로 시작하는 대상 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1580436205281&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;db.getCollection('products').find({&quot;code&quot;:{$regex : /code_\w+/}})
db.getCollection('products').find({&quot;code&quot;:{$regex : &quot;merge_&quot;}}) 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;collection 내림차순 조회&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;db.getCollection('wow').find({}).sort({_id:-1})&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Index 조회&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;db.getCollection('wow').getIndexes()&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;key가 존재하는 것 조회&lt;/h2&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;db.getCollection('wow').find({&quot;korean&quot;:{$exists:true}})&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;key 가 존재하는 결과 갯수 조회&amp;nbsp;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;mongodb find 개수를 count()로 find 로 조회한 결과의 갯수를 확인 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;db.getCollection('wow').find({&quot;korean&quot;:{$exists:true}}).count()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>MongoDB</category>
      <category>mongodb document</category>
      <category>mongodb find or</category>
      <category>mongodb find 개수</category>
      <category>mongodb query 명령어</category>
      <category>mongodb 데이터 조회</category>
      <category>mongodb 명령어</category>
      <category>mongodb 사용법</category>
      <category>mongodb 조회</category>
      <category>몽고디비 명령어</category>
      <category>몽고디비 쿼리</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/43</guid>
      <comments>https://minimilab.tistory.com/43#entry43comment</comments>
      <pubDate>Thu, 29 Aug 2019 23:00:10 +0900</pubDate>
    </item>
    <item>
      <title>대역폭(Bandwidth) 제한 방법 ethtool  (리눅스 우분투)</title>
      <link>https://minimilab.tistory.com/41</link>
      <description>&lt;h1&gt;&lt;b&gt;대역폭(Bandwidth) &lt;b&gt;제한 방법&amp;nbsp;&lt;/b&gt;ethtool (리눅스&amp;nbsp;우분투)&lt;/b&gt;&lt;/h1&gt;
&lt;p&gt;서버에서 이미지를 가져갈 때 속도를 느리게 조절하기 위해서 대역폭 제한방법을 알아보았다.&lt;br /&gt;네트워크 과부하를 막고, IDC에서 추가로 과금되는 경우를 막기 위해서 제한해주었다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;ethtool 명령어를 사용하여 아래와 같이 간단하게 속도를 조절할 수 있다.&lt;br /&gt;하지만 10/100/1000/10000 Mb/s 단위로만 설정이 가능하여,&lt;br /&gt;10단위가 아닌 다른 숫자로 시작하는 단위로 변경을 원할 시에는 tc를 설치해야 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;&lt;b&gt;대역폭(Bandwidth)이란?&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;한번에 보낼 수 있는 최대 데이터량으로 &lt;br /&gt;네트워크에서 전송되는 데이터 범위로 허용할 수 있는 동시접속자 수와 같은 의미이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;ifconfig로 네트워크 장치명 확인&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;ifconfig 명령어로 네트워크 장치명 enp4s0 임을 확인&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;$ ifconfig
docker0   Link encap:Ethernet  HWaddr ***.**.**.**
          inet addr:***.**.**.**  Bcast:***.**.**.**  Mask***.**.**.**
          inet6 addr: ***.**.**.**
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

enp4s0    Link encap:Ethernet  HWaddr ***.**.**.**
          inet addr:***.**.**.**  Bcast:***.**.**.**  Mask:***.**.**.**
          inet6 addr: ***.**.**.**  Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:***.**.**.**
          TX packets:***.**.**.**
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;b&gt;ethtool [네트워크 장치명] 입력&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span&gt;[네트워크 장치명] 에 1번에서 확인한 장치명을 넣어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;현재 속도가 Speed: 1000Mb/s 임을 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ ethtool enp4s0
Settings for enp4s0:
    Supported ports: [ TP ]
    Supported link modes:   10baseT/Half 10baseT/Full 
                            100baseT/Half 100baseT/Full 
                            1000baseT/Full 
    Supported pause frame use: Symmetric
    Supports auto-negotiation: Yes
    Advertised link modes:  10baseT/Half 10baseT/Full 
                            100baseT/Half 100baseT/Full 
                            1000baseT/Full 
    Advertised pause frame use: Symmetric
    Advertised auto-negotiation: Yes
    Speed: 1000Mb/s
    Duplex: Full
    Port: Twisted Pair
    PHYAD: 1
    Transceiver: internal
    Auto-negotiation: on
    MDI-X: off (auto)
Cannot get wake-on-lan settings: Operation not permitted
    Current message level: 0x00000007 (7)
                   drv probe link
    Link detected: yes&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;b&gt;변경하고 싶은 속도로 변경&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;아래와 같이 스피드와 duplex를 같이 셋팅해주어야 한다.&lt;/p&gt;
&lt;p&gt;speed뒤에&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;10/100/1000/10000&lt;span&gt;&amp;nbsp; 단위로 숫자를 입력해준다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;1000 -&amp;gt; 100 Mbs 로 변경&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;$ sudo ethtool -s enp4s0 speed 100 duplex full autoneg off&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;b&gt;변경 확인&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;pre id=&quot;code_1566915648412&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ethtool enp4s0
Settings for enp4s0:
 Supported ports: [ TP ]
 Supported link modes:   10baseT/Half 10baseT/Full 
                         100baseT/Half 100baseT/Full 
                         1000baseT/Full 
 Supported pause frame use: Symmetric
 Supports auto-negotiation: Yes
 Advertised link modes:  Not reported
 Advertised pause frame use: Symmetric
 Advertised auto-negotiation: No
 Speed: 100Mb/s
 Duplex: Full
 Port: Twisted Pair
 PHYAD: 1
 Transceiver: internal
 Auto-negotiation: off
 MDI-X: off (auto)
Cannot get wake-on-lan settings: Operation not permitted
 Current message level: 0x00000007 (7)
                drv probe link
 Link detected: yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2019-08-27 23;35;24.PNG&quot; width=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rwbz1/btqxOH1wt0n/MIYGQEcpKimWAJoL3Pf70k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rwbz1/btqxOH1wt0n/MIYGQEcpKimWAJoL3Pf70k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rwbz1/btqxOH1wt0n/MIYGQEcpKimWAJoL3Pf70k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frwbz1%2FbtqxOH1wt0n%2FMIYGQEcpKimWAJoL3Pf70k%2Fimg.png&quot; data-filename=&quot;2019-08-27 23;35;24.PNG&quot; width=&quot;550&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Linux</category>
      <category>Bandwidth란</category>
      <category>ethtool 사용법</category>
      <category>ethtool 속도 변경</category>
      <category>network bandwidth 측정</category>
      <category>네트워크 대역폭</category>
      <category>대역폭 제어</category>
      <category>대역폭 제한</category>
      <category>대역폭이란</category>
      <category>리눅스 네트워크 속도 설정</category>
      <category>우분투 인터넷 속도 제한하기</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/41</guid>
      <comments>https://minimilab.tistory.com/41#entry41comment</comments>
      <pubDate>Tue, 27 Aug 2019 23:37:40 +0900</pubDate>
    </item>
    <item>
      <title>구글 키워드 검색량 조회 및 검색 방법</title>
      <link>https://minimilab.tistory.com/40</link>
      <description>&lt;h1&gt;구글&amp;nbsp;키워드&amp;nbsp;검색량&amp;nbsp;조회&amp;nbsp;및&amp;nbsp;검색&amp;nbsp;방법&lt;/h1&gt;
&lt;p&gt;블로그에 글을 작성하면서 키워드가 선정이 중요하다는 것을 알게 되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;내가 사용하는 키워드와 사람들이 검색 시에 사용하는 키워드가 일치해야 검색량이 늘어납니다.&lt;/p&gt;
&lt;p&gt;내가 아무리 글을 열심히 작성해도, 사람들이 해당 키워드로 검색을 하지 않으면 그 글은 보여지지 않게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;무료 키워드 검색 방법 및 분석과 관련된 툴 3가지를 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2019-08-11 21;31;59.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcBxAH/btqxmMqoo27/kDcGKC4WrpPFcuIMkvIIX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcBxAH/btqxmMqoo27/kDcGKC4WrpPFcuIMkvIIX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcBxAH/btqxmMqoo27/kDcGKC4WrpPFcuIMkvIIX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcBxAH%2FbtqxmMqoo27%2FkDcGKC4WrpPFcuIMkvIIX1%2Fimg.png&quot; data-filename=&quot;2019-08-11 21;31;59.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;1. 다양한 키워드 만드는 방법, 키워드 검색 방법&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;keywordshitter 라는 사이트를 이용하면 간단하게 다양한 키워드들을 &lt;br /&gt;무료로 생성해낼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1-1.&amp;nbsp;&lt;/span&gt;구글 keywordshitter 사이트 방문&amp;nbsp;&lt;a href=&quot;https://keywordshitter.com/&quot;&gt;https://keywordshitter.com/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1-2. 키워드를 생성하고 싶은 메인 키워드를 입력&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;3-1.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6uOtx/btqxqKYXbKL/nGwmXeDDLE6jHKV4kWekl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6uOtx/btqxqKYXbKL/nGwmXeDDLE6jHKV4kWekl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6uOtx/btqxqKYXbKL/nGwmXeDDLE6jHKV4kWekl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6uOtx%2FbtqxqKYXbKL%2FnGwmXeDDLE6jHKV4kWekl0%2Fimg.png&quot; data-filename=&quot;3-1.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1-3. 생성된 키워드 확인&amp;nbsp;&lt;br /&gt;&lt;/b&gt;구글 키워드를 입력하여, 구글 키워드와 관련된 키워드들이 38개가 생성된 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;4.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bza5c1/btqxqW5VxvN/1eYeeunmmzsFS0M8YJgHj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bza5c1/btqxqW5VxvN/1eYeeunmmzsFS0M8YJgHj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bza5c1/btqxqW5VxvN/1eYeeunmmzsFS0M8YJgHj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbza5c1%2FbtqxqW5VxvN%2F1eYeeunmmzsFS0M8YJgHj1%2Fimg.png&quot; data-filename=&quot;4.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;2. 무료 키워드 및 키워드 검색량&amp;nbsp;조회 방법&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;b&gt;2-1.&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;upbersuggest 사이트 방문&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://neilpatel.com/ubersuggest/&quot;&gt;https://neilpatel.com/ubersuggest/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2-2. 언어 및 국가를 한국으로 변경하고 원하는 키워드를 입력 후 SEARCH 버튼을 클릭합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z5Mz5/btqxqWx5hNb/KW3cFh27qwPNNRxSt2o0KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z5Mz5/btqxqWx5hNb/KW3cFh27qwPNNRxSt2o0KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z5Mz5/btqxqWx5hNb/KW3cFh27qwPNNRxSt2o0KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz5Mz5%2FbtqxqWx5hNb%2FKW3cFh27qwPNNRxSt2o0KK%2Fimg.png&quot; data-filename=&quot;1.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2-3. 검색한 키워드와 관련된 구글 키워드 검색량과 CPC단가 경쟁정도 등을 확인할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;3.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kcz7f/btqxmv3sXVT/PL4ObfUaPCaTi6MZg0LPLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kcz7f/btqxmv3sXVT/PL4ObfUaPCaTi6MZg0LPLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kcz7f/btqxmv3sXVT/PL4ObfUaPCaTi6MZg0LPLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKcz7f%2Fbtqxmv3sXVT%2FPL4ObfUaPCaTi6MZg0LPLK%2Fimg.png&quot; data-filename=&quot;3.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block; text-align: center;&quot; data-ad-layout=&quot;in-article&quot; data-ad-format=&quot;fluid&quot; data-ad-client=&quot;ca-pub-5170996487649025&quot; data-ad-slot=&quot;1473138310&quot;&gt;&lt;/ins&gt;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;3. 구글 애드워즈 키워드 플래너 사용 방법&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;b&gt;3-1. 구글 애드워즈 사이트 방문 &lt;a href=&quot;https://ads.google.com/&quot;&gt;https://ads.google.com/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;구글애즈 계정이 없는 경우 무료이므로 만들어 주시면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3-2. 새 키워드 찾기 클릭&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;5.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AQNzW/btqxpzQTTlm/xq7zEHwq1mjGnNfpKWiJA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AQNzW/btqxpzQTTlm/xq7zEHwq1mjGnNfpKWiJA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AQNzW/btqxpzQTTlm/xq7zEHwq1mjGnNfpKWiJA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAQNzW%2FbtqxpzQTTlm%2Fxq7zEHwq1mjGnNfpKWiJA0%2Fimg.png&quot; data-filename=&quot;5.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3-3. 키워드 입력 후 실적 거두기 클릭&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;7.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXcDAV/btqxoPNq5tb/ZfPMTU3dkBeFW0EW3yQJ50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXcDAV/btqxoPNq5tb/ZfPMTU3dkBeFW0EW3yQJ50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXcDAV/btqxoPNq5tb/ZfPMTU3dkBeFW0EW3yQJ50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXcDAV%2FbtqxoPNq5tb%2FZfPMTU3dkBeFW0EW3yQJ50%2Fimg.png&quot; data-filename=&quot;7.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3-4. 생성된 구글 키워드 및 월간 평균 검색량, 경쟁정도, 광고 입찰가 등을 확인 가능&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;필터 추가 버튼을 클릭하여 키워드 텍스트가 포함된 키워드만도 검색 가능합니다.&lt;/p&gt;
&lt;p&gt;이 외에도 여러 필터들을 추가할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;9.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdkhB1/btqxmLZlEkB/gv3iScztzCRk5BXvQfOmFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdkhB1/btqxmLZlEkB/gv3iScztzCRk5BXvQfOmFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdkhB1/btqxmLZlEkB/gv3iScztzCRk5BXvQfOmFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdkhB1%2FbtqxmLZlEkB%2Fgv3iScztzCRk5BXvQfOmFk%2Fimg.png&quot; data-filename=&quot;9.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXOieJ/btqxqJMvI8c/5doN9Q6UwWrCDhTtdUKck0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXOieJ/btqxqJMvI8c/5doN9Q6UwWrCDhTtdUKck0/img.png&quot; data-alt=&quot;필터 추가 클릭 시 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXOieJ/btqxqJMvI8c/5doN9Q6UwWrCDhTtdUKck0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXOieJ%2FbtqxqJMvI8c%2F5doN9Q6UwWrCDhTtdUKck0%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;필터 추가 클릭 시 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>블로그 운영 팁</category>
      <category>구글 애드워즈 플래너 사용법</category>
      <category>구글 키워드 검색</category>
      <category>구글 키워드 검색 방법</category>
      <category>구글 키워드 검색량 조회</category>
      <category>무료 키워드 검색</category>
      <category>애드워즈 키워드</category>
      <category>애드워즈 키워드 플래너</category>
      <category>키워드 마케팅</category>
      <category>키워드 분석 툴</category>
      <category>키워드 순위</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/40</guid>
      <comments>https://minimilab.tistory.com/40#entry40comment</comments>
      <pubDate>Sun, 11 Aug 2019 21:35:05 +0900</pubDate>
    </item>
    <item>
      <title>건대 사격장 추천 (건대 놀거리)</title>
      <link>https://minimilab.tistory.com/39</link>
      <description>&lt;h1 style=&quot;text-align: center;&quot;&gt;건대&amp;nbsp;사격장&amp;nbsp;추천&amp;nbsp;(건대 놀거리)&lt;/h1&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;건대에 크라임씬을 하려고 갔다가, 시간이 남아서 사격 연습장에 들어갔다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;상호명은 야구 사격 연습장 !&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;위치는 펀시티 오락실 바로 앞에 있다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;사격도 할 수 있고, 야구랑, 농구 기계도 있다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;모든 게임이 특정 점수를 넘으면 쿠폰을 주는데, 해당 쿠폰으로 선물과 교환할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;쿠폰이 많을 수록 좀 더 나은 선물과 교환 가능하다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qoilX/btqxpeeC5bx/GUzqMRyfgDx2ytflkt2on0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qoilX/btqxpeeC5bx/GUzqMRyfgDx2ytflkt2on0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qoilX/btqxpeeC5bx/GUzqMRyfgDx2ytflkt2on0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqoilX%2FbtqxpeeC5bx%2FGUzqMRyfgDx2ytflkt2on0%2Fimg.png&quot; data-filename=&quot;blob&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;​&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;728&quot; height=&quot;970&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9991E1475D4DA87B1C?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9991E1475D4DA87B1C?original&quot; data-alt=&quot;시작전 모습 2,500원에 32발 쏠 수 있게 해준다.&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9991E1475D4DA87B1C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9991E1475D4DA87B1C&quot; width=&quot;728&quot; height=&quot;970&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;시작전 모습 2,500원에 32발 쏠 수 있게 해준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;​&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AKqS7/btqxqKqA2Wl/ODxc1whcTVVKrstgsRWp41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AKqS7/btqxqKqA2Wl/ODxc1whcTVVKrstgsRWp41/img.png&quot; data-alt=&quot;여자는 1450 , 남자는 1750점부터 쿠폰 1장으로 교환해주는데, 2010점이 넘었다.&amp;amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AKqS7/btqxqKqA2Wl/ODxc1whcTVVKrstgsRWp41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAKqS7%2FbtqxqKqA2Wl%2FODxc1whcTVVKrstgsRWp41%2Fimg.png&quot; data-filename=&quot;blob&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;여자는 1450 , 남자는 1750점부터 쿠폰 1장으로 교환해주는데, 2010점이 넘었다.&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;script async src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot;
     style=&quot;display:block; text-align:center;&quot;
     data-ad-layout=&quot;in-article&quot;
     data-ad-format=&quot;fluid&quot;
     data-ad-client=&quot;ca-pub-5170996487649025&quot;
     data-ad-slot=&quot;1473138310&quot;&gt;&lt;/ins&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;​쏠 때 픽픽쓰러지는 과녁판의 느낌이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;또 하고 싶다 *.*&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;728&quot; height=&quot;970&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/996FB23B5D4DA87E32?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/996FB23B5D4DA87E32?original&quot; data-alt=&quot;일정한 점수를 넘기면 쿠폰을 1장 받을 수 있고, 쿠폰으로 상품과 교환할 수 있다.&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996FB23B5D4DA87E32&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996FB23B5D4DA87E32&quot; width=&quot;728&quot; height=&quot;970&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;일정한 점수를 넘기면 쿠폰을 1장 받을 수 있고, 쿠폰으로 상품과 교환할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;사격으로 쿠폰을 1개 받고, 농구로 쿠폰을 1개 받았는데 너~무 고를게 없어서 계속 망설였다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;10분은 서있었던 것 같다... 그러고 있으니&amp;nbsp;다른 게임하고 계시던 분들이 &lt;br /&gt;조금만 기다리라고 하더니 쿠폰 2개를 따서 주고 가셨다.&amp;nbsp;&lt;br /&gt;너무나 착하신분들.. !!&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcRRxj/btqxnnpPH83/f3YNrgimuWfWPd7b3yMBgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcRRxj/btqxnnpPH83/f3YNrgimuWfWPd7b3yMBgk/img.png&quot; data-alt=&quot;쿠폰 4개로 교환한 주사위 인형 ! 파란 색감이 넘나 맘에든다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcRRxj/btqxnnpPH83/f3YNrgimuWfWPd7b3yMBgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcRRxj%2FbtqxnnpPH83%2Ff3YNrgimuWfWPd7b3yMBgk%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;쿠폰 4개로 교환한 주사위 인형 ! 파란 색감이 넘나 맘에든다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;건대 야구사격 연습장 위치&lt;/blockquote&gt;
&lt;p&gt;&lt;iframe mapdata=&quot;addr=%EC%84%9C%EC%9A%B8%20%EA%B4%91%EC%A7%84%EA%B5%AC%20%ED%99%94%EC%96%91%EB%8F%99%207-6%20&amp;amp;addtype=1&amp;amp;confirmid=24204544&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A515140%2C%22mapCenterY%22%3A1122693%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A515142%2C%22y%22%3A1122699%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%95%BC%EA%B5%AC%EC%82%AC%EA%B2%A9%EC%97%B0%EC%8A%B5%EC%9E%A5%22%2C%22confirmid%22%3A24204544%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=515140&amp;amp;mapY=1122693&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=1121571000&amp;amp;tel=&amp;amp;title=%EC%95%BC%EA%B5%AC%EC%82%AC%EA%B2%A9%EC%97%B0%EC%8A%B5%EC%9E%A5&quot; src=&quot;/proxy/plusmapViewer.php?id=maps_1565404290730&quot; id=&quot;maps_1565404290730&quot; width=&quot;540px&quot; height=&quot;350px&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; data-ke-type=&quot;map&quot; data-maps-data=&quot;addr=%EC%84%9C%EC%9A%B8%20%EA%B4%91%EC%A7%84%EA%B5%AC%20%ED%99%94%EC%96%91%EB%8F%99%207-6%20&amp;amp;addtype=1&amp;amp;confirmid=24204544&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A515140%2C%22mapCenterY%22%3A1122693%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A515142%2C%22y%22%3A1122699%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%95%BC%EA%B5%AC%EC%82%AC%EA%B2%A9%EC%97%B0%EC%8A%B5%EC%9E%A5%22%2C%22confirmid%22%3A24204544%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=515140&amp;amp;mapY=1122693&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=1121571000&amp;amp;tel=&amp;amp;title=%EC%95%BC%EA%B5%AC%EC%82%AC%EA%B2%A9%EC%97%B0%EC%8A%B5%EC%9E%A5&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>책.영화.정보</category>
      <category>건대 놀거리</category>
      <category>건대 놀곳</category>
      <category>건대 데이트</category>
      <category>건대 사격 연습장</category>
      <category>건대 사격장</category>
      <category>건대 야구</category>
      <category>건대 오락실</category>
      <category>건대 이색 데이트</category>
      <category>건대 이색데이트</category>
      <category>건대 펀시티</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/39</guid>
      <comments>https://minimilab.tistory.com/39#entry39comment</comments>
      <pubDate>Sat, 10 Aug 2019 12:00:14 +0900</pubDate>
    </item>
    <item>
      <title>건대 엑스크라임 크라임씬 백스테이지 살인사건 후기 (건대 놀거리)</title>
      <link>https://minimilab.tistory.com/38</link>
      <description>&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;h1&gt;건대 크라임 씬 엑스크라임 후기&lt;/h1&gt;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;크라임씬은 jtbc 에서 진행했던 예능 프로그램으로, 방탈출 카페에서 크라임씬과 동일한 형식으로 &lt;br /&gt;진행하는 새로운 테마이다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;4명 이상부터 할 수 있다. 4명이 되지 않는 경우 open room 으로 예약해 놓으면,&lt;br /&gt;같은 시간에 인원 수가 모자라는 다른 팀이 있을 경우 같이 할 수 있다. &lt;br /&gt;&lt;br /&gt;나는 이전에 2명에서 open room 으로 예약을 했었던 적이 있었다.&lt;br /&gt;당연히 그냥 가서 하면 되는 줄 알았는데 30분 전에 사람이 없어서 취소되었다고 연락와서 시간이 붕떳던적이 있었다.&lt;br /&gt;open room 으로 예약하신 분은 미리 확인하고 가시길 ^^ &lt;br /&gt;(예약은 엑스크라임 홈페이지에서 가능하다. 결제는 가서 하면된다.)&lt;br /&gt;&lt;br /&gt;오늘은 가려고 했던 건 아닌데 즉흥적으로 가게되었다.&lt;/p&gt;
&lt;p&gt;복장입는 시간과, 설명듣는 시간이 있어서 예약한 시간 20~30분 전에 도착해야 한다.&lt;br /&gt;엑스크라임에서 대기하는 중에 2분이 크라임씬하고 싶은데 인원이 없어 못한다는 얘기를 듣고, &lt;br /&gt;예전의 내가 생각나서 같이하자고 제안해서 총 6명에서 진행했다. &lt;br /&gt;4명에서 진행 시에는 각 25,000씩인데, &lt;span style=&quot;color: #ff7600;&quot;&gt;6명에서 진행하면 23,000원&lt;/span&gt;으로 할인되었다. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;우리가 진행한 테마는 &lt;span style=&quot;color: #ff7600;&quot;&gt;백스테이지 살인사건&lt;/span&gt;이다.&lt;br /&gt;건대 엑스크라임에는 3가지 크라임씬 테마가 있다.&lt;/p&gt;
&lt;p&gt;1. 백스테이지&lt;/p&gt;
&lt;p&gt;2. 그믐달&lt;/p&gt;
&lt;p&gt;3. 경성도박장&lt;br /&gt;​&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;728&quot; height=&quot;1463&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99DDC64A5D4DA87727?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99DDC64A5D4DA87727?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DDC64A5D4DA87727&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DDC64A5D4DA87727&quot; width=&quot;728&quot; height=&quot;1463&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p&gt;&lt;br /&gt;즉흥적으로 가다보니 백스테이지가 시간이 제일 빨라서 하게되었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;건대 엑스크라임 내부 모습&lt;br /&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;img (1).png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7cChS/btqxnmLgNXG/BsFY2wBm5lB5nO7DPaZAfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7cChS/btqxnmLgNXG/BsFY2wBm5lB5nO7DPaZAfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7cChS/btqxnmLgNXG/BsFY2wBm5lB5nO7DPaZAfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7cChS%2FbtqxnmLgNXG%2FBsFY2wBm5lB5nO7DPaZAfK%2Fimg.png&quot; data-filename=&quot;img (1).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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;728&quot; height=&quot;970&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99FD44485D4DA87807?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99FD44485D4DA87807?original&quot; data-alt=&quot;주의사항&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FD44485D4DA87807&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FD44485D4DA87807&quot; width=&quot;728&quot; height=&quot;970&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;주의사항&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;​&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;728&quot; height=&quot;970&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99B32F495D4DA8790B?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99B32F495D4DA8790B?original&quot; data-alt=&quot;있어보이게 생긴 철문&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B32F495D4DA8790B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B32F495D4DA8790B&quot; width=&quot;728&quot; height=&quot;970&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;있어보이게 생긴 철문&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;​&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;728&quot; height=&quot;970&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9947F83D5D4DA87A04?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9947F83D5D4DA87A04?original&quot; data-alt=&quot;짐을 보관할 수 있는 캐비넷&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9947F83D5D4DA87A04&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9947F83D5D4DA87A04&quot; width=&quot;728&quot; height=&quot;970&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;짐을 보관할 수 있는 캐비넷&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;건대 엑스크라임 크라임씬 진행방법&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&lt;br /&gt;1. 6명은 각자의 역할을 부여받는다. &lt;br /&gt;탐정, 조수, 용의자3, 범인 1 (4명일 경우 탐정,조수가 없다.)&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;2. 자신의 알리바이를 숙지 및 복장을 착용한다.&lt;br /&gt;룰 북을 주는데, 짧은 시간 안에 다 외우기가 어려우므로, 사건 현장에도 가지고 들어갈 수 있다.&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&lt;br /&gt;3. 각 용의자에 방에서 의심이 가는 단서들을 모은다.&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&lt;br /&gt;4. 단서들을 활용하여 추리하여 범인을 잡는다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block; text-align: center;&quot; data-ad-layout=&quot;in-article&quot; data-ad-format=&quot;fluid&quot; data-ad-client=&quot;ca-pub-5170996487649025&quot; data-ad-slot=&quot;1473138310&quot;&gt;&lt;/ins&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;백스테이지 살인사건 총평&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;백스테이지 살인사건은 패션쇼 무대를 하려고 했으나, 직전에 살해당한 연예인을 죽인 범인이 누구인지를 추리하는 테마이다. &lt;br /&gt;단서들이 직관적이어서 좋다. 하지만 각 용의자마다 동기나 의심받을 만한 정황들이 있다. &lt;br /&gt;범인이 너무 연기를 잘해서 맞추지 못한 부분도 있으나(같이 하자고 제안드렸던 분들이 엄청난 연기력을 발휘하셨다는..), 살짝 범인으로 가기까지의 개연성이 떨어지는 느낌이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;건대 엑스크라임 크라임씬 총평&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;자신의 알리바이에 대한 사항들이 많아서 숙지하기가 어렵다. &lt;br /&gt;룰북을 가지고 들어가서 보면서 할 수 있기 때문에 진행하는데 문제는 없지만, 외우고 할 수 있다면 더 자연스러운 연기로 재미가 배가 될 것 같다. &lt;br /&gt;1:1 코칭 시 개개인의 알리바이에 대해 외울 수 있도록 코치해주면 더 좋을 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;크라임씬은 기존에 방탈출과는 다른 추리력을 발휘하게 되는 점이 좋고, &lt;br /&gt;친구들의 어색한 연기를 관람할 수 있는 점도 재미있다.&lt;/p&gt;
&lt;p&gt;4~6명이 모인다면, 한번쯤 해보면 좋을 것 같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;건대 시간때우기 좋은 곳&amp;nbsp;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;크라임씬 하기 전에 시간이 남는다면 가까운 곳에 야구 사격 연습장이 있어서 즐기다가 가면&lt;/p&gt;
&lt;p&gt;시간이 딱 맞다.&lt;/p&gt;
&lt;figure id=&quot;og_1565406216403&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://minimilab.tistory.com/39&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-original-url=&quot;https://minimilab.tistory.com/39&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DPmkg/hyCnEdnKHX/hNzGaQKN6CHJR1g7dkzK3K/img.png?width=720&amp;amp;height=720&amp;amp;face=0_0_720_720,https://scrap.kakaocdn.net/dn/e1g98/hyCnvndqnU/kOnxEeg4anhVxW2XACra80/img.jpg?width=1344&amp;amp;height=1792&amp;amp;face=0_0_1344_1792,https://scrap.kakaocdn.net/dn/hLMKN/hyCnxyyPVl/0DmhmJXHHZSCaFkAepKrhK/img.jpg?width=1344&amp;amp;height=1792&amp;amp;face=0_0_1344_1792');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;건대 사격장 추천 (건대 놀거리)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;건대 사격장 추천 (건대 놀거리) 건대에 크라임씬을 하려고 갔다가, 시간이 남아서 사격 연습장에 들어갔다. 상호명은 야구 사격 연습장 ! 위치는 펀시티 오락실 바로 앞에 있다. 사격도 할 수 있고, 야구랑, 농구..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;minimilab.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;건대 엑스크라임 위치&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;iframe mapdata=&quot;addr=%EC%84%9C%EC%9A%B8%20%EA%B4%91%EC%A7%84%EA%B5%AC%20%ED%99%94%EC%96%91%EB%8F%99%209-47%20%EC%A7%80%ED%95%981%EC%B8%B5&amp;amp;addtype=1&amp;amp;confirmid=361428621&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A515240%2C%22mapCenterY%22%3A1123048%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A515241%2C%22y%22%3A1123051%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%97%91%EC%8A%A4%ED%81%AC%EB%9D%BC%EC%9E%84%20%EA%B1%B4%EB%8C%80%EC%A0%90%22%2C%22confirmid%22%3A361428621%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=515240&amp;amp;mapY=1123048&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=1121571000&amp;amp;tel=02-464-8788&amp;amp;title=%EC%97%91%EC%8A%A4%ED%81%AC%EB%9D%BC%EC%9E%84%20%EA%B1%B4%EB%8C%80%EC%A0%90&quot; src=&quot;/proxy/plusmapViewer.php?id=maps_1565406644632&quot; id=&quot;maps_1565406644632&quot; width=&quot;540px&quot; height=&quot;350px&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; data-ke-type=&quot;map&quot; data-maps-data=&quot;addr=%EC%84%9C%EC%9A%B8%20%EA%B4%91%EC%A7%84%EA%B5%AC%20%ED%99%94%EC%96%91%EB%8F%99%209-47%20%EC%A7%80%ED%95%981%EC%B8%B5&amp;amp;addtype=1&amp;amp;confirmid=361428621&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A515240%2C%22mapCenterY%22%3A1123048%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A515241%2C%22y%22%3A1123051%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%97%91%EC%8A%A4%ED%81%AC%EB%9D%BC%EC%9E%84%20%EA%B1%B4%EB%8C%80%EC%A0%90%22%2C%22confirmid%22%3A361428621%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=515240&amp;amp;mapY=1123048&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=1121571000&amp;amp;tel=02-464-8788&amp;amp;title=%EC%97%91%EC%8A%A4%ED%81%AC%EB%9D%BC%EC%9E%84%20%EA%B1%B4%EB%8C%80%EC%A0%90&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>책.영화.정보</category>
      <category>건대 놀거리</category>
      <category>건대 놀곳</category>
      <category>건대 방탈출</category>
      <category>건대 엑스크라임</category>
      <category>건대 크라임씬</category>
      <category>건대 크라임씬 백스테이지 살인사건</category>
      <category>건대 크라임씬 후기</category>
      <category>방탈출 크라임씬</category>
      <category>백스테이지 살인사건</category>
      <category>백스테이지 살인사건 후기</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/38</guid>
      <comments>https://minimilab.tistory.com/38#entry38comment</comments>
      <pubDate>Sat, 10 Aug 2019 02:08:14 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 구글 스프레드시트 api 연동 및 사용 방법</title>
      <link>https://minimilab.tistory.com/37</link>
      <description>&lt;h1&gt;python google spreadsheet 연동 방법&lt;/h1&gt;
&lt;blockquote style=&quot;font-size: 1.12em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;구글 스프레드시트란 ?&amp;nbsp;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;쉽게 말하면 액셀을 휴대폰, 아이패드, 컴퓨터 등 언제 어디에서나 인터넷만 연결되어 있으면&amp;nbsp;&lt;/p&gt;
&lt;p&gt;확인 및 수정할 수 있는 구글이 개발한 스프레드 시트입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;실시간으로 저장되고 접근 가능성이 용이하여 사용할 수 있는 확장성이 넓습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;구글 스프레드시트를 간단한 데이터베이스로도 사용할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;지금부터 설명드릴 python 과 구글 스프레드시트를 연동하는 방법을 통해&lt;/p&gt;
&lt;p&gt;파이선 코드로 스프레드시트와 접근하여 활용하면&amp;nbsp;활용도가 무궁무진할 것으로 생각됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.12em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;1. 아래 url 클릭 후 서비스 계정 만들기 클릭&amp;nbsp;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;URL :&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://console.developers.google.com/iam-admin/serviceaccounts/&quot;&gt;https://console.developers.google.com/iam-admin/serviceaccounts/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXWgHi/btqxjBCkdrO/CSt1aAubxHtxGicwNAERt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXWgHi/btqxjBCkdrO/CSt1aAubxHtxGicwNAERt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXWgHi/btqxjBCkdrO/CSt1aAubxHtxGicwNAERt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXWgHi%2FbtqxjBCkdrO%2FCSt1aAubxHtxGicwNAERt1%2Fimg.png&quot; data-filename=&quot;1.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.12em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;2. 작업 &amp;rarr; 키만들기 클릭 -&amp;gt; json 선택 후 만들기 클릭&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SeRs5/btqxmMhQ3qj/xp0Z0rj8G3wX9JbFzuEWkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SeRs5/btqxmMhQ3qj/xp0Z0rj8G3wX9JbFzuEWkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SeRs5/btqxmMhQ3qj/xp0Z0rj8G3wX9JbFzuEWkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSeRs5%2FbtqxmMhQ3qj%2Fxp0Z0rj8G3wX9JbFzuEWkK%2Fimg.png&quot; data-filename=&quot;2.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.12em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;3. 생성된 json key파일을 열어서&amp;nbsp;client_email 복사&amp;nbsp;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.12em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;span style=&quot;color: #777777;&quot;&gt;&lt;b&gt;4.&amp;nbsp;구글 spreadsheet 새로 만들기 : 구글 로그인 -&amp;gt; 드라이브 클릭 -&amp;gt; 새로 만들기 클릭 -&amp;gt; 구글 spreadsheet 클릭&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;5.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNO4zc/btqxlxMsuyO/VUsvUCiNnGROZ4KnHkUQWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNO4zc/btqxlxMsuyO/VUsvUCiNnGROZ4KnHkUQWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNO4zc/btqxlxMsuyO/VUsvUCiNnGROZ4KnHkUQWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNO4zc%2FbtqxlxMsuyO%2FVUsvUCiNnGROZ4KnHkUQWK%2Fimg.png&quot; data-filename=&quot;5.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.12em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;5. 새로 만든 구글 spreadsheet 에 3번에서 복사한 client_email 주소를 공유&amp;nbsp;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sodXA/btqxmK5pYQs/s4nMmvvHyMJ7WkTakkfzg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sodXA/btqxmK5pYQs/s4nMmvvHyMJ7WkTakkfzg0/img.png&quot; data-alt=&quot;공유버튼 클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sodXA/btqxmK5pYQs/s4nMmvvHyMJ7WkTakkfzg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsodXA%2FbtqxmK5pYQs%2Fs4nMmvvHyMJ7WkTakkfzg0%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;공유버튼 클릭&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd96YP/btqxlw06dDN/iRNwHz9f9waG0ESO0G9R50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd96YP/btqxlw06dDN/iRNwHz9f9waG0ESO0G9R50/img.png&quot; data-alt=&quot;복사한 client_email 주소를 붙여넣은 후 전송 클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd96YP/btqxlw06dDN/iRNwHz9f9waG0ESO0G9R50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd96YP%2Fbtqxlw06dDN%2FiRNwHz9f9waG0ESO0G9R50%2Fimg.png&quot; data-filename=&quot;blob&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;복사한 client_email 주소를 붙여넣은 후 전송 클릭&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.12em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;6. 구글 spreadsheet id 확인&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;spreadsheets/d/ 뒤에 있는 구글 스프레드시트 아이디를 복사&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.google.com&quot;&gt;https://docs.google.com&lt;/a&gt;/spreadsheets/d/{google spreadsheet id}/edit#gid=0&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;4.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYE3bc/btqxjhRBHui/uGcGnDRYBxlqjGJBzrKTe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYE3bc/btqxjhRBHui/uGcGnDRYBxlqjGJBzrKTe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYE3bc/btqxjhRBHui/uGcGnDRYBxlqjGJBzrKTe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYE3bc%2FbtqxjhRBHui%2FuGcGnDRYBxlqjGJBzrKTe1%2Fimg.png&quot; data-filename=&quot;4.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.12em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;7. python google-spread sheet 라이브러리 설치&amp;nbsp;&lt;/b&gt;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1565266705194&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install --upgrade google-api-python-client oauth2client&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.12em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;8. 아래의 코드에서 SPREADSHEET_ID, credential 변경 후 코드실행&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;(1). SPREADSHEET_ID : 6번에서 복사해둔&amp;nbsp;구글 spreadsheet id 입력&lt;/p&gt;
&lt;p&gt;(2). credentials&amp;nbsp;=&amp;nbsp;ServiceAccountCredentials.from_json_keyfile_name( 뒷부분에 2번에서 저장해둔 json key 파일의 위치를 입력&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565266915462&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# -*- coding: utf-8 -*-

from httplib2 import Http
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
# Google API 요청 시 필요한 권한 유형
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
# 구글 시트 ID
SPREADSHEET_ID = 'test'
def main():
    values = [
    ['이건', '첫 번째', '행입니다.'],
    ['첫 번째'],
    ['열입니다.'],
    ]
    body = {
        'values': values
    }

    # json 파일로 서비스 계정 credential 정의
    credentials = ServiceAccountCredentials.from_json_keyfile_name('/home/miminilab/service_key.json', SCOPES)
    http_auth = credentials.authorize(Http())
    service = build('sheets', 'v4', http=http_auth)

    # 업데이트 요청 및 실행
    request = service.spreadsheets().values().update(spreadsheetId=SPREADSHEET_ID,
                                                    range='시트1!A1:D3', # 2
                                                    valueInputOption='RAW',
                                                    body=body)
    request.execute()

if __name__ == '__main__':
    main()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python</category>
      <category>python googlespreadsheet</category>
      <category>python 구글 api</category>
      <category>구글 스프레드시트 api</category>
      <category>구글 스프레드시트 api 예제</category>
      <category>구글스프레드시트 파이썬</category>
      <category>파이썬 구글 api</category>
      <category>파이썬 구글스프레드시트</category>
      <category>파이썬 구글스프레드시트 쓰기</category>
      <category>파이썬 구글스프레드시트 연동방법</category>
      <category>파이썬 구글스프레드시트 코드</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/37</guid>
      <comments>https://minimilab.tistory.com/37#entry37comment</comments>
      <pubDate>Thu, 8 Aug 2019 21:42:29 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 find 명령어 사용법 정리 (디렉토리 출력, 이름 검색, exec, 특정 크기 이상)</title>
      <link>https://minimilab.tistory.com/36</link>
      <description>&lt;h1&gt;linux 리눅스 find 명령어 활용하기&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;지정한 파일 타입만 출력하기&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;. /: 현재 디렉토리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;./폴더명 : 현재 디렉토리 아래에 있는 폴더 내부에서 검색&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-type 옵션 : 지정한 파일 타입 출력&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-maxdepth n 옵션 : 서브디렉토리의 depth 범위를 지정 /&amp;nbsp;&amp;nbsp;현재 디렉터리만 검색하는 경우 -maxdepth 0&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&lt;b&gt;폴더(디렉터리) 타입만 출력&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;find ./ -type d&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&lt;b&gt;파일 타입만 출력&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;find ./ -type f&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&lt;b&gt;빈 파일 찾기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;find ./ -type f -empty&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;이름이 일치하는 타입 출력하기&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;-name 옵션 : 특정 이름과 일치하는 파일을 출력 , 정규식 사용가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-o 옵션 : or 의 의미로 앞뒤로 조건을 입력&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1565183091792&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ find . -type d -name &quot;ocale&quot; -o -name &quot;pr&quot;

./.idea/practice.iml
./locale&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;find 결과 값을 명령어로 이어서 실행&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;{} : find로 찾은 결과 값이 위치하게 됨&lt;/li&gt;
&lt;li&gt;-exec 옵션 : 찾은 파일을 이용해서 다른 명령어를 실행할 때&lt;/li&gt;
&lt;li&gt;cp -R : 폴더 내부 내용까지 복사하기 (원본폴더-&amp;gt;복사폴더)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;$ find /home/test/*  -type d -exec cp -R {} /home/test2/ \;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;특정 크기 이상인 파일 찾기&lt;/b&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;$ find ~ -size +2000k -exec ls -l {} \;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;리눅스 find.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSozJj/btqxjgRR97x/5BGyZIFRnW1MnfznFNQdQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSozJj/btqxjgRR97x/5BGyZIFRnW1MnfznFNQdQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSozJj/btqxjgRR97x/5BGyZIFRnW1MnfznFNQdQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSozJj%2FbtqxjgRR97x%2F5BGyZIFRnW1MnfznFNQdQ0%2Fimg.png&quot; data-filename=&quot;리눅스 find.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Linux</category>
      <category>find exec</category>
      <category>linux find</category>
      <category>리눅스 find</category>
      <category>리눅스 find cp</category>
      <category>리눅스 find exec</category>
      <category>리눅스 find 예제</category>
      <category>리눅스 find 현재 디렉토리</category>
      <category>리눅스 특정크기 이상</category>
      <category>리눅스 파일타입만출력</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/36</guid>
      <comments>https://minimilab.tistory.com/36#entry36comment</comments>
      <pubDate>Wed, 7 Aug 2019 22:24:37 +0900</pubDate>
    </item>
    <item>
      <title>윈도우 컬러피커 color picker 색상 추출 하는 방법</title>
      <link>https://minimilab.tistory.com/34</link>
      <description>&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;h1&gt;&lt;b&gt;윈도우&amp;nbsp;컬러피커&amp;nbsp;color&amp;nbsp;picker&amp;nbsp;색상&amp;nbsp;추출&lt;/b&gt;&lt;/h1&gt;
&lt;p&gt;모니터에 있는 색상이 어떤 색상인지 컬러를 추출하고 싶은 경우가 있습니다. &lt;br /&gt;아주 간단하게 윈도우용 무료 컬러피커 프로그램(eclipsepalette)을 설치하면 &lt;br /&gt;내 모니터상에 있는 컬러를 선택하여 rgb 색상 값을 확인할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;1. 홈페이지 방문하여 왼쪽에 Download setup file 클릭&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;윈도우 컬러피커 다운 주소&amp;nbsp; :&amp;nbsp;&lt;a href=&quot;http://www.greeneclipse.com/eclipsepalette.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://www.greeneclipse.com/eclipsepalette.html&lt;/a&gt;&lt;br /&gt;​&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;728&quot; height=&quot;581&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99A4524C5D4AC65908?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99A4524C5D4AC65908?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A4524C5D4AC65908&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A4524C5D4AC65908&quot; width=&quot;728&quot; height=&quot;581&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;blockquote data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;2. 설치 후 실행하여 스포이드 모양 클릭하여 원하는 색의 색상 정보 확인​&lt;/b&gt;&lt;/blockquote&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;276&quot; height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9942A0395D4AC65920?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9942A0395D4AC65920?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9942A0395D4AC65920&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9942A0395D4AC65920&quot; width=&quot;276&quot; height=&quot;296&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;</description>
      <category>책.영화.정보</category>
      <category>RGB색상 추출</category>
      <category>무료 컬러피커</category>
      <category>색상 추출하는 방법</category>
      <category>색상코드 추출</category>
      <category>윈도우 색상 추출</category>
      <category>윈도우 색상추출</category>
      <category>윈도우 스포이드</category>
      <category>윈도우 컬러피커</category>
      <category>컬러피커</category>
      <category>컬러피커 추천</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/34</guid>
      <comments>https://minimilab.tistory.com/34#entry34comment</comments>
      <pubDate>Wed, 7 Aug 2019 21:38:49 +0900</pubDate>
    </item>
    <item>
      <title>에어팟2 사용법 (에어팟 연동, 기능설정, 아이패드와 전환)</title>
      <link>https://minimilab.tistory.com/33</link>
      <description>&lt;h2&gt;에어팟&amp;nbsp;사용법&amp;nbsp;(에어팟&amp;nbsp;연동,&amp;nbsp;기능설정,&amp;nbsp;아이패드와&amp;nbsp;전환)&lt;/h2&gt;
&lt;p&gt;에어팟 사용법에 대해 간단히 3가지 사항을 공유하려고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. 에어팟과 아이폰 연동방법&lt;/p&gt;
&lt;p&gt;2. 에어팟 기능 설정방법&lt;/p&gt;
&lt;p&gt;3. 아이폰과 아이패드와의 전환 방법&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;에어팟을 쓰기 전에 jbl 블루투스 이어폰도 사용했었는데, 아이폰은 에어팟이 짱입니다.&lt;/p&gt;
&lt;p&gt;에어팟을 귀에 꼽기만하면 바로 아이폰과 연동되는 점도 좋고,&amp;nbsp;아이패드와도 쉽게 전환하여 사용할 수 있기 때문에 편합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;또한 기존 아이폰 이어폰과 같은 모양이기 때문에 귀가 아프지 않고 편안하게 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;에어팟과 아이폰 연동하기&lt;/blockquote&gt;
&lt;p&gt;1. 에어팟을 에어팟 케이스에 담은채로 뚜껑 열기&lt;/p&gt;
&lt;p&gt;2. 아이폰에서 연결클릭하기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;KakaoTalk_20190806_225231269.jpg&quot; width=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK8nnS/btqxgy6ypiY/ZOIxLl49nDGgE1VU935p9K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK8nnS/btqxgy6ypiY/ZOIxLl49nDGgE1VU935p9K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK8nnS/btqxgy6ypiY/ZOIxLl49nDGgE1VU935p9K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK8nnS%2Fbtqxgy6ypiY%2FZOIxLl49nDGgE1VU935p9K%2Fimg.jpg&quot; data-filename=&quot;KakaoTalk_20190806_225231269.jpg&quot; width=&quot;300&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;3. 에어팟 케이스 뒤의 동그란 버튼 길게 누르기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;KakaoTalk_20190806_225231821.jpg&quot; width=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bau5lw/btqxgzxCw1G/upzxxdeKn71g0S5KME9UO1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bau5lw/btqxgzxCw1G/upzxxdeKn71g0S5KME9UO1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bau5lw/btqxgzxCw1G/upzxxdeKn71g0S5KME9UO1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbau5lw%2FbtqxgzxCw1G%2FupzxxdeKn71g0S5KME9UO1%2Fimg.jpg&quot; data-filename=&quot;KakaoTalk_20190806_225231821.jpg&quot; width=&quot;300&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;4. 에어팟을 착용하고 연결되었는지 확인하기&lt;/p&gt;
&lt;p&gt;5. 연결되지 않았을 경우 아이폰에서 설정 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;KakaoTalk_20190806_225232228.jpg&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSl434/btqxf3TfTa1/pu2K5SpuXhaHKZEXVWJTl1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSl434/btqxf3TfTa1/pu2K5SpuXhaHKZEXVWJTl1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSl434/btqxf3TfTa1/pu2K5SpuXhaHKZEXVWJTl1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSl434%2Fbtqxf3TfTa1%2Fpu2K5SpuXhaHKZEXVWJTl1%2Fimg.jpg&quot; data-filename=&quot;KakaoTalk_20190806_225232228.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;6. bluetooth 설정화면에서 에어팟 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2019-08-06 23;02;17.PNG&quot; width=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXhCIT/btqxj0NQXiE/SqNIxK3xACdTa5c6u655a0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXhCIT/btqxj0NQXiE/SqNIxK3xACdTa5c6u655a0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXhCIT/btqxj0NQXiE/SqNIxK3xACdTa5c6u655a0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXhCIT%2Fbtqxj0NQXiE%2FSqNIxK3xACdTa5c6u655a0%2Fimg.png&quot; data-filename=&quot;2019-08-06 23;02;17.PNG&quot; width=&quot;300&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;에어팟 기능 설정하기&amp;nbsp;&lt;/blockquote&gt;
&lt;p&gt;에어팟을 톡톡치면(이중탭) 어떤 기능을 할 것인지를 설정할 수 있습니다.&lt;/p&gt;
&lt;p&gt;우선적으로 에어팟은 한쪽이라도 귀에서 빼면 동영상이나 음악 등이 중지 됩니다.&lt;/p&gt;
&lt;p&gt;그리고 다시 끼면 자동으로 재생이 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기본적인 사항 외에 시리를 부를지, 재생/일시정지할지, 다음 트랙 혹은 이전트랙을 들을지를 선택할 수 있습니다.&lt;/p&gt;
&lt;p&gt;설정방법은 아래와 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. 설정 클릭&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSl434/btqxf3TfTa1/pu2K5SpuXhaHKZEXVWJTl1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSl434/btqxf3TfTa1/pu2K5SpuXhaHKZEXVWJTl1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSl434/btqxf3TfTa1/pu2K5SpuXhaHKZEXVWJTl1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSl434%2Fbtqxf3TfTa1%2Fpu2K5SpuXhaHKZEXVWJTl1%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. bluetooth 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgNQP9/btqxhyLPVbN/vKMlAtKFSaeOXewFhKORBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgNQP9/btqxhyLPVbN/vKMlAtKFSaeOXewFhKORBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgNQP9/btqxhyLPVbN/vKMlAtKFSaeOXewFhKORBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgNQP9%2FbtqxhyLPVbN%2FvKMlAtKFSaeOXewFhKORBK%2Fimg.png&quot; width=&quot;300&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;3. i 버튼클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; width=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CcbMq/btqxf36QLVL/DX9A2mL0SMnCLT1TzsJrDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CcbMq/btqxf36QLVL/DX9A2mL0SMnCLT1TzsJrDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CcbMq/btqxf36QLVL/DX9A2mL0SMnCLT1TzsJrDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCcbMq%2Fbtqxf36QLVL%2FDX9A2mL0SMnCLT1TzsJrDk%2Fimg.png&quot; data-filename=&quot;blob&quot; width=&quot;300&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;4. 오른쪽, 왼쪽 에어팟 선택&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clnERW/btqxfEGaLXy/9PVq7q2kcZvoKQExtbzwmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clnERW/btqxfEGaLXy/9PVq7q2kcZvoKQExtbzwmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clnERW/btqxfEGaLXy/9PVq7q2kcZvoKQExtbzwmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclnERW%2FbtqxfEGaLXy%2F9PVq7q2kcZvoKQExtbzwmk%2Fimg.png&quot; width=&quot;300&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;5. 원하는 기능 선택&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; width=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhN7Xo/btqxgyyLbe0/oh3r3HUyFv2gyrBboronCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhN7Xo/btqxgyyLbe0/oh3r3HUyFv2gyrBboronCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhN7Xo/btqxgyyLbe0/oh3r3HUyFv2gyrBboronCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhN7Xo%2FbtqxgyyLbe0%2Foh3r3HUyFv2gyrBboronCK%2Fimg.png&quot; data-filename=&quot;blob&quot; width=&quot;300&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;에어팟 아이폰 아이패드 전환 방법&lt;/blockquote&gt;
&lt;p&gt;아이폰을 사용하다가 아이패드를 사용할 때 에어팟으로 듣고 있는 경우 쉽게 전환할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. 아이폰 혹은 아이패드 오른쪽 끝에서 끌어내린 후 음악 오른쪽 위 파란색 버튼 길게클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;KakaoTalk_20190806_225238005.jpg&quot; width=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqdviK/btqxj0Aj7Iy/vzbLNC7eFH3iOs2xGWsKEk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqdviK/btqxj0Aj7Iy/vzbLNC7eFH3iOs2xGWsKEk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqdviK/btqxj0Aj7Iy/vzbLNC7eFH3iOs2xGWsKEk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqdviK%2Fbtqxj0Aj7Iy%2FvzbLNC7eFH3iOs2xGWsKEk%2Fimg.jpg&quot; data-filename=&quot;KakaoTalk_20190806_225238005.jpg&quot; width=&quot;300&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;2. airpods 선택 시, 기존에 다른 기기에서 현재 설정한 기기로 에어팟이 전환됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm5E8d/btqxf3Z4pPY/DHXn4ccT1qON5GeNhoeyXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm5E8d/btqxf3Z4pPY/DHXn4ccT1qON5GeNhoeyXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm5E8d/btqxf3Z4pPY/DHXn4ccT1qON5GeNhoeyXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm5E8d%2Fbtqxf3Z4pPY%2FDHXn4ccT1qON5GeNhoeyXk%2Fimg.png&quot; width=&quot;300&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>책.영화.정보</category>
      <category>에어팟 기능 설정</category>
      <category>에어팟 동시 사용</category>
      <category>에어팟 블루투스 연결</category>
      <category>에어팟 사용 후기</category>
      <category>에어팟 사용방법</category>
      <category>에어팟 사용법</category>
      <category>에어팟 세팅</category>
      <category>에어팟 아이패드</category>
      <category>에어팟 아이폰 아이패드 동시 사용</category>
      <category>에어팟 아이폰 아이패드 전환</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/33</guid>
      <comments>https://minimilab.tistory.com/33#entry33comment</comments>
      <pubDate>Tue, 6 Aug 2019 23:32:49 +0900</pubDate>
    </item>
    <item>
      <title>포노사피엔스 - 최재붕 책 리뷰</title>
      <link>https://minimilab.tistory.com/31</link>
      <description>&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;포노사피엔스&amp;nbsp;책은 인터넷 시대의 흐름의&amp;nbsp;맞춰&amp;nbsp;&lt;br /&gt;디지털&amp;nbsp;플랫폼에&amp;nbsp;대한&amp;nbsp;이해도를&amp;nbsp;쌓자는&amp;nbsp;내용의&amp;nbsp;책이다.&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;베이비붐세대와 x&amp;nbsp;세대&amp;nbsp;중&amp;nbsp;인터넷에&amp;nbsp;관심이&amp;nbsp;없었던&amp;nbsp;&lt;br /&gt;사람들에게만&amp;nbsp;추천할&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;것&amp;nbsp;같다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;★&lt;span style=&quot;color: #333333;&quot;&gt;☆&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;☆&lt;span style=&quot;color: #333333;&quot;&gt;☆&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;☆&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table class=&quot;tt-plugin-interpark&quot; style=&quot;background: #fff; border: 1px solid #e0e0e0; width: 408px;&quot; border=&quot;0&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;vertical-align: top; padding: 10px 0 10px 10px;&quot; width=&quot;70&quot;&gt;&lt;a href=&quot;http://book.interpark.com/blog/integration/product/itemDetail.rdo?prdNo=301768447&amp;amp;refererType=8303&amp;amp;bookblockname=bpmain_in&amp;amp;booklinkname=wg_search_FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&amp;amp;key=FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img style=&quot;border: 0 none;&quot; src=&quot;http://bimage.interpark.com/goods_image/8/4/4/7/301768447h.jpg&quot; width=&quot;66&quot; height=&quot;90&quot; /&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;vertical-align: top; padding: 10px 10px 10px 15px;&quot;&gt;
&lt;dl style=&quot;margin: 0; padding: 2px 0 0 0; list-style: none; font: 11px dotum, sans-serif; letter-spacing: -1px; color: #777;&quot;&gt;
&lt;dt style=&quot;padding: 0; margin: 0;&quot;&gt;&lt;a style=&quot;font-size: 12px; color: #444 !important; font-weight: bold; text-decoration: none !important;&quot; href=&quot;http://book.interpark.com/blog/integration/product/itemDetail.rdo?prdNo=301768447&amp;amp;refererType=8303&amp;amp;bookblockname=bpmain_in&amp;amp;booklinkname=wg_search_FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&amp;amp;key=FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;포노 사피엔스&lt;/a&gt;&lt;/dt&gt;
&lt;dd style=&quot;padding: 7px 0 0 0; margin: 0; color: #a0a0a0;&quot;&gt;국내도서&lt;/dd&gt;
&lt;dd style=&quot;padding: 17px 0 0 0; margin: 0;&quot;&gt;저자 : 최재붕&lt;/dd&gt;
&lt;dd style=&quot;padding: 4px 0 0 0; margin: 0;&quot;&gt;출판 : 쌤앤파커스 &lt;span style=&quot;letter-spacing: normal;&quot;&gt;2019.03.11&lt;/span&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;a style=&quot;float: right; width: 44px; height: 11px; background: url('//t1.daumcdn.net/tistory_admin/static/images/icon_ipark_detail.gif') no-repeat; overflow: hidden; display: block; text-indent: -1000em;&quot; href=&quot;http://book.interpark.com/blog/integration/product/itemDetail.rdo?prdNo=301768447&amp;amp;refererType=8303&amp;amp;bookblockname=bpmain_in&amp;amp;booklinkname=wg_search_FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&amp;amp;key=FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;상세보기&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;책의 핵심 주제&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;과거부터 시대 흐름에 맞지 않는 기업들은 도산했다. 지금 시대는 인터넷, SNS로 이루어진 시대이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;시대의 흐름에 맞게 인터넷과 SNS, 디지털 플랫폼, 빅데이터, 인공지능과 같은 분야에 대한 이해도를 쌓자.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;책에 대한 감상평&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;베이비붐 세대 (1955년 ~ 1963년 사이 출생), X 세대 (1960년대 중반 ~ 1870년대 후반 출생) 사람들이 보면&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;도움이 될 수도 있는 책이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;밀레니얼 세대(1980년대 초반 ~ 2000년대 초반 출생)가 보기에는 너무 당연하게 알고 있는 내용들을 장황하게 써놓은 느낌이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를들어 &lt;b&gt;우버, 카카오뱅크, 에어비엔비, 삼성 메모리, 애플, 아마존, 방탄소년단&lt;/b&gt; 등 현시대를 살아가고 있다면&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;당연하고 익숙하게 접해서 알고있는 기업들에 대한 정의나 성공요인과 같은 내용들이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데 그 성공요인에 대한 저자의 생각도 굉장히 비논리적이고 좁다는 생각이 든다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 기업의 성공요인이 거의 1가지씩 밖에 쓰여있지 않은데, 그 1가지 조차도 공감이 가지 않는다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;작가가 베이비붐 세대라서 그런지 베이비붐 세대에 타겟팅해서 쉽게 쓴 것 같기도 하다.&lt;/span&gt;&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;책을 통해 생각한 것&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;항상 트랜드를 읽고 현 상황에 대한 견해를 갖자.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;시대가 굉장히 급변한다는 것을 이 책을 통해서 알 수 있었다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;책에서 삼성 메모리에 대한 예시를 들었다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;삼성전자의 주력 생산품은 메모리 반도체로 18년도 3분기 이익의 77퍼센트를 반도체에서 냈으며 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;영업이익이 70퍼센트라고 했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데 1년이 된 지금 찾아보니 삼성전자 2분기 매출액은 전년 동기 대비 56% 감소했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;불과 2018년도 예시인데도 불구하고 1년 사이에도 상황이 변화해가고 있는 중이다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;시대의 흐름을 따라가지 못한 모토롤라가 망했듯이 어떤 기업이 어떻게 망할지 모른다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;항상 트랜드를 읽고 현 상황에 대한 견해를 갖을 수 있도록 노력해야겠다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;팬덤은 어떻게 생기는지 분석하자.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;자신만의 스타일을 만들고 팬을 만들기 위해 노력해야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단기적인 광고로 사람들의 유입을 잠시 모을 수는 있어도, 팬을 만들지 못하면 장기적으로 살아남을 수 없다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인기가 많은 것을 볼 때 왜 인기가 많을까? 를 생각하면서 분석하자.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;blockquote&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;공감하지 못했던 내용&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; width=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQf7Cp/btqxeINYrQl/XLxFkQCddYHOtaKd5odyek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQf7Cp/btqxeINYrQl/XLxFkQCddYHOtaKd5odyek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQf7Cp/btqxeINYrQl/XLxFkQCddYHOtaKd5odyek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQf7Cp%2FbtqxeINYrQl%2FXLxFkQCddYHOtaKd5odyek%2Fimg.png&quot; data-filename=&quot;blob&quot; width=&quot;250&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1. 택시와 우버는 다르지 않지만 게임 같은 즐거움을 선사해서 성공했다 ?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;디지털 맵을 게임판으로 두고, 고객들은 가고 싶은 위치를 표시한다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우버기사는 표시한 위치에 있는 버튼을 눌러서 게임으로 인지하며 가벼운 마음으로 손님을 만나러간다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'달랑 이 차이'가 소비자들 사이에 급속도로 확산되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff7154; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;gt; 나의 생각&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우리나라 지방에 가면 서울에서처럼 지나가는 택시들을 잡을 수 없다. 택시가 보이지 않는다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;택시를 타려면 택시업체에 전화를 해야한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하물며 미국은 어떨까? 미국은 우리나라보다 크다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;미국에서 대부분의 사람들이 차가 있는 이유는 차가 '발'이기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;미국 도시는 그나마 대중교통이 되어있지만, 그 도시에서 30분만 나가도 차가 없으면 움직일 수가 없다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그렇기 때문에 우버 이전의 택시들도 마찬가지로 전화를 하거나, 온라인 시스템으로 예약을 해서 사용했을 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이런 상황에서 우버는 번거로움을 없애주었다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;앱을 키면 택시가 보이고, 바로 그 택시를 부를 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한 택시기사가 아닌 일반인들도 차만 있으면 우버기사를 할 수 있도록 하여 기사의 수를 늘렸다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;택시는 어디에서나 필요하지만, 택시기사는 돈 되는 곳에서 운행을 하고 싶어할 것이기 때문에 기사가 사람이 없는 곳에는 잘 없을 것이다. 하지만 일반인들이 집주변, 회사주변에서도 차만 있으면 기사를 할 수 있기 때문에 &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;좀 더 다양한 곳에서 손님을 받을 수 있었을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;246x0w.jpg&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dc2lhC/btqxbCBfBFm/iidRPE5eXyLXgOh6KOenz1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dc2lhC/btqxbCBfBFm/iidRPE5eXyLXgOh6KOenz1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dc2lhC/btqxbCBfBFm/iidRPE5eXyLXgOh6KOenz1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdc2lhC%2FbtqxbCBfBFm%2FiidRPE5eXyLXgOh6KOenz1%2Fimg.jpg&quot; data-filename=&quot;246x0w.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2. 카카오뱅크가 만들어진지 불과 1년 사이에 680만명이 넘는 고객을 확보한 이유는 귀여워서다 ?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;K뱅크와는 다르게 '귀엽다'라는 미묘한 차이로 680만 고객이 열광했다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #ff7154;&quot;&gt;&lt;b&gt;&amp;gt; 나의 생각&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;카카오뱅크의 성공요인은 높은 이율, 비대면계좌 개설로 손쉽게 접근 가능, 카카오라는 브랜드 인식, &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;친숙한 캐릭터라고 생각한다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;카카오뱅크는 초반에 높은 예금과 이자가 저렴한 대출상품으로 대대적인 홍보와 마케팅을 했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;게다가 몇번의 클릭만으로 계좌 개설이 가능하니, 손해볼 것 없으니 쉽게 가입을 했다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한 국민의 대다수가 사용하고 있는 '카카오' 브랜드로 네이밍하여 높은 호감도로 시작할 수 있었다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 친숙한 캐릭터가 성공요인에 없다고 생각하지 않지만 가장 낮은 비율이라고 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; width=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XbAec/btqxeKL2IOw/aKOwGEmtwkqc82MoynrFgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XbAec/btqxeKL2IOw/aKOwGEmtwkqc82MoynrFgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XbAec/btqxeKL2IOw/aKOwGEmtwkqc82MoynrFgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXbAec%2FbtqxeKL2IOw%2FaKOwGEmtwkqc82MoynrFgK%2Fimg.png&quot; data-filename=&quot;blob&quot; width=&quot;500&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>책.영화.정보</category>
      <category>디지털 플랫폼</category>
      <category>우버 성공요인</category>
      <category>우버와 택시</category>
      <category>최재붕</category>
      <category>최재붕 교수</category>
      <category>카카오뱅크 성공요인</category>
      <category>포노사피엔스</category>
      <category>포노사피엔스 리뷰</category>
      <category>포노사피엔스 책 리뷰</category>
      <category>호모 포노 사피엔스</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/31</guid>
      <comments>https://minimilab.tistory.com/31#entry31comment</comments>
      <pubDate>Sat, 3 Aug 2019 16:22:16 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 Pillow 이미지 처리 (픽셀값 구하기, 누끼 이미지, 이미지 붙이기)</title>
      <link>https://minimilab.tistory.com/30</link>
      <description>&lt;h1&gt;파이썬&amp;nbsp;Pillow&amp;nbsp;이미지&amp;nbsp;처리&amp;nbsp;(픽셀&amp;nbsp;색상&amp;nbsp;구하기,&amp;nbsp;누끼&amp;nbsp;이미지&amp;nbsp;만들기,&amp;nbsp;로고&amp;nbsp;이미지&amp;nbsp;붙이기)&lt;/h1&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;파이썬 이미지 처리 라이브러리인 Pillow는 image와 관련된 다양한 처리를 할 수 있습니다.&lt;br /&gt;그 중에서 특정 픽셀의 색상 구하기, 누끼이미지 만들기, 이미지에 이미지를 붙이기(로고 붙이기)를 해보도록 하겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2&gt;python Pillow 설치&lt;/h2&gt;
&lt;pre id=&quot;code_1564403731532&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install pillow&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2&gt;특정 픽셀의 r,g,b 색상 구하기&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from PIL import Image

# 이미지 객체로 생성
im = Image.open(file_) 

# RGB 모드로 변경 
rgb_im = im.convert('RGB')

# 지정한 좌표(1, 400)의 색상을 r,g,b 변수에 넣음
r, g, b = rgb_im.getpixel((1, 400)) 

print(r)
print(g)
print(b)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2&gt;누끼 이미지 만들기&lt;/h2&gt;
&lt;p&gt;이 방법은 r,g,b 값이 흰색일 경우 투명한 픽셀로 변경하여 누끼 이미지로 만드는 방법입니다.&lt;br /&gt;완전한 흰색이 아닌 경우 255 숫자의 범위를 낮추어서 범위를 조정한 후 사용할 수도 있습니다.&lt;br /&gt;누끼컷의 경우 png 만 가능하므로, 저장은 png로 해주셔야 합니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from PIL import Image

# 누끼컷으로 변경할 이미지
img = Image.open('./iwantnuki.png') 
img = img.convert(&quot;RGBA&quot;)
datas = img.getdata()
newData = []
for item in datas:
    if item[0] == 255 and item[1] == 255 and item[2] == 255:
        newData.append((255, 255, 255, 0))
    else:
        newData.append(item)
img.putdata(newData)

# png 확장자로 저장
img.save(&quot;./TransparentImage.png&quot;, &quot;PNG&quot;) &lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2&gt;이미지 위에 로고 붙이기&lt;/h2&gt;
&lt;p&gt;pillow로 이미지 위에 이미지를 붙일 수 있습니다.&lt;br /&gt;로고와 같은 이미지를 일괄적으로 붙이고 싶을 때 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from PIL import Image, ImageDraw

template = Image.open(&quot;/home/template.jpg&quot;) 
rgb_im = template.convert('RGB') 

logo = Image.open(&quot;/home/logo.jpg&quot;)

# template 이미지 객체 0,0 위치에 logo 이미지를 붙여줍니다.
rgb_im.paste(logo, (0, 0)) 

# 붙인 이미지를 새로운 이름으로 저장합니다.
rgb_im.save(&quot;/home/pasted_logo.jpg&quot;, &quot;JPEG&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;pillow 관련글&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/25&quot;&gt;파이썬 webp 파일 다루기 , webp 란?&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1564404315476&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://minimilab.tistory.com/25&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-original-url=&quot;https://minimilab.tistory.com/25&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/i5VQ2/hyCbXx7k6m/8JRhK599zxjQpPGK08k800/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/cI89aP/hyCbW0gAXK/KIhqK0zzPSk9TdUESldk3k/img.png?width=1430&amp;amp;height=455&amp;amp;face=0_0_1430_455');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;파이썬 webp 파일 다루기 , webp 란?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;webp 란? 구글에서 만든 새로운 이미지 압축 포맷이다. 이미지는 JPG, PNG, GIF 포맷을 일반적으로 사용했지만, 이 모든 것을 대체할 수 있는 것이 webp 형식이다. 확장자가 webp인데 GIF 처럼 애니메이션 이미지..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;minimilab.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9LRDa/btqw7v2XtGs/xlExJSfamVYdP48Cr8VS3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9LRDa/btqw7v2XtGs/xlExJSfamVYdP48Cr8VS3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9LRDa/btqw7v2XtGs/xlExJSfamVYdP48Cr8VS3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9LRDa%2Fbtqw7v2XtGs%2FxlExJSfamVYdP48Cr8VS3k%2Fimg.png&quot; width=&quot;500&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Python</category>
      <category>python image processing</category>
      <category>python pillow 라이브러리</category>
      <category>파이썬 pil</category>
      <category>파이썬 pillow</category>
      <category>파이썬 누끼</category>
      <category>파이썬 누끼이미지</category>
      <category>파이썬 이미지</category>
      <category>파이썬 이미지 붙이기</category>
      <category>파이썬 이미지처리</category>
      <category>파이썬 픽셀 색상</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/30</guid>
      <comments>https://minimilab.tistory.com/30#entry30comment</comments>
      <pubDate>Mon, 29 Jul 2019 21:46:42 +0900</pubDate>
    </item>
    <item>
      <title>티스토리 블로그 애드센스 사이드바 등록 방법</title>
      <link>https://minimilab.tistory.com/29</link>
      <description>&lt;h1&gt;티스토리&amp;nbsp;블로그 애드센스 사이드바 등록방법&lt;/h1&gt;
&lt;p&gt;티스토리 블로그에 구글 애드센스 사이드바를 등록하는 방법을 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;1. 티스토리 관리페이지 -&amp;gt; 플러그인 -&amp;gt; 배너출력 클릭&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;합니다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KLo1U/btqw7PNaTeK/6LjXTHveLJWiLwwLIBBS80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KLo1U/btqw7PNaTeK/6LjXTHveLJWiLwwLIBBS80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KLo1U/btqw7PNaTeK/6LjXTHveLJWiLwwLIBBS80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKLo1U%2Fbtqw7PNaTeK%2F6LjXTHveLJWiLwwLIBBS80%2Fimg.png&quot; data-filename=&quot;blob&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3&gt;&lt;b&gt;2. 적용 버튼 클릭&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;합니다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bETZtC/btqw56bgmTk/ruw22KWe8H1xKRisQgpuQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bETZtC/btqw56bgmTk/ruw22KWe8H1xKRisQgpuQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bETZtC/btqw56bgmTk/ruw22KWe8H1xKRisQgpuQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbETZtC%2Fbtqw56bgmTk%2Fruw22KWe8H1xKRisQgpuQ1%2Fimg.png&quot; width=&quot;600&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3&gt;&lt;b&gt;3.&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;티스토리 관리페이지 -&amp;gt;&lt;span&gt;&amp;nbsp;꾸미기 사이드바 클릭합니다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;[플러그인] HTML 배너출력 목록이 생긴 것을 확인할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2.PNG&quot; width=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vZsKc/btqw8BATmaS/5jAF6vmBCoHzA3JFgP9DP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vZsKc/btqw8BATmaS/5jAF6vmBCoHzA3JFgP9DP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vZsKc/btqw8BATmaS/5jAF6vmBCoHzA3JFgP9DP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvZsKc%2Fbtqw8BATmaS%2F5jAF6vmBCoHzA3JFgP9DP1%2Fimg.png&quot; data-filename=&quot;2.PNG&quot; width=&quot;600&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;h3&gt;&lt;b&gt;4. 생성된&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;[플러그인] HTML 배너출력을 드래그하여 오른쪽 사이드바 위치에 넣고 싶은 곳에 복사&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;합니다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(사진에 인피드 광고로 되어있는 것은 5 번에서 제목을 변경하였기 때문입니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;같은 방식으로 여러개 넣을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;3.PNG&quot; width=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcQzGt/btqw7bQHlZJ/sdBeaM3IO2crbktr29qzS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcQzGt/btqw7bQHlZJ/sdBeaM3IO2crbktr29qzS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcQzGt/btqw7bQHlZJ/sdBeaM3IO2crbktr29qzS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcQzGt%2Fbtqw7bQHlZJ%2FsdBeaM3IO2crbktr29qzS0%2Fimg.png&quot; data-filename=&quot;3.PNG&quot; width=&quot;600&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3&gt;&lt;b&gt;5. 편집을 클릭&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;합니다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;4.PNG&quot; width=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfM3Uj/btqw4oDyZRH/znfzuWQ9f09aLZVD8gEwWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfM3Uj/btqw4oDyZRH/znfzuWQ9f09aLZVD8gEwWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfM3Uj/btqw4oDyZRH/znfzuWQ9f09aLZVD8gEwWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfM3Uj%2Fbtqw4oDyZRH%2FznfzuWQ9f09aLZVD8gEwWk%2Fimg.png&quot; data-filename=&quot;4.PNG&quot; width=&quot;600&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3&gt;&lt;b&gt;6. 구글 애드센스에서 만든 소스를 HTML 소스 부분에 넣고 확인을 클릭합니다.&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;구글 애드센스 -&amp;gt; 광고단위 -&amp;gt; 디스플레이 광고 -&amp;gt; 수직형 클릭하여 자신의 사이트에 맞는 고정형 사이즈 혹은 반응형을 선택하여 소스를 만들고 해당 소스를 복사하여 붙여넣습니다.&lt;/p&gt;
&lt;p&gt;구글 애드센스 등록을 하지 못하신 분은 아래글을 먼저 확인해주세요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/23&quot;&gt;티스토리 구글 애드센스 신청방법&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://minimilab.tistory.com/27&quot;&gt;티스토리 구글 애드센스 승인 ! 한번에 승인받은 방법&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;5.PNG&quot; width=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/142u2/btqw6oCKZTW/cHtNRqh9rki34YX1BVQi11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/142u2/btqw6oCKZTW/cHtNRqh9rki34YX1BVQi11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/142u2/btqw6oCKZTW/cHtNRqh9rki34YX1BVQi11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F142u2%2Fbtqw6oCKZTW%2FcHtNRqh9rki34YX1BVQi11%2Fimg.png&quot; data-filename=&quot;5.PNG&quot; width=&quot;600&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;6.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4Btos/btqw5f0Bstz/6XzePcXYiVKy0wTsCRKcN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4Btos/btqw5f0Bstz/6XzePcXYiVKy0wTsCRKcN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4Btos/btqw5f0Bstz/6XzePcXYiVKy0wTsCRKcN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4Btos%2Fbtqw5f0Bstz%2F6XzePcXYiVKy0wTsCRKcN1%2Fimg.png&quot; data-filename=&quot;6.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3&gt;&lt;b&gt;7. 내 블로그 메인에서 사이드바가 뜨는지 확인해봅니다.&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;</description>
      <category>블로그 운영 팁</category>
      <category>블로그 애드센스 등록</category>
      <category>사이드바 애드센스 등록</category>
      <category>애드센스</category>
      <category>애드센스 블로그 등록</category>
      <category>애드센스 사이드바</category>
      <category>애드센스 사이드바 등록</category>
      <category>티스토리 메인 광고</category>
      <category>티스토리 사이드바 광고</category>
      <category>티스토리 애드센스 등록</category>
      <category>티스토리 애드센스 사이드바 등록</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/29</guid>
      <comments>https://minimilab.tistory.com/29#entry29comment</comments>
      <pubDate>Sun, 28 Jul 2019 21:36:00 +0900</pubDate>
    </item>
    <item>
      <title>팀뷰어 상업적 사용 해결 방법</title>
      <link>https://minimilab.tistory.com/28</link>
      <description>&lt;h1&gt;팀뷰어 상업적 사용 해결 방법&lt;/h1&gt;
&lt;p&gt;팀뷰어를 잘 사용하다가 아래와 같은 메세지가 떴다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;500&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XKhws/btqw5hw9M5V/0jUkYVwpAz9TkR2JQpRjF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XKhws/btqw5hw9M5V/0jUkYVwpAz9TkR2JQpRjF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XKhws/btqw5hw9M5V/0jUkYVwpAz9TkR2JQpRjF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXKhws%2Fbtqw5hw9M5V%2F0jUkYVwpAz9TkR2JQpRjF1%2Fimg.png&quot; width=&quot;500&quot; data-filename=&quot;blob&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;box&quot;&gt;현재 귀하 또는 귀하의 연결 파트너가 TeamViewer를 상업적으로 사용하고 있습니다.&lt;br /&gt;세션이 곧 종료될 예정입니다.&lt;br /&gt;무료버전은 오직 개인적 사용을 위한 것입니다.&amp;nbsp;&lt;/blockquote&gt;
&lt;p&gt;해결방법으로 돌아다니는 mac 주소도 변경해보고, 리셋 프로그램도 사용해보았지만 소용이 없었다.&lt;/p&gt;
&lt;p&gt;그러다가 크롬 원격 데스크톱을 알게되었다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;설치도 굉장히 간편한데다가, 크롬에서 동작되어 크롬만 있으면 원격 제어를 할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;우분투 컴퓨터와 윈도우 컴퓨터를 연결해봤는데 잘 동작되었다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기업에서도 무료&amp;nbsp;원격&amp;nbsp;제어&amp;nbsp;프로그램을 찾고 있다면, 고민할 필요없이 chrome 원격 데스크톱을 사용하면 될 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;크롬 원격 데스크톱 설치 및 사용방법은 아래와 같다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;1. 크롬 원격 데스크톱 사이트 접속&lt;/b&gt;&lt;/blockquote&gt;
&lt;figure id=&quot;og_1564237484647&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://remotedesktop.google.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-original-url=&quot;https://remotedesktop.google.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/byXgQp/hyB91nfi1l/QQwwyVffeOWPwnmRdIRw0K/img.png?width=593&amp;amp;height=648&amp;amp;face=0_0_593_648');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Chrome 원격 데스크톱&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;어디에서나 데스크톱 공유스마트폰, 태블릿, 다른 컴퓨터에서 내 컴퓨터에 안전하게 액세스하세요. 빠르고 간편하며 무료입니다.지원 주고받기어디에서나 원격으로 액세스웹, Android 및 iOS에서 사용할 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;remotedesktop.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;2. 시작하기 버튼 클릭&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.png&quot; width=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJQv2F/btqw56ovpqJ/qb1oHcz6k0ez7jSfzTX5d0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJQv2F/btqw56ovpqJ/qb1oHcz6k0ez7jSfzTX5d0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJQv2F/btqw56ovpqJ/qb1oHcz6k0ez7jSfzTX5d0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJQv2F%2Fbtqw56ovpqJ%2Fqb1oHcz6k0ez7jSfzTX5d0%2Fimg.png&quot; data-filename=&quot;1.png&quot; width=&quot;500&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;3. 다운로드 버튼 클릭&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJgXRz/btqw3kgYou7/PWkQVTDifRGjT3kJlKICLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJgXRz/btqw3kgYou7/PWkQVTDifRGjT3kJlKICLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJgXRz/btqw3kgYou7/PWkQVTDifRGjT3kJlKICLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJgXRz%2Fbtqw3kgYou7%2FPWkQVTDifRGjT3kJlKICLK%2Fimg.png&quot; data-filename=&quot;2.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;4. chrome remote desktop 에서 chromeremotedesktophost.msi 파일을 &lt;br /&gt;열도록 허용하여 설치&lt;/b&gt;&lt;/blockquote&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;4.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2PfmE/btqw7vVpP0T/QxgyPpfxcpBpuxvQYQWIe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2PfmE/btqw7vVpP0T/QxgyPpfxcpBpuxvQYQWIe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2PfmE/btqw7vVpP0T/QxgyPpfxcpBpuxvQYQWIe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2PfmE%2Fbtqw7vVpP0T%2FQxgyPpfxcpBpuxvQYQWIe1%2Fimg.png&quot; data-filename=&quot;4.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;5. 컴퓨터 닉네임 지정&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;5.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rHADx/btqw7QdXICM/qIt595BnRhXYfdwtknvsB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rHADx/btqw7QdXICM/qIt595BnRhXYfdwtknvsB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rHADx/btqw7QdXICM/qIt595BnRhXYfdwtknvsB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrHADx%2Fbtqw7QdXICM%2FqIt595BnRhXYfdwtknvsB0%2Fimg.png&quot; data-filename=&quot;5.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;6. 컴퓨터의 PIN 비밀번호 설정&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;6.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bElP0C/btqw6nwPQr0/PVJTi1MsYBkHlS957O85Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bElP0C/btqw6nwPQr0/PVJTi1MsYBkHlS957O85Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bElP0C/btqw6nwPQr0/PVJTi1MsYBkHlS957O85Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbElP0C%2Fbtqw6nwPQr0%2FPVJTi1MsYBkHlS957O85Xk%2Fimg.png&quot; data-filename=&quot;6.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;font-size: 1.25em;&quot; data-ke-style=&quot;normal&quot;&gt;&lt;b&gt;7. 설정 완료되면 설정한 컴퓨터가 보인다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;여기까지 하면 컴퓨터 등록이 완료된 것이다.&lt;/p&gt;
&lt;p&gt;원격제어를 하고 싶은 다른 컴퓨터에서&amp;nbsp;&lt;a href=&quot;https://remotedesktop.google.com/&quot;&gt;https://remotedesktop.google.com/&lt;/a&gt;&amp;nbsp;사이트에 접속하여,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;등록한 기기를 클릭하고 6번에서 설정한 PIN 번호를 입력하면 원격 제어가 시작된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;7.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQVTuK/btqw4oDhw64/jG0Mck13mtjuhTKuCsPgP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQVTuK/btqw4oDhw64/jG0Mck13mtjuhTKuCsPgP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQVTuK/btqw4oDhw64/jG0Mck13mtjuhTKuCsPgP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQVTuK%2Fbtqw4oDhw64%2FjG0Mck13mtjuhTKuCsPgP0%2Fimg.png&quot; data-filename=&quot;7.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;팀뷰어 상업적 사용 문제나 팀뷰어&amp;nbsp;라이센스 문제로 머리아플 때&amp;nbsp;무료인 크롬 원격 데스크톱을 사용해도 무리가 없을 것 같다.&amp;nbsp;&lt;/p&gt;</description>
      <category>책.영화.정보</category>
      <category>teamviewer 라이센스</category>
      <category>기업 무료 원격 제어 프로그램</category>
      <category>무료 원격제어</category>
      <category>크롬 원격</category>
      <category>크롬 원격 데스크톱</category>
      <category>크롬 원격 데스크톱 사용</category>
      <category>팀뷰어 라이센스</category>
      <category>팀뷰어 상업적</category>
      <category>팀뷰어 상업적 사용</category>
      <category>팀뷰어 상업적사용 해제</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/28</guid>
      <comments>https://minimilab.tistory.com/28#entry28comment</comments>
      <pubDate>Sun, 28 Jul 2019 00:02:20 +0900</pubDate>
    </item>
    <item>
      <title>티스토리 구글 애드센스 승인 ! 한번에 승인받은 방법</title>
      <link>https://minimilab.tistory.com/27</link>
      <description>&lt;h2&gt;구글&amp;nbsp;애드센스 한번에&amp;nbsp;승인 받다&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;구글 애드센스 신청방법을 작성하고, 승인이 되거나 떨어지면 이후 포스팅을 진행하겠다고 했었다.&lt;br /&gt;애드고시라고 해서 한번에 승인받지 못하더라도 계속 도전할 생각을 가지고 있었는데,&lt;br /&gt;다음날 바로 한번에 승인되었다는 이메일을 받았다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다른 블로그 포스팅에서 포스팅도 많이 쓰고, 방문자도 많은데 3 번만에 합격하고&lt;/p&gt;
&lt;p&gt;이런 글들을 많이 보았는데,&lt;/p&gt;
&lt;p&gt;나는 운이 좋았던 것인지 전혀 그정도 수치가 되지 않았는데&amp;nbsp;한번에 합격했다.&lt;/p&gt;
&lt;p&gt;어떤 상태에서 합격했는지 정리해보려고 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2&gt;작성한 글의 수&lt;/h2&gt;
&lt;p&gt;비공개 글을 제외하고 노출된 포스팅 수는 18개 였다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;8.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfXR2n/btqw7vujke1/ZTjz8LTEq0YKzOOZM2x4uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfXR2n/btqw7vujke1/ZTjz8LTEq0YKzOOZM2x4uK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfXR2n/btqw7vujke1/ZTjz8LTEq0YKzOOZM2x4uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfXR2n%2Fbtqw7vujke1%2FZTjz8LTEq0YKzOOZM2x4uK%2Fimg.png&quot; data-filename=&quot;8.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2&gt;방문자 수&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;방문자수는 굉장히 저조했다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;22일에 애드센스 신청을 했는데 그날 방문자가 18명이었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;22.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EJk3Q/btqw786pxKO/qlQSUFZ3sTgZLfvoHqmosK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EJk3Q/btqw786pxKO/qlQSUFZ3sTgZLfvoHqmosK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EJk3Q/btqw786pxKO/qlQSUFZ3sTgZLfvoHqmosK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEJk3Q%2Fbtqw786pxKO%2FqlQSUFZ3sTgZLfvoHqmosK%2Fimg.png&quot; data-filename=&quot;22.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2&gt;1일 1포스팅 진행 여부 ?&lt;/h2&gt;
&lt;p&gt;다른 사람의 블로그 포스팅을 찾아보면 1일 1포스팅을 해야 유리하다는 말이 많았다.&lt;br /&gt;하지만 나는 그렇게 성실하지 못하다.&lt;br /&gt;2달 동안 9개 정도의 포스팅을 유지하다가 구글 애드센스를 등록하고자 마음먹은 당일날&lt;br /&gt;8개의 글을 폭풍 업로드 했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;게다가 8개의 글은 내가 미리 작성해 놓은 글이었어서 2시간 정도 이내에 모두 등록을 했다.&lt;br /&gt;하루에 몇개 이상 등록하면 안되고, 몇시간 내에 등록하면 안되고 이런 글들이 많은데&lt;br /&gt;내가 승인이 된 걸 보면 상관이 없는 것 같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;5.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfZupD/btqw571TxEO/YOKrB7jFDhBXogZ4FlgWuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfZupD/btqw571TxEO/YOKrB7jFDhBXogZ4FlgWuk/img.png&quot; data-alt=&quot;작심삼일을 보여주는 5월의 포스팅&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfZupD/btqw571TxEO/YOKrB7jFDhBXogZ4FlgWuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfZupD%2Fbtqw571TxEO%2FYOKrB7jFDhBXogZ4FlgWuk%2Fimg.png&quot; data-filename=&quot;5.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;/&gt;&lt;/span&gt;&lt;figcaption&gt;작심삼일을 보여주는 5월의 포스팅&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;6.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DsUye/btqw7vOymJU/bOKKXtpohsOt101hsviX80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DsUye/btqw7vOymJU/bOKKXtpohsOt101hsviX80/img.png&quot; data-alt=&quot;5월보다 심한 6월 포스팅&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DsUye/btqw7vOymJU/bOKKXtpohsOt101hsviX80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDsUye%2Fbtqw7vOymJU%2FbOKKXtpohsOt101hsviX80%2Fimg.png&quot; data-filename=&quot;6.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;/&gt;&lt;/span&gt;&lt;figcaption&gt;5월보다 심한 6월 포스팅&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;7.PNG&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mEwmx/btqw8apB69D/kcK28D0ckzqp7xjL1Mefhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mEwmx/btqw8apB69D/kcK28D0ckzqp7xjL1Mefhk/img.png&quot; data-alt=&quot;7월에 폭풍 포스팅&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mEwmx/btqw8apB69D/kcK28D0ckzqp7xjL1Mefhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmEwmx%2Fbtqw8apB69D%2FkcK28D0ckzqp7xjL1Mefhk%2Fimg.png&quot; data-filename=&quot;7.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;/&gt;&lt;/span&gt;&lt;figcaption&gt;7월에 폭풍 포스팅&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2&gt;포스팅 당 1000자 유지 ?&lt;/h2&gt;
&lt;p&gt;사실 포스팅할 때 글자 수 같은건 생각하지 않고 작성했다가&lt;br /&gt;이 글을 작성하려고 몇자를 썼는지 살펴 보았다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;딱 1개만 1,000자가 넘고, 나머지는 300 ~ 500자 정도의 글이었다.&lt;br /&gt;나 스스로 길게 썼다고 생각해서 1,000자는 넘겠지라고 막연히 생각했는데&lt;br /&gt;1,000자를 넘기는 것은 꽤 긴 글이었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2&gt;애드핏이 애드센스보다 승인 받기 쉽다 ?&lt;/h2&gt;
&lt;p&gt;다른 사람들이 애드핏은 신청만 하면 다 되는 것 처럼 포스팅한 글이 많길래&lt;br /&gt;애드핏과 애드센스를 동시에 신청했다.&lt;br /&gt;애드센스 승인을 받지 못하면 애드핏이라도 달아 놓으려고 했다.&lt;br /&gt;애드핏도 신청한지 하루만에 답변이 왔는데 결과는 불합격이었다...&lt;br /&gt;사유는 컨텐츠 부족 ..&lt;br /&gt;애드핏은 컨텐츠를 어느정도 작성해야되는지 잘 모르겠지만 일단 애드센스 승인을 받았으니&lt;br /&gt;포스팅 수가 40개 정도 되면 신청해볼까 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;블로그에 떠도는 말들이 사실은 아닌 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;구글 애드센스를 승인 받기 위한 목표는 세우되 지례 겁먹고,&amp;nbsp;너무 시간 끌기보다는,&lt;/p&gt;
&lt;p&gt;포스팅 20개 정도 되었을 때 도전해보는 것이 좋을 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;구글 애드센스 신청방법을 알고 싶다면 아래의 글대로 따라하면 쉽게 신청할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1564219882791&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://minimilab.tistory.com/23&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-original-url=&quot;https://minimilab.tistory.com/23&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/1Y8Zc/hyB920tE8o/5x3rkEbdBlLmJDH6b5yUc1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bHSqWZ/hyB9X5Vl0b/r7XOXYOKOCDWwxwycLc5CK/img.png?width=918&amp;amp;height=918&amp;amp;face=0_0_918_918,https://scrap.kakaocdn.net/dn/bZXdXa/hyB90uO4Nq/hp94TKwK73KJmfdr3ayELK/img.png?width=805&amp;amp;height=808&amp;amp;face=0_0_805_808');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;티스토리 구글 애드센스 신청방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;티스토리 구글 애드센스를 등록하면서 신청방법을 정리해둔다. 애드고시라는 말이 있을 정도로 어렵다고 해서 포스팅을 40개 정도 등록하고 하려고 했으나, 성격이 급해서 18개 작성하고 우선 신청을 해본다. 떨어..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;minimilab.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>블로그 운영 팁</category>
      <category>구글 애드센스</category>
      <category>구글 애드센스 승인</category>
      <category>애드센스</category>
      <category>애드센스 노하우</category>
      <category>애드센스 승인</category>
      <category>애드센스 주의사항</category>
      <category>애드센스 팁</category>
      <category>애드센스 한번에 합격</category>
      <category>애드센스 합격</category>
      <category>애드핏</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/27</guid>
      <comments>https://minimilab.tistory.com/27#entry27comment</comments>
      <pubDate>Sat, 27 Jul 2019 18:41:00 +0900</pubDate>
    </item>
    <item>
      <title>[책 리뷰/요약] 모티베이터 - 조서환</title>
      <link>https://minimilab.tistory.com/26</link>
      <description>&lt;blockquote&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;사고로 오른손을 잃고도 노력과 자신감으로 &lt;br /&gt;이루어낸 마케팅 성공 스토리들을&lt;br /&gt;마치 영화를 보는 것처럼 시간가는 줄 모르고 빠져서 읽은 책&lt;br /&gt;모티베이터 - 조서환&lt;br /&gt;★★★★★&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;책 리뷰 모티베이터 조서환&lt;/h1&gt;
&lt;table class=&quot;tt-plugin-interpark&quot; style=&quot;background: #ffffff; border: 1px solid #e0e0e0; width: 723px; height: 134px;&quot; border=&quot;0&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;vertical-align: top; padding: 10px 0px 10px 10px; width: 70px;&quot;&gt;&lt;a href=&quot;http://book.interpark.com/blog/integration/product/itemDetail.rdo?prdNo=208381428&amp;amp;refererType=8303&amp;amp;bookblockname=bpmain_in&amp;amp;booklinkname=wg_search_FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&amp;amp;key=FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img style=&quot;border: 0 none;&quot; src=&quot;http://bimage.interpark.com/goods_image/1/4/2/8/208381428h.jpg&quot; width=&quot;66&quot; height=&quot;90&quot; /&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;vertical-align: top; padding: 10px 10px 10px 15px; width: 612.333px;&quot;&gt;
&lt;dl style=&quot;margin: 0; padding: 2px 0 0 0; list-style: none; font: 11px dotum, sans-serif; letter-spacing: -1px; color: #777;&quot;&gt;
&lt;dt style=&quot;padding: 0; margin: 0;&quot;&gt;&lt;a style=&quot;font-size: 12px; color: #444 !important; font-weight: bold; text-decoration: none !important;&quot; href=&quot;http://book.interpark.com/blog/integration/product/itemDetail.rdo?prdNo=208381428&amp;amp;refererType=8303&amp;amp;bookblockname=bpmain_in&amp;amp;booklinkname=wg_search_FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&amp;amp;key=FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모티베이터&lt;/a&gt;&lt;/dt&gt;
&lt;dd style=&quot;padding: 7px 0 0 0; margin: 0; color: #a0a0a0;&quot;&gt;국내도서&lt;/dd&gt;
&lt;dd style=&quot;padding: 17px 0 0 0; margin: 0;&quot;&gt;저자 : 조서환&lt;/dd&gt;
&lt;dd style=&quot;padding: 4px 0 0 0; margin: 0;&quot;&gt;출판 : 위즈덤하우스 &lt;span style=&quot;letter-spacing: normal;&quot;&gt;2011.06.10&lt;/span&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;a style=&quot;float: right; width: 44px; height: 11px; background: url('//t1.daumcdn.net/tistory_admin/static/images/icon_ipark_detail.gif') no-repeat; overflow: hidden; display: block; text-indent: -1000em;&quot; href=&quot;http://book.interpark.com/blog/integration/product/itemDetail.rdo?prdNo=208381428&amp;amp;refererType=8303&amp;amp;bookblockname=bpmain_in&amp;amp;booklinkname=wg_search_FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&amp;amp;key=FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;상세보기&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;모티베이터 책의 저자이신 조서환 박사님은 군대에서 사고로 오른손을 잃고도,&lt;br /&gt;노력과 자신감으로 양손이 멀쩡한 사람들도 이루어내기 어려운 업적들을 마케팅 분야에서 세우셨다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;일반인들은 어렵지 않은 오른손으로 글쓰기, 운전하기, 골프치기와 같은 일상적인 활동들 조차도&lt;br /&gt;일반사람들처럼 하기위해 얼마나 많은 노력을 하셨을 지 생각해보면 뭉클해지는데,&lt;br /&gt;그 훨씬 이상을 해내신 것을 보니 귀감이 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감명 깊었던 부분은 사고를 당하시고 애경그룹에서 면접을 볼때 였다.&lt;br /&gt;오른손을 숨기려고 했으나, 면접 중간에 면접관들이 알게 되었고 바로 면접은 중지되고 면접장을 나오셔야 했다.&lt;br /&gt;하지만 이내 다시 회사로 돌아가 면접관들에게 자신의 생각을 명확하게 전달하고&lt;br /&gt;당당히 합격한 부분이 인상 깊었다.&lt;br /&gt;자신감을 갖고 간절히 원하면 이루어진다는 것을 몸소 보여주셨다고 생각한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;입사해서도 약자라고 바라보는 시선으로 인해 업무 평가 D 를 연속으로 받았지만&lt;br /&gt;그에 굴하지 않고 성과 들을 발휘하며 특진을 거듭하고 여러 회사에도 스카우트되며&lt;br /&gt;애경산업,유니레버,다이알사,로슈사 의 고위 마케팅 직급을 보내셨다.&lt;br /&gt;세우셨던 과정들과 업적들의 기록이 마치 영화를 보는 것처럼 시간가는 줄 모르고 빠져서 읽었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;내가 결혼을 하게 된다면 나도 박사님의 아내와 같은 사람이 되어주고 싶다.&lt;/p&gt;
&lt;p&gt;오른 손을 잃었어도 완벽하게 믿어주는 아내 덕분에 그 믿음에 헛되지 않도록 그는 죽을만큼 최선을 다했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;모티베이터 책 이외에도 9권의 책을 쓰셨던데, 모두 읽어보고 싶다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;박세니 대표님이 스승으로 모시는 분이신 만큼&lt;br /&gt;근본적인 철학과 강조하는 부분들이 일치했다.&lt;br /&gt;관련하여 내가 생각했을 때 모티베이터 책에서 전달하고자 하는 메세지를 7가지로 짧게 요약해보았다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2&gt;1. 자신감의 중요성&lt;/h2&gt;
&lt;p&gt;누군가한테 무언가를 보여줄 때는아주 당당하게 내가 진짜 전문가라는 태도를 보이는 것이 중요하다.&lt;br /&gt;조서환 박사님은 연봉협상 때 내가 받아야 할 자격이 그 금액이라고 생각하고 예산이 부족하다면&lt;br /&gt;값싼 사람을 찾아보라고 당당히 말하고도 합격하셨다.&lt;br /&gt;물건을 판매하는 사람이 물건에 대해 자신감이 없다면 사겠는가?&lt;br /&gt;강하게 소비자 여러분, 걱정 말고 사십시오. 만족하실 것입니다. 라고 크게 외쳐야 한다.&lt;/p&gt;
&lt;h2&gt;2. 계획하고, 준비하고, 연습하자.&lt;/h2&gt;
&lt;p&gt;자기 확신을 갖게 되면 강한 자신감이 생긴다.&lt;br /&gt;자기 확신은 계획하고 준비하고 연습했을 때 나온다.&lt;br /&gt;대리 진급 무렵 조인벤처 기념식에서 통역 진행하라는 지시가 왔을 때,&lt;br /&gt;회장이 할 만한 이야기를 영어로 옮긴 뒤 그 내용을 전부 외웠고 성공적으로 기념식을 마쳤다.&lt;br /&gt;진정한 용기는 필요할 때 막힘없이 능력을 발휘하도록 실력을 갖췄을 때 비로소 나온다.&lt;br /&gt;작아도 뭔가 해보는 것이 중요하고 거기에 최선의 노력을 다해 필사적으로 해냄으로써 스스로 성공 요건을 끄집어 내야 한다.&lt;/p&gt;
&lt;h2&gt;3. 긍정적인 사고방식의 중요성&lt;/h2&gt;
&lt;p&gt;부정적으로 생각하면 한도 끝도 없지만, 긍정적으로 생각하면 모든 생활이 윤택해진다.&lt;br /&gt;다른 사람은 돈 내고 시간 투자 해가면서 영어를 배우는데,&lt;br /&gt;회사 돈으로 택시타고 다니면서 업무에서 영어를 사용하니 스스로를 복이 많은 사람이라고 생각하며&lt;br /&gt;업무에 대한 부정적인 생각을 전환한다.&lt;br /&gt;운칠 복삼이다.&lt;/p&gt;
&lt;h2&gt;4. 상상할 수 있는 것은 다 이루어진다.&lt;/h2&gt;
&lt;p&gt;왜 안돼? 부터 출발하면 답이 나온다.&lt;br /&gt;핵심은 무엇을 보든 항상 물음표를 붙이는 것, 자기 자신, 세상, 사물에 대한 물음 등&lt;/p&gt;
&lt;p&gt;세상에 극복되지 않는 것은 없다.&lt;br /&gt;인간이 상상할 수 있는 것은 다 이루어진다.&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;!-- 수평형 --&gt;
&lt;p&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-5170996487649025&quot; data-ad-slot=&quot;3530178217&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;h2&gt;5. 명확한 포지셔닝&lt;/h2&gt;
&lt;p&gt;아주 세분화된 명확한 포지셔닝이 필요하다.&lt;br /&gt;고급 제품이냐, 벨류 포 머니 제품이냐, 값싼 제품이냐 타겟팅에 따라서 광고도 다르게 한다.&lt;br /&gt;예를들어 대학교 앞에는 커플 요금제 포스터를, 대형마트에는 가족요금제를 광고하는 포스터를 각기 다르게 제작하여 붙인다.&lt;br /&gt;상대방이 무엇을 얻고자 하는지를 알고 계획하자.&lt;/p&gt;
&lt;h2&gt;6. 전문가의 태도&lt;/h2&gt;
&lt;p&gt;당황하거나 모른다고 말하지 않는다.&lt;br /&gt;모르는 질문이 나와도 아 그거 정말 좋은 질문이네요,&lt;br /&gt;저도 별첨자료에 준비해왔는데 수치가 여러개라서 바로 이메일로 알려드리겠습니다. 라고 유연한 태도를 갖춘다.&lt;/p&gt;
&lt;h2&gt;7. 생활 속 차별화&lt;/h2&gt;
&lt;p&gt;쇼핑할 때도 무심코 흘러가지 않고, 어떻게 디스플레이를 해놨고, 어떤 색을 매치시켜놨는지 주의 깊게 본다.&lt;br /&gt;매일 새벽 4시 25분에 일어나서 5시부터 새벽기도를 하고 1시간 동안 중국어를 배우고, 걷기운동을 한다.&lt;/p&gt;
&lt;table class=&quot;tt-plugin-interpark&quot; style=&quot;background: #fff; border: 1px solid #e0e0e0; width: 408px;&quot; border=&quot;0&quot; width=&quot;100%&quot; cellspacing=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;vertical-align: top; padding: 10px 0 10px 10px;&quot; width=&quot;70&quot;&gt;&lt;a href=&quot;http://book.interpark.com/blog/integration/product/itemDetail.rdo?prdNo=208381428&amp;amp;refererType=8303&amp;amp;bookblockname=bpmain_in&amp;amp;booklinkname=wg_search_FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&amp;amp;key=FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img style=&quot;border: 0 none;&quot; src=&quot;http://bimage.interpark.com/goods_image/1/4/2/8/208381428h.jpg&quot; width=&quot;66&quot; height=&quot;90&quot; /&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;vertical-align: top; padding: 10px 10px 10px 15px; text-align: justify;&quot;&gt;
&lt;dl style=&quot;margin: 0; padding: 2px 0 0 0; list-style: none; font: 11px dotum, sans-serif; letter-spacing: -1px; color: #777;&quot;&gt;
&lt;dt style=&quot;padding: 0; margin: 0;&quot;&gt;&lt;a style=&quot;font-size: 12px; color: #444 !important; font-weight: bold; text-decoration: none !important;&quot; href=&quot;http://book.interpark.com/blog/integration/product/itemDetail.rdo?prdNo=208381428&amp;amp;refererType=8303&amp;amp;bookblockname=bpmain_in&amp;amp;booklinkname=wg_search_FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&amp;amp;key=FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모티베이터&lt;/a&gt;&lt;/dt&gt;
&lt;dd style=&quot;padding: 7px 0 0 0; margin: 0; color: #a0a0a0;&quot;&gt;국내도서&lt;/dd&gt;
&lt;dd style=&quot;padding: 17px 0 0 0; margin: 0;&quot;&gt;저자 : 조서환&lt;/dd&gt;
&lt;dd style=&quot;padding: 4px 0 0 0; margin: 0;&quot;&gt;출판 : 위즈덤하우스 &lt;span style=&quot;letter-spacing: normal;&quot;&gt;2011.06.10&lt;/span&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;a style=&quot;float: right; width: 44px; height: 11px; background: url('//t1.daumcdn.net/tistory_admin/static/images/icon_ipark_detail.gif') no-repeat; overflow: hidden; display: block; text-indent: -1000em;&quot; href=&quot;http://book.interpark.com/blog/integration/product/itemDetail.rdo?prdNo=208381428&amp;amp;refererType=8303&amp;amp;bookblockname=bpmain_in&amp;amp;booklinkname=wg_search_FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&amp;amp;key=FF846BA4F89BBCAE046EB5550182420FC8B470110EC45F26DAFB1FB6342CAFEA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;상세보기&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1564284250714&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://minimilab.tistory.com/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-original-url=&quot;https://minimilab.tistory.com/17&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bIdTe0/hyB90Ww5eW/YEhG2KV6fkIfPhlR0pRdeK/img.png?width=270&amp;amp;height=270&amp;amp;face=28_42_80_98,https://scrap.kakaocdn.net/dn/bAym9u/hyB9WGBsZK/dlgNDfsrKgwEKXcAkFn731/img.png?width=270&amp;amp;height=270&amp;amp;face=28_42_80_98');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[책 리뷰] 공부하지마라 최면해라 박세니&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;자기개발 서적의 완결판 같은 책 실제 예시들과 함께 쓰여있어 이해하기 쉽다. ★★★★★ 공부하지 마라 최면해라! 국내도서 저자 : 박세니 출판 : 도서출판 맑은샘 2013.03.15 상세보기 시크릿, 2억 빚을 진 내..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;minimilab.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;image&quot; data-ke-style=&quot;alignCenter&quot;&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x59Un/btqw7QZsHnB/zBb24kzWtjWDdzEVheYhZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x59Un/btqw7QZsHnB/zBb24kzWtjWDdzEVheYhZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x59Un/btqw7QZsHnB/zBb24kzWtjWDdzEVheYhZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx59Un%2Fbtqw7QZsHnB%2FzBb24kzWtjWDdzEVheYhZK%2Fimg.png&quot; data-filename=&quot;blob&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>책.영화.정보</category>
      <category>마케팅 방법</category>
      <category>마케팅 책</category>
      <category>모티베이터</category>
      <category>모티베이터 리뷰</category>
      <category>모티베이터 요약</category>
      <category>모티베이터 책</category>
      <category>모티베이터 책리뷰</category>
      <category>박세니</category>
      <category>박세니 책 추천</category>
      <category>조서환</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/26</guid>
      <comments>https://minimilab.tistory.com/26#entry26comment</comments>
      <pubDate>Sat, 27 Jul 2019 01:27:07 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 webp 파일 다루기 , webp 란?</title>
      <link>https://minimilab.tistory.com/25</link>
      <description>&lt;h1&gt;webp 란?&lt;/h1&gt;
&lt;p&gt;구글에서 만든 새로운 이미지 압축 포맷이다.&lt;br /&gt;이미지는 JPG, PNG, GIF 포맷을 일반적으로 사용했지만, 이 모든 것을 대체할 수 있는 것이 webp 형식이다.&lt;br /&gt;확장자가 webp인데 GIF 처럼 애니메이션 이미지도 되고 JPG 이미지도 된다.&lt;br /&gt;구글의 크롬처럼 webp 를 지원하는 웹 브라우저만 사용이 가능하여 많이 활용하지는 않는 추세였는데,&lt;br /&gt;근래 1달 정도 전부터 쇼핑몰에서 webp 형식으로 gif이나 jpg 형식을 많이 사용하고 있다.&lt;/p&gt;
&lt;h2&gt;파이썬으로 webp 다루기&lt;/h2&gt;
&lt;p&gt;PIL 라이브러리(6.1.0 버전 이상)에서 webp 파일을 지원한다.&lt;br /&gt;다만 파이썬 버전에 따라 지원하지 않을 수도 있으니, 아래의 표를 참고하자.&lt;br /&gt;지원하지 않는 경우에는 리눅스에 webp 를 설치하여 사용할 수도 있다.&lt;br /&gt;마지막으로 url 확장자가 webp 로 끝나는 경우에 움직이는 경우 gif, 움직이지 않는 경우 jpg, png 로 변경하여 실행해보면 실행된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot;&gt;* PIL 지원 파이썬 버전 (&lt;a href=&quot;https://buildmedia.readthedocs.org/media/pdf/pillow/stable/pillow.pdf&quot;&gt;https://buildmedia.readthedocs.org/media/pdf/pillow/stable/pillow.pdf&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsakPS/btqw2zQCT8k/RlnQ7cTIQBcaRRqwnj3a7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsakPS/btqw2zQCT8k/RlnQ7cTIQBcaRRqwnj3a7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsakPS/btqw2zQCT8k/RlnQ7cTIQBcaRRqwnj3a7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsakPS%2Fbtqw2zQCT8k%2FRlnQ7cTIQBcaRRqwnj3a7K%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;1. 파이썬 PIL로 webp 파일 gif로 변환하기&lt;/h2&gt;
&lt;p&gt;* PIL 설치&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;$ pip install Pillow&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;* webp -&amp;gt; gif 변환 예제&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from PIL import Image

im = Image.open('/home/minimilab/PycharmProjects/minimilab.webp')
im.save('/home/minimilab/PycharmProjects/minimilab.gif', 'gif', save_all=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. linux 에서 webp 파일 png 로 변환하기&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;- 움직이지&amp;nbsp;않는&amp;nbsp;webp&amp;nbsp;만&amp;nbsp;-&amp;gt;&amp;nbsp;png&amp;nbsp;로&amp;nbsp;가능하다.&amp;nbsp; &lt;br /&gt;- 고정된&amp;nbsp;이미지가&amp;nbsp;아닌&amp;nbsp;animated&amp;nbsp;파일(gif)은&amp;nbsp;지원을&amp;nbsp;하지&amp;nbsp;않으며, animated 파일은 webmux를&amp;nbsp;install 하여 사용하자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;* linux에 webp 설치&lt;/p&gt;
&lt;pre id=&quot;code_1563982257155&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;~$ sudo apt-get install webp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;* webp -&amp;gt; png 변환 예제&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;~$ dwebp file.webp -o file.png&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python</category>
      <category>linux webp</category>
      <category>PIL webp</category>
      <category>pillow webp</category>
      <category>python webp</category>
      <category>webp</category>
      <category>webp 변환</category>
      <category>webp 이미지</category>
      <category>webp 확장자</category>
      <category>webp란</category>
      <category>파이썬 webp</category>
      <author>운영하는 사람</author>
      <guid isPermaLink="true">https://minimilab.tistory.com/25</guid>
      <comments>https://minimilab.tistory.com/25#entry25comment</comments>
      <pubDate>Thu, 25 Jul 2019 00:33:20 +0900</pubDate>
    </item>
  </channel>
</rss>