<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>예담직업전문학교(IT)</title>
        <link>https://velog.io/</link>
        <description>대구 SW개발 &amp; DB전문교육기관</description>
        <lastBuildDate>Fri, 20 Dec 2024 05:21:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>예담직업전문학교(IT)</title>
            <url>https://velog.velcdn.com/images/yedam_it/profile/cf55aaaf-a52e-43de-8d42-a99266c057ea/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 예담직업전문학교(IT). All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yedam_it" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Vue.js Options API VS Composition API]]></title>
            <link>https://velog.io/@yedam_it/Vue.js-Options-API-VS-Composition-API</link>
            <guid>https://velog.io/@yedam_it/Vue.js-Options-API-VS-Composition-API</guid>
            <pubDate>Fri, 20 Dec 2024 05:21:02 GMT</pubDate>
            <description><![CDATA[<h2 id="options-api">Options API</h2>
<h2 id="composition-api">Composition API</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[Windows 단축키]]></title>
            <link>https://velog.io/@yedam_it/Windows-%EB%8B%A8%EC%B6%95%ED%82%A4</link>
            <guid>https://velog.io/@yedam_it/Windows-%EB%8B%A8%EC%B6%95%ED%82%A4</guid>
            <pubDate>Tue, 10 Dec 2024 07:59:48 GMT</pubDate>
            <description><![CDATA[<h3 id="키보드-특수문자-이름">키보드 특수문자 이름</h3>
<table>
<thead>
<tr>
<th align="left">기호</th>
<th>영문이름</th>
<th align="left">한글이름</th>
</tr>
</thead>
<tbody><tr>
<td align="left">`</td>
<td>Grave Accent, backtick, Backquote</td>
<td align="left">백틱</td>
</tr>
<tr>
<td align="left">~</td>
<td>Tilde(틸드)</td>
<td align="left">물결표시</td>
</tr>
<tr>
<td align="left">!</td>
<td>Exclamation point</td>
<td align="left">포인트 / 느낌표</td>
</tr>
<tr>
<td align="left">@</td>
<td>At sign / Commercial at</td>
<td align="left">골뱅이</td>
</tr>
<tr>
<td align="left">#</td>
<td>Crosshatch / Sharp</td>
<td align="left">샵,해쉬</td>
</tr>
<tr>
<td align="left">$</td>
<td>Dollar Sign</td>
<td align="left">딸라</td>
</tr>
<tr>
<td align="left">%</td>
<td>Percent Sign</td>
<td align="left">퍼센트</td>
</tr>
<tr>
<td align="left">^</td>
<td>Circumflex/caret</td>
<td align="left">꺽쇠,웃는 표시</td>
</tr>
<tr>
<td align="left">&amp;</td>
<td>Ampersand</td>
<td align="left">앤드(AND)</td>
</tr>
<tr>
<td align="left">*</td>
<td>Astrrisk</td>
<td align="left">별</td>
</tr>
<tr>
<td align="left">_</td>
<td>Underscore / Underline</td>
<td align="left">밑줄</td>
</tr>
<tr>
<td align="left">-</td>
<td>Minus sign / hyphen / Dash</td>
<td align="left">빼기</td>
</tr>
<tr>
<td align="left">+</td>
<td>Plus sign</td>
<td align="left">더하기</td>
</tr>
<tr>
<td align="left">=</td>
<td>Equal sign</td>
<td align="left">같다</td>
</tr>
<tr>
<td align="left">/</td>
<td>Slash / Virgule</td>
<td align="left">슬래쉬 / 나누기</td>
</tr>
<tr>
<td align="left">\</td>
<td>Back Slash</td>
<td align="left">백 슬래쉬</td>
</tr>
<tr>
<td align="left">|</td>
<td>Vertical Bar</td>
<td align="left">수직작대기, 파이프</td>
</tr>
<tr>
<td align="left">:</td>
<td>Colon / Double Dott</td>
<td align="left">콜론/땡땡</td>
</tr>
<tr>
<td align="left">;</td>
<td>Semicolon</td>
<td align="left">세미콜론</td>
</tr>
<tr>
<td align="left">,</td>
<td>Comma</td>
<td align="left">쉼표</td>
</tr>
<tr>
<td align="left">.</td>
<td>Period / Fuall Stop</td>
<td align="left">점/마침표</td>
</tr>
<tr>
<td align="left">&quot;</td>
<td>double quotes</td>
<td align="left">큰(쌍) 따옴표</td>
</tr>
<tr>
<td align="left">&#39;</td>
<td>single quotes / Apostrophe</td>
<td align="left">작은(홀) 따옴표</td>
</tr>
<tr>
<td align="left">?</td>
<td>Question Mark</td>
<td align="left">물음표</td>
</tr>
<tr>
<td align="left">( )</td>
<td>Parenthesis</td>
<td align="left">소괄호</td>
</tr>
<tr>
<td align="left">{ }</td>
<td>Brace</td>
<td align="left">중괄호</td>
</tr>
<tr>
<td align="left">[ ]</td>
<td>Bracket</td>
<td align="left">대괄호</td>
</tr>
<tr>
<td align="left">&lt; &gt;</td>
<td>Angle Bracket</td>
<td align="left">화살표</td>
</tr>
<tr>
<td align="left">&gt;</td>
<td>Greater Than Sign</td>
<td align="left">크다</td>
</tr>
<tr>
<td align="left">&lt;</td>
<td>Less Than sign</td>
<td align="left">작다</td>
</tr>
<tr>
<td align="left"></td>
<td>Space / Blank</td>
<td align="left">빈칸 / 공백</td>
</tr>
</tbody></table>
<h3 id="윈도우참조키">윈도우참조키</h3>
<p><a href="https://support.microsoft.com/ko-kr/windows/windows%EC%9D%98-%EB%B0%94%EB%A1%9C-%EA%B0%80%EA%B8%B0-%ED%82%A4-dcc61a57-8ff0-cffe-9796-cb9706c75eec#desktop">reference</a>  </p>
<p>|  단축키 | 설명 |
| :- | :- | :-  |
|이모지/특수문자| <strong>윈도우로고키 + 마침표(.) 또는 세미콜론(;)</strong> | 이모지패널 열기(✔✨👍) | 
|| <strong>한글자음 + 한자 + Tab</strong> | 해당 자음의 특수문자 전체 |
|| <strong>윈도우로고키 + Shift + S</strong> | 스크린샷 |
|윈도우 창| <strong>윈도우로로키 + M</strong> | 모든 창 최소화  |
|| <strong>윈도우로고키 + D</strong> | 바탕화면 보기 |
|| <strong>윈도우로고키 + 방향키</strong> | 화면분할. 다른 옆에 무슨 창을 최대화할 건지 선택하는 화면이 나옴 |
|| <strong>윈도우로로키 + Shift + M</strong> | 모든 창 복원  |
|| <strong>Ctrl + Shift + T</strong> | Edge 브라우저에서 닫힌 탭을 복원 |
|| <strong>윈도우로고키 + E</strong> | 파일 탐색기 실행  |
|복사/붙여넣기| <strong>Ctrl + A</strong> | 전체선택 |
|| <strong>Ctrl + C</strong> | 복사 |
|| <strong>Ctrl + X</strong> | 자르기 |
|| <strong>Ctrl + V</strong> | 붙여넣기 |
|| <strong>Ctrl + Z</strong> | 작업 취소 |
|| <strong>Ctrl + Y</strong> | 작업 재실행 |
|가상데스크톱| <strong>윈도우로고키 + Tab</strong> | 작업보기 열기 |
|| <strong>윈도우로고키 + Ctrl + 방향키</strong> | 윈도우 작업화면 이동 |
|| <strong>윈도우로고키 + Ctrl + D</strong> | 가상 데스크톱 추가 |
|| <strong>윈도우로고키 + Ctrl + F4</strong> | 사용 중인 가상 데스크톱 닫기 |</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS 실습]]></title>
            <link>https://velog.io/@yedam_it/AWS-%EC%8B%A4%EC%8A%B5</link>
            <guid>https://velog.io/@yedam_it/AWS-%EC%8B%A4%EC%8A%B5</guid>
            <pubDate>Mon, 09 Dec 2024 23:46:00 GMT</pubDate>
            <description><![CDATA[<h3 id="실습1-s3-이용하여-폴더-백업하기">실습1: S3 이용하여 폴더 백업하기</h3>
<p>a. ACL 작성</p>
<pre><code class="language-json">{    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Id&quot;: &quot;Polic  y1700440993280&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Sid&quot;: &quot;Stmt1700440977436&quot;,
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Principal&quot;: &quot;*&quot;,
            &quot;Action&quot;: &quot;s3:*&quot;,
            &quot;Resource&quot;: &quot;arn:aws:s3:::cyan-bucket/*&quot;
        }
    ]
}</code></pre>
<pre><code class="language-bash">aws s3 ls
aws s3  sync  . s3://cyan-bucket2/web</code></pre>
<h3 id="실습2-amazon-dynamodb-nosql-테이블-생성-및-조회">실습2: Amazon DynamoDB NoSQL 테이블 생성 및 조회</h3>
<p>reference</p>
<ul>
<li><a href="https://aws.amazon.com/ko/tutorials/create-nosql-table/">create nosql table</a></li>
<li><a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/getting-started-step-1.html">amazondynamodb</a></li>
</ul>
<ol>
<li>NoSQL 테이블 생성
a. DynamoDB 콘솔에서 테이블생성 버튼
b. 테이블 세부정보 입력
테이블이름 : Music
파티션키 : Artist
정렬키 : songTitle
c. 테이블생성</li>
</ol>
<p>**  파티션 키는 확장성을 위해 파티션 간에 데이터를 분산하는 데 사용됩니다. 값 범위가 넓고 액세스 패턴이 고르게 분산될 가능성이 있는 속성을 선택하는 것이 중요합니다.</p>
<ol start="2">
<li><p>NoSQL 테이블 데이터 입력
a. 항목탐색
b. 좌축 메뉴에서 Music 선택
c. 항목생성 버튼
d. 값입력
e. 항목생성</p>
</li>
<li><p>NoSQL 테이블 조회</p>
</li>
<li><p>데이터 삭제</p>
</li>
<li><p>NoSQL 테이블 삭제</p>
</li>
</ol>
<h3 id="실습3-aws-cli-설정">실습3: AWS CLI 설정</h3>
<p>reference</p>
<ul>
<li>(aws cli 설정)[<a href="https://aws.amazon.com/ko/getting-started/guides/setup-environment/module-three/%5D">https://aws.amazon.com/ko/getting-started/guides/setup-environment/module-three/]</a></li>
</ul>
<p>a. AWS CLI 설치
다운로드 : <a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html">https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html</a>
파일명 : AWSCLIV2.msi</p>
<p>b. 설치 확인</p>
<p>C:\Users\user&gt;aws --version
aws-cli/2.22.12 Python/3.12.6 Windows/11 exe/AMD64</p>
<p>c. sso 설정</p>
<pre><code class="language-bash">C:\Users\user&gt;aws configure sso
SSO session name (Recommended): Test1
SSO start URL [None]: https://d-9b67788a7b.awsapps.com/start
SSO region [None]: ap-northeast-2
SSO registration scopes [sso:account:access]:
Attempting to automatically open the SSO authorization page in your default browser.

aws s3 ls --profile admin-1
aws ec2 describe-vpcs --profile admin-1
aws dynamodb list-tables --profile </code></pre>
<h3 id="실습4-lambda-및-dynamodb를-사용한-crud-http-api-생성">실습4 Lambda 및 DynamoDB를 사용한 CRUD HTTP API 생성</h3>
<p>reference</p>
<ul>
<li><p><a href="https://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/http-api-dynamo-db.html">http-api-dynamo-db</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/programming-with-python.html">programming-with-python</a></p>
<p>IAM(Identity and Access Management) : 리소스 접근 권한</p>
</li>
</ul>
<ol>
<li>롤 생성</li>
<li>Lambda 검색하고 함수생성 클릭</li>
<li>함수이름 입력하고 런타임은 python 선택하고 함수생성</li>
<li><pre><code>import boto3
</code></pre></li>
</ol>
<p>dynamodb = boto3.resource(&#39;dynamodb&#39;)</p>
<p>table = dynamodb.Table(&#39;Music&#39;)</p>
<p>def lambda_handler(event, context):
    try:<br>        response=table.put_item(Item=event)<br>        return table.scan()
    except:
        raise</p>
<pre><code>

### 실습5: API Gateway에서 Lambda 사용
reference
https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/services-apigateway-tutorial.html
</code></pre><p>aws lambda invoke ^
--function-name LambdaFunctionOverHttps ^
--payload file://input.txt outputfile.txt ^
--cli-binary-format raw-in-base64-out --profile admin-1</p>
<p>curl <a href="https://5bwffjeoq6.execute-api.ap-northeast-2.amazonaws.com/test/DynamoDBManager">https://5bwffjeoq6.execute-api.ap-northeast-2.amazonaws.com/test/DynamoDBManager</a> ^
-d &#39;{&quot;operation&quot;: &quot;create&quot;, &quot;payload&quot;: {&quot;Item&quot;: {&quot;id&quot;: &quot;5678EFGH&quot;, &quot;number&quot;: 15}}}&#39;</p>
<p>curl <a href="https://5bwffjeoq6.execute-api.ap-northeast-2.amazonaws.com/test/DynamoDBManager">https://5bwffjeoq6.execute-api.ap-northeast-2.amazonaws.com/test/DynamoDBManager</a> -d ^
&quot;{&quot;operation&quot;: &quot;read&quot;, &quot;payload&quot;: {&quot;Key&quot;: {&quot;id&quot;: &quot;5678EFGH&quot;}}}&quot;</p>
<pre><code>
### 실습6: ELB 구성
VPC 구성요소  

1. VPC
2. 서브넷(Subnet)
3. 라우팅테이블
4. 보안그룹
5. 인터넷게이트웨이
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[mariadb]]></title>
            <link>https://velog.io/@yedam_it/mariadb</link>
            <guid>https://velog.io/@yedam_it/mariadb</guid>
            <pubDate>Mon, 09 Dec 2024 05:04:59 GMT</pubDate>
            <description><![CDATA[<p>reference</p>
<ul>
<li><a href="https://github.com/mariadb-corporation/mariadb-connector-nodejs/blob/master/documentation/promise-api.md">mariadb-connector-nodejs</a></li>
<li><a href="https://mariadb.com/docs/server/connect/programming-languages/nodejs/callback/connection-pools/">connection-pools</a></li>
</ul>
<p>node에서 maridb 연결
<code>permitSetMultiParamEntries</code> 을 true로 설정해야 <code>insert into table명 set ?</code> 이 가능함</p>
<pre><code class="language-javascript">const mariadb = require(&#39;mariadb&#39;);
const pool = mariadb.createPool({
     host: &#39;127.0.0.1&#39;, 
     user:&#39;user01&#39;, 
     password: &#39;0000&#39;,
     database: &#39;shop&#39;,
     permitSetMultiParamEntries : true,
     connectionLimit: 5
});
async function asyncFunction() {
  let conn;
  try {
    conn = await pool.getConnection();   
    const data = { username: &#39;scott&#39;, password: &#39;0000&#39; };
    const res = await pool.query(&quot;insert into emp set ? &quot;,data) ;
    console.log(res);  // { affectedRows: 1, insertId: 1, warningStatus: 0 }

    const rows = await conn.query(&quot;SELECT * from emp&quot;);
    console.log(rows); 

  } catch (err) {
    throw err;
  } finally {
    if (conn) conn.end();
  }
}
asyncFunction().then(() =&gt; {
  pool.end();
});</code></pre>
<pre><code class="language-bash">mkdir shop
cd shop
npm init
npm install mariadb</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[sql 튜닝]]></title>
            <link>https://velog.io/@yedam_it/sql-%ED%8A%9C%EB%8B%9D</link>
            <guid>https://velog.io/@yedam_it/sql-%ED%8A%9C%EB%8B%9D</guid>
            <pubDate>Mon, 02 Dec 2024 23:26:11 GMT</pubDate>
            <description><![CDATA[<h3 id="실행계획execution-plan">실행계획(execution plan)</h3>
<p>sql 파싱 -&gt; sql 최적화 -&gt; sql 실행</p>
<p>sql 파싱</p>
<ul>
<li>SQL 구문 오류 검사</li>
<li>대상객체가 존재 여부와 제약조건 권한 등을 체크</li>
<li>sql 실행 비용(cost) 계산</li>
<li>어떤 방식으로 실행할지 판단하여 실행계획을 결정</li>
</ul>
<h3 id="스캔방식의-구조">스캔방식의 구조</h3>
<ul>
<li><p>Full Table Scan
순차적으로 블록을 액세스하고 멀티블록 I/O와 병렬 액세스 가능</p>
</li>
<li><p>Index Scan
인덱스 블록을 액세스 후 해당 rowid로 데이터 블록 액세스하고 싱글 블록 I/O 가능</p>
</li>
<li><p>DW 업무 전용서버에서는 Multi Block Read Count를 크게 지정하고 OLTP 업무 위주의 서버라면 작게 지정.</p>
</li>
<li><p>데이터가 저장되어 있는 블록의 수로 판단하여 풀 테이블 스캔을 할지 인덱스 스캔을 할지 결정해야 함.</p>
</li>
<li><p>Index range scan이 table full scan 보다 느려지는 조회 건수 지점을 인덱스 손익분기점 이라 하는데, 테이블 전체 데이터양의 10 ~ 15% 이상을 출력하게 되면 오히려 table full scan이 효율적일 수 있다.</p>
</li>
<li><p>테이블의 데이터가 저장되어 있는 전체 블록 수가 Multi Block Read Count보다 작다면 한번의 I/O만으로 해당 데이터를 추출할 수 있으므로 인덱스를 생성할 필요가 없음</p>
</li>
</ul>
<h3 id="인덱스-활용시-주의사항">인덱스 활용시 주의사항</h3>
<p>조건절에 기술되는 컬럼의 인덱스를 생성한 후 사용자의 실수나 의도적인 사용 제한으로 인해 인덱스 사용이 제한되는 경우입니다.</p>
<ol>
<li><p>인덱스 컬럼을 가공을 하면 안됨.</p>
<pre><code class="language-sql">-- full table scan (좌변을 연산하게 되면 풀테이블 스캔 방식 적용)
where substr(product_code, 1, 3) = &#39;PRD&#39;    

-- index scan ( 와일드카드(%) 는 끝에 작성하게 되면 인덱스 스캔 방식을 적용 )
where product_code like &#39;PRD%&#39;              </code></pre>
<pre><code class="language-sql">-- full table scan
where trunc(regdate) = to_date(&#39;20240101&#39;, &#39;yyyymmdd&#39;) 

-- index range scan
where regdate between to_date(&#39;20240101&#39; || &#39;000000&#39;, &#39;yyyymmddhhmiss&#39;)         
                  and to_date(&#39;20240101&#39; || &#39;235959&#39;, &#39;yyyymmddhhmiss&#39;)</code></pre>
</li>
<li><p>인덱스와 상수로 제공되는 값의 데이터 형식 차이로 인해 발생하는 문제(묵시적 형변환이 발생)</p>
<pre><code class="language-sql">-- 타입이 맞지 않아 인덱스 컬럼에 형변환이 발생
where cnt = &#39;10&#39;    ==&gt;   where to_char(cnt) = &#39;10&#39;    </code></pre>
</li>
<li><p>not 연산자는 인덱스를 사용하지 않으므로 not exists, minus 등을 이용하여 인덱스 사용을 유도해야 함.</p>
<pre><code class="language-sql">where empno &lt;&gt; &#39;1234&#39;
    ==&gt;  where not exists (select &#39;1&#39; from employees where employee_id = &#39;1234&#39;)
    ==&gt;  select * from employees
         minus
         select * from employees where where employee_id = &#39;1234&#39;</code></pre>
</li>
<li><p>is not null은 인덱스 사용에 제한을 받음
좁은 분포도의 경우에는 인덱스를 이용하고 넓은 분포도의 경우에는 인덱스를 변형하여 full table scan을 수행하도록 하는 경우에 데이터의 분포도 균형이 깨지고 저장 공강의 낭비만 발생한다면 null 값을 사용하는게 효율적임</p>
<pre><code class="language-sql">where status = &#39;A&#39;
where status = &#39;E&#39;  --&gt; 분포도가 80%를 넘어간다면 null을 사용 --&gt;  status = to_char(null)</code></pre>
</li>
<li><p>OR 대신 Union을 사용</p>
<pre><code class="language-sql">WHERE department = &#39;Marketing&#39; OR department = &#39;IT&#39;;         -- full table scan
  ==&gt; SELECT * FROM employees                                -- index scan
       WHERE department = &#39;Marketing&#39;
       union all
      SELECT * FROM employees
       WHERE department = &#39;IT&#39;</code></pre>
</li>
</ol>
<h3 id="sql-쿼리-속도를-올리려면">sql 쿼리 속도를 올리려면</h3>
<ol>
<li><p>필요한 Row, Column만 가져와라.</p>
<pre><code class="language-sql">SELECT e.name, e.department, e.sales
FROM employees e
JOIN (
SELECT department, MAX(sales) AS max_sales
FROM employees
GROUP BY department
) d ON e.department = d.department AND e.sales = d.max_sales;</code></pre>
</li>
<li><p>분석 함수를 최대한 활용</p>
<ul>
<li>전통적인 집계 함수와 달리 사전에 데이터를 그룹화할 필요가 없어요. 이는 불필요한 자원 소모를 줄이고 쿼리 성능을 높임</li>
<li>복잡한 데이터 분석 과정에서 발생할 수 있는 중간 결과물의 저장과 재처리를 최소화할 수 있어요. 이는 쿼리 실행 시간을 크게 단축</li>
<li>순위 결정 함수: ROW_NUMBER(), RANK(), DENSE_RANK()</li>
<li>데이터 변화를 추적하는 분석 함수: LEAD(), LAG() 등의 함수</li>
</ul>
<pre><code class="language-sql">-- 급여가 높은 상위 3명의 직원 정보만 추출
WITH ranked_employees AS (
SELECT  name,
       department,
       salary,
       ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank
 FROM employees
)
SELECT *
 FROM ranked_employees
WHERE rank &lt;= 3;</code></pre>
</li>
<li><p>계산값을 미리 저장해두고, 나중에 사용하라.</p>
<ul>
<li>쿼리가 실행될 때마다 방대한 양의 주문 및 고객 데이터를 모두 읽어서 복잡한 계산을 수행해야하고 특히 재구매율 계산을 위해 서브쿼리까지 사용되고 있어 쿼리 속도는 더욱 느려짐</li>
<li>계산 결과를 별도의 테이블에 저장하여 사용하며 주기적으로 계산 결과 업데이트</li>
</ul>
</li>
<li><p>hint 사용</p>
<ul>
<li>힌트란 SQL 튜닝의 핵심 부분으로 일종의 지시 구문이다.</li>
<li>오라클 옵티마이저(Optimizer)에게 SQL문 실행을 위한 데이터를 스캐닝하는 경로, 조인하는 방법 등을 알려주기 위해 SQL사용자가 SQL 구문에 작성하는 것을 뜻한다.</li>
<li>오라클이 항상 최적의 실행 경로를 만들어 내기는 불가능하기 때문에 직접 최적의 실행 경로를 작성해 주는 것</li>
<li>힌트, 인덱스, 조인의 개념을 정확히 알고 사용하지 않은 무분별한 힌트의 사용은 성능의 저하를 초래하기 때문에 잘 알고 최적의 실행 경로를 알고 있을 경우 적절하게 사용하여야 한다.</li>
</ul>
<pre><code class="language-sql">select /*+ index_asc(board ipx_board_regdate) */ * from board ;
select /*+ full(board) */ * from board ;</code></pre>
</li>
</ol>
<h3 id="인덱스-설정-시-유의사항">인덱스 설정 시 유의사항</h3>
<ul>
<li>인덱스를 생성해야 하는 경우
인덱스를 많이 생성한다고 반드시 좋은 것(쿼리속도 향상)은 아니다. DML 작업이 커밋되면 변경사항을 인덱스에도 반영해야하는데, 테이블과 연관된 인덱스가 많을 수록 관련 인덱스를 모두 갱신해야 함으로 서버의 부담이 증가한다. 따라서 다음과 같은 경우에만 인덱스를 생성해야한다.</li>
</ul>
<ol>
<li><p>열(Column)에 많은 NULL 값이 포함된 경우<br>NULL 값을 제외하고 검색해야하는 경우 인덱스를 사용하면 검색 속도를 향상시킬 수 있다.</p>
</li>
<li><p>열(Column)에 광범위한 값이 포함된 경우<br>인덱스 컬럼에 다양한 값이 있는 경우 인덱스를 사용하면 검색 속도를 향상시킬 수 있다.</p>
</li>
<li><p>WHERE절 혹은 JOIN 조건에 자주 사용되는 경우</p>
</li>
<li><p>테이블이 크고 대부분의 쿼리가 테이블에서 2~4% 미만의 행을 검색할 것으로 예상되는경우</p>
</li>
<li><p>ORDER BY 절에 자주 사용되는 경우<br>인덱스는 기본적으로 정렬되어있어서 order by를 수행할 필요가 없다.</p>
</li>
</ol>
<ul>
<li>인덱스 생성을 안해야 하는 경우</li>
</ul>
<ol>
<li>데이터 변경이 자주 발생</li>
<li>검색할 데이터가 전체 데이터의 20% 이상인 경우(데이터 중복도가 높은 경우)</li>
</ol>
<h3 id="요약정리"><a href="https://community.heartcount.io/ko/query-optimization-tips/">요약정리</a></h3>
<ul>
<li><p>데이터를 변형하는 연산은 가급적 피하고, 원본 데이터를 직접 비교하는 조건을 사용하세요. 이는 인덱스 활용도를 높여 쿼리 속도를 향상시킵니다.</p>
</li>
<li><p>OR 연산자 대신 UNION을 활용하면 각 조건을 독립적으로 최적화하고 인덱스를 효과적으로 사용할 수 있습니다.</p>
</li>
<li><p>불필요한 Row와 Column을 제외하고 꼭 필요한 데이터만 조회하세요. 이는 데이터 처리량을 최소화하여 쿼리 성능을 높입니다.</p>
</li>
<li><p>ROW_NUMBER(), RANK(), LEAD(), LAG() 등의 분석 함수를 적극 활용하면 복잡한 데이터 분석을 유연하고 효율적으로 수행할 수 있습니다.</p>
</li>
<li><p>LIKE 연산자와 와일드카드(%)를 사용할 때는 문자열 끝에 와일드카드를 두는 것이 인덱스 활용에 유리합니다.</p>
</li>
<li><p>복잡한 계산은 실시간으로 처리하기보다는 미리 계산해서 저장해두고 주기적으로 업데이트하는 것이 효율적입니다.</p>
<pre><code class="language-sql">CREATE TABLE BOARD
( BNO NUMBER(10,0) primary key,
TITLE VARCHAR2(1000),
CONTENTS VARCHAR2(4000),
WRITER VARCHAR2(1000),
REGDATE DATE,
UPDATEDATE DATE DEFAULT sysdate,
IMAGE VARCHAR2(2000)
) ;

create sequence SEQ_BOARD start with 107;
INSERT INTO BOARD( BNO,TITLE,CONTENTS,WRITER,REGDATE,UPDATEDATE,IMAGE)
SELECT SEQ_BOARD.NEXTVAL, TITLE,CONTENTS,WRITER,REGDATE+1,UPDATEDATE+1, IMAGE from board;

select count(*) from board;

select * from dba_data_files;
ALTER DATABASE DATAFILE &#39;C:\ORACLEXE\APP\ORACLE\ORADATA\XE\UNDOTBS1.DBF&#39; RESIZE 1000M;</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 코딩 가이드]]></title>
            <link>https://velog.io/@yedam_it/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BD%94%EB%94%A9-%EA%B0%80%EC%9D%B4%EB%93%9C</link>
            <guid>https://velog.io/@yedam_it/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BD%94%EB%94%A9-%EA%B0%80%EC%9D%B4%EB%93%9C</guid>
            <pubDate>Wed, 27 Nov 2024 09:04:26 GMT</pubDate>
            <description><![CDATA[<p>코딩 표준을 준수하면 가독성이 좋아지고 유지보수가 수월해짐.
개발자간의 코드를 협업하고 이해하기 쉬워짐.
버그와 에러의 발생을 최소화할 수 있음.</p>
<h1 id="코딩-가이드">코딩 가이드</h1>
<h3 id="naming-convention">Naming Convention</h3>
<ul>
<li>snake_case : 테이블 컬럼명</li>
<li>camelCase : 메서드(함수)명</li>
<li>PascalCase : 클래스명</li>
<li>UPPER_CASE : 상수</li>
<li>kebab-case : html 태그/속성, 스프링 yml, url주소</li>
</ul>
<h3 id="comments-and-documentation">Comments and Documentation</h3>
<ul>
<li>다른 개발자가 코드를 보고 맥락을 이해하도록 주석을 작성</li>
<li>주석은 간결하게 작성하고 일반적인 것들은 주석에서 제외</li>
</ul>
<h3 id="indent들여쓰기와-공백">indent(들여쓰기)와 공백</h3>
<ul>
<li>가로 들여쓰기 : 2칸 공백 사용</li>
<li>세로 들여쓰기 : 논리 블록 사이에 빈줄을 넣어 코드 분리</li>
<li>예약어 뒤에는 공백 추가(if, for..)</li>
<li>함수 선언 괄호 앞에 공백 추가</li>
<li>연산자, 콤마, 콜론 뒤에 공백 추가</li>
</ul>
<pre><code>var x = 2
var obj = { &#39;key&#39;: &#39;value&#39; } 
var list = [1, 2, 3, 4]
function greet (name, options) { 
  if (name === &#39;John&#39;) {
    // ...
  } else {
    // ...
  }
}
</code></pre><h3 id="함수-배치">함수 배치</h3>
<ul>
<li><p>함수 호이스팅<br>함수가 선언되기 전에 호출할 수 있는 개념으로서 코드를 먼저 작성하고 함수 선언는 그 다음에 작성<br>함수 선언에만 사용되고 함수 표현식에는 적용안됨</p>
</li>
<li><p>코드 가독성<br>관련기능을 그룹화하고 서로 가까이 배치<br>#region folding for VS Code 확장팩을 이용하여 코드 영역을 나누고 코드 폴딩</p>
<pre><code> // #resion 이름  ~~~ // #endregion 로 </code></pre><p>변수선언, 함수 선언, 이벤트 핸들러 등 기능별로 영역을 나누어서 코딩</p>
</li>
<li><p>종속성
다른 함수에서 참조되는 함수를 먼저 선언
함수가 다른 함수에 의존하는 경우 의존하는 함수 뒤에 위치</p>
</li>
<li><p>범위 및 액세스
함수내에 선언된 함수는 부모 함수의 변수와 함수에 접근이 가능함<br>너무 깊은 중첩 레벨은 사용하지 말 것</p>
</li>
</ul>
<h3 id="linter">Linter</h3>
<p>Linter라는 도구를 사용하면 내가 작성한 코드가 스타일 가이드를 준수하고 있는지를 자동으로 확인할 수 있고, 스타일 개선과 관련된 제안도 받을 수 있습니다.</p>
<ul>
<li>JSLint</li>
<li>ESLint</li>
</ul>
<pre><code class="language-javascript">/*! 
    파일명 : DateUtil.js
      작성일 : 2020-10-01   
      작성자 : 개발팀 홍길동   

      수정일        수정자         수정내용
      ------       ------     -------------------
      2020.10.01    홍길동        신규작업 
    2020.11.10    김기자        today()함수 추가
*/

/**
 * @type {Object.&lt;string, number&gt;}  상품별 주문수량
 */
let product;

/**
 * a와 b를 더한 결과를 반환
 * @param {number} a 첫번째 숫자
 * @param {number} b 두번째 숫자
 * @returns {number} a와 b를 더한 결과
 */
function plus(a, b) {
  return a + b;
}</code></pre>
<h1 id="구글-javascript-스타일-가이드">구글 JavaScript 스타일 가이드</h1>
<h3 id="2-소스파일">2. 소스파일</h3>
<ul>
<li>파일명은 밑줄(_) 또는 대시(-)를 포함할 수 있으며 확장자는 .js 여야 합니다.</li>
<li>UTF-8 인코딩</li>
<li>공백문자는 탭을 사용하지 말고 스페이스바를 사용</li>
<li>Non-ASCII characters</li>
</ul>
<h3 id="3-소스파일-구조">3. 소스파일 구조</h3>
<ul>
<li>각 섹션 사이에 1~2줄의 빈줄로 구분
```</li>
</ul>
<ol>
<li>License or copyright information, if present</li>
<li>@fileoverview JSDoc, if present</li>
<li>goog.module statement, if a goog.module file</li>
<li>ES import statements, if an ES module</li>
<li>goog.require and goog.requireType statements</li>
<li>The file’s implementation<pre><code></code></pre></li>
</ol>
<h3 id="4-포맷팅">4. 포맷팅</h3>
<h4 id="41-중괄호">4.1 중괄호</h4>
<ul>
<li><p>모든 제어문에 중괄호는 필요하며 본문에 문장이 하나만 있어도 필요함.</p>
</li>
<li><p>줄바꿈을 생략할 수 있는 유일한 경우는 줄바꿈 없이 한 줄에 전부 들어갈 수 있는 간단한 if 문만 가능함.</p>
</li>
<li><p>여는 중괄호뒤에 줄바꿈이 있고, 닫는 중괄호뒤에 줄바꿈이 있는데 닫는 중괄호 뒤에 else, catch 등이 오는 경우는 예외임</p>
<pre><code class="language-javascript">class InnerClass {
constructor() {}

/** @param {number} foo */
method(foo) {
  if (condition(foo)) {
    try {
      // Note: this might fail.
      something();
    } catch (err) {
      recover();
    }
  }
}
}</code></pre>
</li>
<li><p>빈 블록이나 블록과 유사한 구조는 열자마자 바로 닫을 수 있으며, 그 사이에 문자, 공백, 줄 바꿈이 없어야 합니다.</p>
<pre><code class="language-javascript">function doNothing() {}</code></pre>
</li>
</ul>
<h4 id="42-들여쓰기">4.2 들여쓰기</h4>
<ul>
<li><p>새로운 블록 들여쓰기는 2칸 사용</p>
</li>
<li><p>배열, 객체 상수는 블록처럼 들여쓰기를 지정할 수도 있고 옆으로 나열할 수도 있음</p>
<pre><code class="language-javascript">const a = [
0,
1,
2,
];
const b = [0, 1, 2];
const c = {
a: 0,
b: 1,
};
const d = {a: 0, b: 1};
someMethod(foo, [
0, 1, 2,
], bar);</code></pre>
</li>
<li><p>Class 선언에서 클래스 선언 뒤나 메서드 끝에 세미콜론을 적지 말고 상속인 경우 @extends JSDoc 주석을 작성</p>
</li>
<li><p>익명함수 선언할 때 함수 본문은 이전 들여쓰기보다 두칸 더 들여쓰기함</p>
</li>
<li><p>Switch 문장에서 case 라벨 뒤에는 줄바꿈을 하고 2칸 들여쓰기</p>
<pre><code class="language-javascript">switch (animal) {
case Animal.BANDERSNATCH:
  handleBandersnatch();
  break;

case Animal.JABBERWOCK:
  handleJabberwock();
  break;

default:
  throw new Error(&#39;Unknown animal&#39;);
}</code></pre>
</li>
</ul>
<h4 id="43-문장">4.3 문장</h4>
<ul>
<li>한 줄에 하나의 구문만 작성</li>
<li>모든 문장은 세미콜론으로 끝나야 함.</li>
</ul>
<h4 id="44-열제한-80">4.4 열제한 80</h4>
<ul>
<li>컬럼 길이는 80자를 넘지않도록 하고 코드를 여러 줄로 나누어서 작성. </li>
<li>예외사항<ul>
<li>import, export</li>
<li>long URL</li>
<li>shell 명령어</li>
<li>긴 문자열 상수(ex: 긴 파일경로명)</li>
</ul>
</li>
</ul>
<h3 id="45-line-wrapping줄바꿈">4.5 Line-wrapping(줄바꿈)</h3>
<ul>
<li>열 제한을 준수하기 위해서 하나의 문장을 여러 줄로 나누어서 작성.</li>
<li>지역변수나 메서드를 작성하면 줄바꿈을 하지 않고도 해결할 수 있음.</li>
<li>return value 절에서 return과 리턴값 사이에는 줄바꿈을 하지 않음.</li>
<li>하나의 문장에서 줄바꿈이 필요하다면 기호(, 연산자) 뒤에서 줄바꿈이 발생함.</li>
<li>원래 줄에서 +4만큼 들여쓰기</li>
</ul>
<h3 id="46-공백">4.6 공백</h3>
<ul>
<li>수직 여백<ul>
<li>필드의 논리적인 그룹을 만들 때 빈줄 삽입</li>
<li>함수 본문의 시작 또는 끝에 있는 빈 줄은 허용되지 않음</li>
<li>여러 줄의 빈줄은 허용하지만 권장되지는 않음</li>
</ul>
</li>
<li>수평 여백</li>
</ul>
<h3 id="47-공백">4.7 공백</h3>
<h1 id="airbnb-javascript-스타일-가이드">Airbnb JavaScript 스타일 가이드</h1>
<h2 id="목차">목차</h2>
<ol>
<li><a href="#%EB%8D%B0%EC%9D%B4%ED%84%B0%ED%98%95">Types</a></li>
<li><a href="#references">References</a></li>
<li><a href="#objects">Objects</a></li>
<li><a href="#arrays">Arrays</a></li>
<li><a href="#destructuring">Destructuring</a></li>
<li><a href="#strings">Strings</a></li>
<li><a href="#functions">Functions</a></li>
<li><a href="#arrow-functions">Arrow Functions</a></li>
<li><a href="#classes--constructors">Classes &amp; Constructors</a></li>
<li><a href="#modules">Modules</a></li>
<li><a href="#iterators-and-generators">Iterators and Generators</a></li>
<li><a href="#properties">Properties</a></li>
<li><a href="#variables">Variables</a></li>
<li><a href="#hoisting">Hoisting</a></li>
<li><a href="#comparison-operators--equality">Comparison Operators &amp; Equality</a></li>
<li><a href="#blocks">Blocks</a></li>
<li><a href="#control-statements">Control Statements</a></li>
<li><a href="#comments">Comments</a></li>
<li><a href="#whitespace">Whitespace</a></li>
<li><a href="#commas">Commas</a></li>
<li><a href="#semicolons">Semicolons</a></li>
<li><a href="#type-casting--coercion">Type Casting &amp; Coercion</a></li>
<li><a href="#naming-conventions">Naming Conventions</a></li>
<li><a href="#accessors">Accessors</a></li>
<li><a href="#events">Events</a></li>
<li><a href="#jquery">jQuery</a></li>
<li><a href="#ecmascript-5-compatibility">ECMAScript 5 Compatibility</a></li>
<li><a href="#ecmascript-6-es-2015-styles">ECMAScript 6+ (ES 2015+) Styles</a></li>
<li><a href="#standard-library">Standard Library</a></li>
<li><a href="#testing">Testing</a></li>
<li><a href="#performance">Performance</a></li>
<li><a href="#resources">Resources</a></li>
<li><a href="#in-the-wild">In the Wild</a></li>
<li><a href="#translation">Translation</a></li>
<li><a href="#the-javascript-style-guide-guide">The JavaScript Style Guide Guide</a></li>
<li><a href="#chat-with-us-about-javascript">Chat With Us About JavaScript</a></li>
<li><a href="#contributors">Contributors</a></li>
<li><a href="#license">License</a></li>
<li><a href="#amendments">Amendments</a></li>
</ol>
<h2 id="데이터형">데이터형</h2>
<p>  <a name="types--primitives"></a><a name="1.1"></a></p>
<ul>
<li><p><a href="#types--primitives">1.1</a> <strong>Primitives</strong>: 기본형은 값을 직접 조작합니다.</p>
<ul>
<li><code>string</code></li>
<li><code>number</code></li>
<li><code>boolean</code></li>
<li><code>null</code></li>
<li><code>undefined</code></li>
</ul>
</li>
</ul>
<pre><code>&lt;br /&gt;

```javascript
const foo = 1;
let bar = foo;

bar = 9;

console.log(foo, bar); // =&gt; 1, 9
```</code></pre><p>  <a name="types--complex"></a><a name="1.2"></a></p>
<ul>
<li><p><a href="#types--complex">1.2</a>  <strong>Complex</strong>: 복합형은 참조를 통해서 값을 조작합니다.</p>
<ul>
<li><code>object</code></li>
<li><code>array</code></li>
<li><code>function</code></li>
</ul>
<br />

<pre><code class="language-javascript">const foo = [1, 2];
const bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // =&gt; 9, 9</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="references">References</h2>
<p>  <a name="references--prefer-const"></a><a name="2.1"></a></p>
<ul>
<li><p><a href="#references--prefer-const">2.1</a> 모든 참조는  <code>var</code> 대신에 <code>const</code> 를 사용합니다. eslint: <a href="https://eslint.org/docs/rules/prefer-const"><code>prefer-const</code></a>, <a href="https://eslint.org/docs/rules/no-const-assign"><code>no-const-assign</code></a></p>
<blockquote>
<p>Why? 참조를 재할당 할 수 없으므로, 버그로 이어지고 이해하기 어려운 코드가 되는것을 방지합니다.</p>
</blockquote>
<pre><code class="language-javascript">// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;</code></pre>
<p><a name="references--disallow-var"></a><a name="2.2"></a></p>
</li>
<li><p><a href="#references--disallow-var">2.2</a> 참조를 재할당해야한다면 <code>var</code> 대신 <code>let</code> 을 사용합니다. eslint: <a href="https://eslint.org/docs/rules/no-var"><code>no-var</code></a></p>
<blockquote>
<p>Why? function-scoped 인 <code>var</code> 보다는  block-scoped 인 <code>let</code> 을 사용</p>
</blockquote>
<pre><code class="language-javascript">// bad
var count = 1;
if (true) {
  count += 1;
}

// good, use the let.
let count = 1;
if (true) {
  count += 1;
}</code></pre>
<p><a name="references--block-scope"></a><a name="2.3"></a></p>
</li>
<li><p><a href="#references--block-scope">2.3</a> Note that both <code>let</code> and <code>const</code> are block-scoped, whereas <code>var</code> is function-scoped.</p>
<pre><code class="language-javascript">// const and let only exist in the blocks they are defined in.
{
  let a = 1;
  const b = 1;
  var c = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError
console.log(c); // Prints 1</code></pre>
<p>In the above code, you can see that referencing <code>a</code> and <code>b</code> will produce a ReferenceError, while <code>c</code> contains the number. This is because <code>a</code> and <code>b</code> are block scoped, while <code>c</code> is scoped to the containing function.</p>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="objects">Objects</h2>
<p>  <a name="objects--no-new"></a><a name="3.1"></a></p>
<ul>
<li><p><a href="#objects--no-new">3.1</a> Use the literal syntax for object creation. eslint: <a href="https://eslint.org/docs/rules/no-new-object"><code>no-new-object</code></a></p>
<pre><code class="language-javascript">// bad
const item = new Object();

// good
const item = {};</code></pre>
<p><a name="es6-computed-properties"></a><a name="3.4"></a></p>
</li>
<li><p><a href="#es6-computed-properties">3.2</a> Use computed property names when creating objects with dynamic property names.</p>
<blockquote>
<p>Why? They allow you to define all the properties of an object in one place.</p>
</blockquote>
<pre><code class="language-javascript">
function getKey(k) {
  return `a key named ${k}`;
}

// bad
const obj = {
  id: 5,
  name: &#39;San Francisco&#39;,
};
obj[getKey(&#39;enabled&#39;)] = true;

// good
const obj = {
  id: 5,
  name: &#39;San Francisco&#39;,
  [getKey(&#39;enabled&#39;)]: true,
};</code></pre>
<p><a name="es6-object-shorthand"></a><a name="3.5"></a></p>
</li>
<li><p><a href="#es6-object-shorthand">3.3</a> Use object method shorthand. eslint: <a href="https://eslint.org/docs/rules/object-shorthand"><code>object-shorthand</code></a></p>
<pre><code class="language-javascript">// bad
const atom = {
  value: 1,

  addValue: function (value) {
    return atom.value + value;
  },
};

// good
const atom = {
  value: 1,

  addValue(value) {
    return atom.value + value;
  },
};</code></pre>
<p><a name="es6-object-concise"></a><a name="3.6"></a></p>
</li>
<li><p><a href="#es6-object-concise">3.4</a> Use property value shorthand. eslint: <a href="https://eslint.org/docs/rules/object-shorthand"><code>object-shorthand</code></a></p>
<blockquote>
<p>Why? It is shorter and descriptive.</p>
</blockquote>
<pre><code class="language-javascript">const lukeSkywalker = &#39;Luke Skywalker&#39;;

// bad
const obj = {
  lukeSkywalker: lukeSkywalker,
};

// good
const obj = {
  lukeSkywalker,
};</code></pre>
<p><a name="objects--grouped-shorthand"></a><a name="3.7"></a></p>
</li>
<li><p><a href="#objects--grouped-shorthand">3.5</a> Group your shorthand properties at the beginning of your object declaration.</p>
<blockquote>
<p>Why? It’s easier to tell which properties are using the shorthand.</p>
</blockquote>
<pre><code class="language-javascript">const anakinSkywalker = &#39;Anakin Skywalker&#39;;
const lukeSkywalker = &#39;Luke Skywalker&#39;;

// bad
const obj = {
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  lukeSkywalker,
  episodeThree: 3,
  mayTheFourth: 4,
  anakinSkywalker,
};

// good
const obj = {
  lukeSkywalker,
  anakinSkywalker,
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  episodeThree: 3,
  mayTheFourth: 4,
};</code></pre>
<p><a name="objects--quoted-props"></a><a name="3.8"></a></p>
</li>
<li><p><a href="#objects--quoted-props">3.6</a> Only quote properties that are invalid identifiers. eslint: <a href="https://eslint.org/docs/rules/quote-props"><code>quote-props</code></a></p>
<blockquote>
<p>Why? In general we consider it subjectively easier to read. It improves syntax highlighting, and is also more easily optimized by many JS engines.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const bad = {
  &#39;foo&#39;: 3,
  &#39;bar&#39;: 4,
  &#39;data-blah&#39;: 5,
};

// good
const good = {
  foo: 3,
  bar: 4,
  &#39;data-blah&#39;: 5,
};</code></pre>
<p><a name="objects--prototype-builtins"></a></p>
</li>
<li><p><a href="#objects--prototype-builtins">3.7</a> Do not call <code>Object.prototype</code> methods directly, such as <code>hasOwnProperty</code>, <code>propertyIsEnumerable</code>, and <code>isPrototypeOf</code>. eslint: <a href="https://eslint.org/docs/rules/no-prototype-builtins"><code>no-prototype-builtins</code></a></p>
<blockquote>
<p>Why? These methods may be shadowed by properties on the object in question - consider <code>{ hasOwnProperty: false }</code> - or, the object may be a null object (<code>Object.create(null)</code>). In modern browsers that support ES2022, or with a polyfill such as <a href="https://npmjs.com/object.hasown">https://npmjs.com/object.hasown</a>, <code>Object.hasOwn</code> can also be used as an alternative to <code>Object.prototype.hasOwnProperty.call</code>.</p>
</blockquote>
<pre><code class="language-javascript">// bad
console.log(object.hasOwnProperty(key));

// good
console.log(Object.prototype.hasOwnProperty.call(object, key));

// better
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
console.log(has.call(object, key));

// best
console.log(Object.hasOwn(object, key)); // only supported in browsers that support ES2022

/* or */
import has from &#39;has&#39;; // https://www.npmjs.com/package/has
console.log(has(object, key));
/* or */
console.log(Object.hasOwn(object, key)); // https://www.npmjs.com/package/object.hasown</code></pre>
<p><a name="objects--rest-spread"></a></p>
</li>
<li><p><a href="#objects--rest-spread">3.8</a> Prefer the object spread syntax over <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign"><code>Object.assign</code></a> to shallow-copy objects. Use the object rest parameter syntax to get a new object with certain properties omitted. eslint: <a href="https://eslint.org/docs/rules/prefer-object-spread"><code>prefer-object-spread</code></a></p>
<pre><code class="language-javascript">// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this

// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy =&gt; { a: 1, b: 2, c: 3 }

// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy =&gt; { a: 1, b: 2, c: 3 }

const { a, ...noA } = copy; // noA =&gt; { b: 2, c: 3 }</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="arrays">Arrays</h2>
<p>  <a name="arrays--literals"></a><a name="4.1"></a></p>
<ul>
<li><p><a href="#arrays--literals">4.1</a> Use the literal syntax for array creation. eslint: <a href="https://eslint.org/docs/rules/no-array-constructor"><code>no-array-constructor</code></a></p>
<pre><code class="language-javascript">// bad
const items = new Array();

// good
const items = [];</code></pre>
<p><a name="arrays--push"></a><a name="4.2"></a></p>
</li>
<li><p><a href="#arrays--push">4.2</a> Use <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push">Array#push</a> instead of direct assignment to add items to an array.</p>
<pre><code class="language-javascript">const someStack = [];

// bad
someStack[someStack.length] = &#39;abracadabra&#39;;

// good
someStack.push(&#39;abracadabra&#39;);</code></pre>
<p><a name="es6-array-spreads"></a><a name="4.3"></a></p>
</li>
<li><p><a href="#es6-array-spreads">4.3</a> Use array spreads <code>...</code> to copy arrays.</p>
<pre><code class="language-javascript">// bad
const len = items.length;
const itemsCopy = [];
let i;

for (i = 0; i &lt; len; i += 1) {
  itemsCopy[i] = items[i];
}

// good
const itemsCopy = [...items];</code></pre>
<p><a name="arrays--from"></a>
<a name="arrays--from-iterable"></a><a name="4.4"></a></p>
</li>
<li><p><a href="#arrays--from-iterable">4.4</a> To convert an iterable object to an array, use spreads <code>...</code> instead of <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from"><code>Array.from</code></a></p>
<pre><code class="language-javascript">const foo = document.querySelectorAll(&#39;.foo&#39;);

// good
const nodes = Array.from(foo);

// best
const nodes = [...foo];</code></pre>
<p><a name="arrays--from-array-like"></a></p>
</li>
<li><p><a href="#arrays--from-array-like">4.5</a> Use <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from"><code>Array.from</code></a> for converting an array-like object to an array.</p>
<pre><code class="language-javascript">const arrLike = { 0: &#39;foo&#39;, 1: &#39;bar&#39;, 2: &#39;baz&#39;, length: 3 };

// bad
const arr = Array.prototype.slice.call(arrLike);

// good
const arr = Array.from(arrLike);</code></pre>
<p><a name="arrays--mapping"></a></p>
</li>
<li><p><a href="#arrays--mapping">4.6</a> Use <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from"><code>Array.from</code></a> instead of spread <code>...</code> for mapping over iterables, because it avoids creating an intermediate array.</p>
<pre><code class="language-javascript">// bad
const baz = [...foo].map(bar);

// good
const baz = Array.from(foo, bar);</code></pre>
<p><a name="arrays--callback-return"></a><a name="4.5"></a></p>
</li>
<li><p><a href="#arrays--callback-return">4.7</a> Use return statements in array method callbacks. It’s ok to omit the return if the function body consists of a single statement returning an expression without side effects, following <a href="#arrows--implicit-return">8.2</a>. eslint: <a href="https://eslint.org/docs/rules/array-callback-return"><code>array-callback-return</code></a></p>
<pre><code class="language-javascript">// good
[1, 2, 3].map((x) =&gt; {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) =&gt; x + 1);

// bad - no returned value means `acc` becomes undefined after the first iteration
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) =&gt; {
  const flatten = acc.concat(item);
});

// good
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) =&gt; {
  const flatten = acc.concat(item);
  return flatten;
});

// bad
inbox.filter((msg) =&gt; {
  const { subject, author } = msg;
  if (subject === &#39;Mockingbird&#39;) {
    return author === &#39;Harper Lee&#39;;
  } else {
    return false;
  }
});

// good
inbox.filter((msg) =&gt; {
  const { subject, author } = msg;
  if (subject === &#39;Mockingbird&#39;) {
    return author === &#39;Harper Lee&#39;;
  }

  return false;
});</code></pre>
<p><a name="arrays--bracket-newline"></a></p>
</li>
<li><p><a href="#arrays--bracket-newline">4.8</a> Use line breaks after opening array brackets and before closing array brackets, if an array has multiple lines</p>
<pre><code class="language-javascript">// bad
const arr = [
  [0, 1], [2, 3], [4, 5],
];

const objectInArray = [{
  id: 1,
}, {
  id: 2,
}];

const numberInArray = [
  1, 2,
];

// good
const arr = [[0, 1], [2, 3], [4, 5]];

const objectInArray = [
  {
    id: 1,
  },
  {
    id: 2,
  },
];

const numberInArray = [
  1,
  2,
];</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="destructuring">Destructuring</h2>
<p>  <a name="destructuring--object"></a><a name="5.1"></a></p>
<ul>
<li><p><a href="#destructuring--object">5.1</a> Use object destructuring when accessing and using multiple properties of an object. eslint: <a href="https://eslint.org/docs/rules/prefer-destructuring"><code>prefer-destructuring</code></a></p>
<blockquote>
<p>Why? Destructuring saves you from creating temporary references for those properties, and from repetitive access of the object. Repeating object access creates more repetitive code, requires more reading, and creates more opportunities for mistakes. Destructuring objects also provides a single site of definition of the object structure that is used in the block, rather than requiring reading the entire block to determine what is used.</p>
</blockquote>
<pre><code class="language-javascript">// bad
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;

  return `${firstName} ${lastName}`;
}

// good
function getFullName(user) {
  const { firstName, lastName } = user;
  return `${firstName} ${lastName}`;
}

// best
function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`;
}</code></pre>
<p><a name="destructuring--array"></a><a name="5.2"></a></p>
</li>
<li><p><a href="#destructuring--array">5.2</a> Use array destructuring. eslint: <a href="https://eslint.org/docs/rules/prefer-destructuring"><code>prefer-destructuring</code></a></p>
<pre><code class="language-javascript">const arr = [1, 2, 3, 4];

// bad
const first = arr[0];
const second = arr[1];

// good
const [first, second] = arr;</code></pre>
<p><a name="destructuring--object-over-array"></a><a name="5.3"></a></p>
</li>
<li><p><a href="#destructuring--object-over-array">5.3</a> Use object destructuring for multiple return values, not array destructuring.</p>
<blockquote>
<p>Why? You can add new properties over time or change the order of things without breaking call sites.</p>
</blockquote>
<pre><code class="language-javascript">// bad
function processInput(input) {
  // then a miracle occurs
  return [left, right, top, bottom];
}

// the caller needs to think about the order of return data
const [left, __, top] = processInput(input);

// good
function processInput(input) {
  // then a miracle occurs
  return { left, right, top, bottom };
}

// the caller selects only the data they need
const { left, top } = processInput(input);</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="strings">Strings</h2>
<p>  <a name="strings--quotes"></a><a name="6.1"></a></p>
<ul>
<li><p><a href="#strings--quotes">6.1</a> Use single quotes <code>&#39;&#39;</code> for strings. eslint: <a href="https://eslint.org/docs/rules/quotes"><code>quotes</code></a></p>
<pre><code class="language-javascript">// bad
const name = &quot;Capt. Janeway&quot;;

// bad - template literals should contain interpolation or newlines
const name = `Capt. Janeway`;

// good
const name = &#39;Capt. Janeway&#39;;</code></pre>
<p><a name="strings--line-length"></a><a name="6.2"></a></p>
</li>
<li><p><a href="#strings--line-length">6.2</a> Strings that cause the line to go over 100 characters should not be written across multiple lines using string concatenation.</p>
<blockquote>
<p>Why? Broken strings are painful to work with and make code less searchable.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const errorMessage = &#39;This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.&#39;;

// bad
const errorMessage = &#39;This is a super long error that was thrown because &#39; +
  &#39;of Batman. When you stop to think about how Batman had anything to do &#39; +
  &#39;with this, you would get nowhere fast.&#39;;

// good
const errorMessage = &#39;This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.&#39;;</code></pre>
<p><a name="es6-template-literals"></a><a name="6.4"></a></p>
</li>
<li><p><a href="#es6-template-literals">6.3</a> When programmatically building up strings, use template strings instead of concatenation. eslint: <a href="https://eslint.org/docs/rules/prefer-template"><code>prefer-template</code></a> <a href="https://eslint.org/docs/rules/template-curly-spacing"><code>template-curly-spacing</code></a></p>
<blockquote>
<p>Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features.</p>
</blockquote>
<pre><code class="language-javascript">// bad
function sayHi(name) {
  return &#39;How are you, &#39; + name + &#39;?&#39;;
}

// bad
function sayHi(name) {
  return [&#39;How are you, &#39;, name, &#39;?&#39;].join();
}

// bad
function sayHi(name) {
  return `How are you, ${ name }?`;
}

// good
function sayHi(name) {
  return `How are you, ${name}?`;
}</code></pre>
<p><a name="strings--eval"></a><a name="6.5"></a></p>
</li>
<li><p><a href="#strings--eval">6.4</a> Never use <code>eval()</code> on a string; it opens too many vulnerabilities. eslint: <a href="https://eslint.org/docs/rules/no-eval"><code>no-eval</code></a></p>
<p><a name="strings--escaping"></a></p>
</li>
<li><p><a href="#strings--escaping">6.5</a> Do not unnecessarily escape characters in strings. eslint: <a href="https://eslint.org/docs/rules/no-useless-escape"><code>no-useless-escape</code></a></p>
<blockquote>
<p>Why? Backslashes harm readability, thus they should only be present when necessary.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const foo = &#39;\&#39;this\&#39; \i\s \&quot;quoted\&quot;&#39;;

// good
const foo = &#39;\&#39;this\&#39; is &quot;quoted&quot;&#39;;
const foo = `my name is &#39;${name}&#39;`;</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="functions">Functions</h2>
<p>  <a name="functions--declarations"></a><a name="7.1"></a></p>
<ul>
<li><p><a href="#functions--declarations">7.1</a> Use named function expressions instead of function declarations. eslint: <a href="https://eslint.org/docs/rules/func-style"><code>func-style</code></a>, <a href="https://eslint.org/docs/latest/rules/func-names"><code>func-names</code></a></p>
<blockquote>
<p>Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to explicitly name the expression, regardless of whether or not the name is inferred from the containing variable (which is often the case in modern browsers or when using compilers such as Babel). This eliminates any assumptions made about the Error’s call stack. (<a href="https://github.com/airbnb/javascript/issues/794">Discussion</a>)</p>
</blockquote>
<pre><code class="language-javascript">// bad
function foo() {
  // ...
}

// bad
const foo = function () {
  // ...
};

// good
// lexical name distinguished from the variable-referenced invocation(s)
const short = function longUniqueMoreDescriptiveLexicalFoo() {
  // ...
};</code></pre>
<p><a name="functions--iife"></a><a name="7.2"></a></p>
</li>
<li><p><a href="#functions--iife">7.2</a> Wrap immediately invoked function expressions in parentheses. eslint: <a href="https://eslint.org/docs/rules/wrap-iife"><code>wrap-iife</code></a></p>
<blockquote>
<p>Why? An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. Note that in a world with modules everywhere, you almost never need an IIFE.</p>
</blockquote>
<pre><code class="language-javascript">// immediately-invoked function expression (IIFE)
(function () {
  console.log(&#39;Welcome to the Internet. Please follow me.&#39;);
}());</code></pre>
<p><a name="functions--in-blocks"></a><a name="7.3"></a></p>
</li>
<li><p><a href="#functions--in-blocks">7.3</a> Never declare a function in a non-function block (<code>if</code>, <code>while</code>, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. eslint: <a href="https://eslint.org/docs/rules/no-loop-func"><code>no-loop-func</code></a></p>
<p><a name="functions--note-on-blocks"></a><a name="7.4"></a></p>
</li>
<li><p><a href="#functions--note-on-blocks">7.4</a> <strong>Note:</strong> ECMA-262 defines a <code>block</code> as a list of statements. A function declaration is not a statement.</p>
<pre><code class="language-javascript">// bad
if (currentUser) {
  function test() {
    console.log(&#39;Nope.&#39;);
  }
}

// good
let test;
if (currentUser) {
  test = () =&gt; {
    console.log(&#39;Yup.&#39;);
  };
}</code></pre>
<p><a name="functions--arguments-shadow"></a><a name="7.5"></a></p>
</li>
<li><p><a href="#functions--arguments-shadow">7.5</a> Never name a parameter <code>arguments</code>. This will take precedence over the <code>arguments</code> object that is given to every function scope.</p>
<pre><code class="language-javascript">// bad
function foo(name, options, arguments) {
  // ...
}

// good
function foo(name, options, args) {
  // ...
}</code></pre>
<p><a name="es6-rest"></a><a name="7.6"></a></p>
</li>
<li><p><a href="#es6-rest">7.6</a> Never use <code>arguments</code>, opt to use rest syntax <code>...</code> instead. eslint: <a href="https://eslint.org/docs/rules/prefer-rest-params"><code>prefer-rest-params</code></a></p>
<blockquote>
<p>Why? <code>...</code> is explicit about which arguments you want pulled. Plus, rest arguments are a real Array, and not merely Array-like like <code>arguments</code>.</p>
</blockquote>
<pre><code class="language-javascript">// bad
function concatenateAll() {
  const args = Array.prototype.slice.call(arguments);
  return args.join(&#39;&#39;);
}

// good
function concatenateAll(...args) {
  return args.join(&#39;&#39;);
}</code></pre>
<p><a name="es6-default-parameters"></a><a name="7.7"></a></p>
</li>
<li><p><a href="#es6-default-parameters">7.7</a> Use default parameter syntax rather than mutating function arguments.</p>
<pre><code class="language-javascript">// really bad
function handleThings(opts) {
  // No! We shouldn’t mutate function arguments.
  // Double bad: if opts is falsy it&#39;ll be set to an object which may
  // be what you want but it can introduce subtle bugs.
  opts = opts || {};
  // ...
}

// still bad
function handleThings(opts) {
  if (opts === void 0) {
    opts = {};
  }
  // ...
}

// good
function handleThings(opts = {}) {
  // ...
}</code></pre>
<p><a name="functions--default-side-effects"></a><a name="7.8"></a></p>
</li>
<li><p><a href="#functions--default-side-effects">7.8</a> Avoid side effects with default parameters.</p>
<blockquote>
<p>Why? They are confusing to reason about.</p>
</blockquote>
<pre><code class="language-javascript">let b = 1;
// bad
function count(a = b++) {
  console.log(a);
}
count();  // 1
count();  // 2
count(3); // 3
count();  // 3</code></pre>
<p><a name="functions--defaults-last"></a><a name="7.9"></a></p>
</li>
<li><p><a href="#functions--defaults-last">7.9</a> Always put default parameters last. eslint: <a href="https://eslint.org/docs/rules/default-param-last"><code>default-param-last</code></a></p>
<pre><code class="language-javascript">// bad
function handleThings(opts = {}, name) {
  // ...
}

// good
function handleThings(name, opts = {}) {
  // ...
}</code></pre>
<p><a name="functions--constructor"></a><a name="7.10"></a></p>
</li>
<li><p><a href="#functions--constructor">7.10</a> Never use the Function constructor to create a new function. eslint: <a href="https://eslint.org/docs/rules/no-new-func"><code>no-new-func</code></a></p>
<blockquote>
<p>Why? Creating a function in this way evaluates a string similarly to <code>eval()</code>, which opens vulnerabilities.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const add = new Function(&#39;a&#39;, &#39;b&#39;, &#39;return a + b&#39;);

// still bad
const subtract = Function(&#39;a&#39;, &#39;b&#39;, &#39;return a - b&#39;);</code></pre>
<p><a name="functions--signature-spacing"></a><a name="7.11"></a></p>
</li>
<li><p><a href="#functions--signature-spacing">7.11</a> Spacing in a function signature. eslint: <a href="https://eslint.org/docs/rules/space-before-function-paren"><code>space-before-function-paren</code></a> <a href="https://eslint.org/docs/rules/space-before-blocks"><code>space-before-blocks</code></a></p>
<blockquote>
<p>Why? Consistency is good, and you shouldn’t have to add or remove a space when adding or removing a name.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const f = function(){};
const g = function (){};
const h = function() {};

// good
const x = function () {};
const y = function a() {};</code></pre>
<p><a name="functions--mutate-params"></a><a name="7.12"></a></p>
</li>
<li><p><a href="#functions--mutate-params">7.12</a> Never mutate parameters. eslint: <a href="https://eslint.org/docs/rules/no-param-reassign"><code>no-param-reassign</code></a></p>
<blockquote>
<p>Why? Manipulating objects passed in as parameters can cause unwanted variable side effects in the original caller.</p>
</blockquote>
<pre><code class="language-javascript">// bad
function f1(obj) {
  obj.key = 1;
}

// good
function f2(obj) {
  const key = Object.prototype.hasOwnProperty.call(obj, &#39;key&#39;) ? obj.key : 1;
}</code></pre>
<p><a name="functions--reassign-params"></a><a name="7.13"></a></p>
</li>
<li><p><a href="#functions--reassign-params">7.13</a> Never reassign parameters. eslint: <a href="https://eslint.org/docs/rules/no-param-reassign"><code>no-param-reassign</code></a></p>
<blockquote>
<p>Why? Reassigning parameters can lead to unexpected behavior, especially when accessing the <code>arguments</code> object. It can also cause optimization issues, especially in V8.</p>
</blockquote>
<pre><code class="language-javascript">// bad
function f1(a) {
  a = 1;
  // ...
}

function f2(a) {
  if (!a) { a = 1; }
  // ...
}

// good
function f3(a) {
  const b = a || 1;
  // ...
}

function f4(a = 1) {
  // ...
}</code></pre>
<p><a name="functions--spread-vs-apply"></a><a name="7.14"></a></p>
</li>
<li><p><a href="#functions--spread-vs-apply">7.14</a> Prefer the use of the spread syntax <code>...</code> to call variadic functions. eslint: <a href="https://eslint.org/docs/rules/prefer-spread"><code>prefer-spread</code></a></p>
<blockquote>
<p>Why? It’s cleaner, you don’t need to supply a context, and you can not easily compose <code>new</code> with <code>apply</code>.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);

// good
const x = [1, 2, 3, 4, 5];
console.log(...x);

// bad
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));

// good
new Date(...[2016, 8, 5]);</code></pre>
<p><a name="functions--signature-invocation-indentation"></a></p>
</li>
<li><p><a href="#functions--signature-invocation-indentation">7.15</a> Functions with multiline signatures, or invocations, should be indented just like every other multiline list in this guide: with each item on a line by itself, with a trailing comma on the last item. eslint: <a href="https://eslint.org/docs/rules/function-paren-newline"><code>function-paren-newline</code></a></p>
<pre><code class="language-javascript">// bad
function foo(bar,
             baz,
             quux) {
  // ...
}

// good
function foo(
  bar,
  baz,
  quux,
) {
  // ...
}

// bad
console.log(foo,
  bar,
  baz);

// good
console.log(
  foo,
  bar,
  baz,
);</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="arrow-functions">Arrow Functions</h2>
<p>  <a name="arrows--use-them"></a><a name="8.1"></a></p>
<ul>
<li><p><a href="#arrows--use-them">8.1</a> When you must use an anonymous function (as when passing an inline callback), use arrow function notation. eslint: <a href="https://eslint.org/docs/rules/prefer-arrow-callback"><code>prefer-arrow-callback</code></a>, <a href="https://eslint.org/docs/rules/arrow-spacing"><code>arrow-spacing</code></a></p>
<blockquote>
<p>Why? It creates a version of the function that executes in the context of <code>this</code>, which is usually what you want, and is a more concise syntax.</p>
</blockquote>
<blockquote>
<p>Why not? If you have a fairly complicated function, you might move that logic out into its own named function expression.</p>
</blockquote>
<pre><code class="language-javascript">// bad
[1, 2, 3].map(function (x) {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) =&gt; {
  const y = x + 1;
  return x * y;
});</code></pre>
<p><a name="arrows--implicit-return"></a><a name="8.2"></a></p>
</li>
<li><p><a href="#arrows--implicit-return">8.2</a> If the function body consists of a single statement returning an <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions">expression</a> without side effects, omit the braces and use the implicit return. Otherwise, keep the braces and use a <code>return</code> statement. eslint: <a href="https://eslint.org/docs/rules/arrow-parens"><code>arrow-parens</code></a>, <a href="https://eslint.org/docs/rules/arrow-body-style"><code>arrow-body-style</code></a></p>
<blockquote>
<p>Why? Syntactic sugar. It reads well when multiple functions are chained together.</p>
</blockquote>
<pre><code class="language-javascript">// bad
[1, 2, 3].map((number) =&gt; {
  const nextNumber = number + 1;
  `A string containing the ${nextNumber}.`;
});

// good
[1, 2, 3].map((number) =&gt; `A string containing the ${number + 1}.`);

// good
[1, 2, 3].map((number) =&gt; {
  const nextNumber = number + 1;
  return `A string containing the ${nextNumber}.`;
});

// good
[1, 2, 3].map((number, index) =&gt; ({
  [index]: number,
}));

// No implicit return with side effects
function foo(callback) {
  const val = callback();
  if (val === true) {
    // Do something if callback returns true
  }
}

let bool = false;

// bad
foo(() =&gt; bool = true);

// good
foo(() =&gt; {
  bool = true;
});</code></pre>
<p><a name="arrows--paren-wrap"></a><a name="8.3"></a></p>
</li>
<li><p><a href="#arrows--paren-wrap">8.3</a> In case the expression spans over multiple lines, wrap it in parentheses for better readability.</p>
<blockquote>
<p>Why? It shows clearly where the function starts and ends.</p>
</blockquote>
<pre><code class="language-javascript">// bad
[&#39;get&#39;, &#39;post&#39;, &#39;put&#39;].map((httpMethod) =&gt; Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod,
  )
);

// good
[&#39;get&#39;, &#39;post&#39;, &#39;put&#39;].map((httpMethod) =&gt; (
  Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod,
  )
));</code></pre>
<p><a name="arrows--one-arg-parens"></a><a name="8.4"></a></p>
</li>
<li><p><a href="#arrows--one-arg-parens">8.4</a> Always include parentheses around arguments for clarity and consistency. eslint: <a href="https://eslint.org/docs/rules/arrow-parens"><code>arrow-parens</code></a></p>
<blockquote>
<p>Why? Minimizes diff churn when adding or removing arguments.</p>
</blockquote>
<pre><code class="language-javascript">// bad
[1, 2, 3].map(x =&gt; x * x);

// good
[1, 2, 3].map((x) =&gt; x * x);

// bad
[1, 2, 3].map(number =&gt; (
  `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));

// good
[1, 2, 3].map((number) =&gt; (
  `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));

// bad
[1, 2, 3].map(x =&gt; {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) =&gt; {
  const y = x + 1;
  return x * y;
});</code></pre>
<p><a name="arrows--confusing"></a><a name="8.5"></a></p>
</li>
<li><p><a href="#arrows--confusing">8.5</a> Avoid confusing arrow function syntax (<code>=&gt;</code>) with comparison operators (<code>&lt;=</code>, <code>&gt;=</code>). eslint: <a href="https://eslint.org/docs/rules/no-confusing-arrow"><code>no-confusing-arrow</code></a></p>
<pre><code class="language-javascript">// bad
const itemHeight = (item) =&gt; item.height &lt;= 256 ? item.largeSize : item.smallSize;

// bad
const itemHeight = (item) =&gt; item.height &gt;= 256 ? item.largeSize : item.smallSize;

// good
const itemHeight = (item) =&gt; (item.height &lt;= 256 ? item.largeSize : item.smallSize);

// good
const itemHeight = (item) =&gt; {
  const { height, largeSize, smallSize } = item;
  return height &lt;= 256 ? largeSize : smallSize;
};</code></pre>
<p><a name="whitespace--implicit-arrow-linebreak"></a></p>
</li>
<li><p><a href="#whitespace--implicit-arrow-linebreak">8.6</a> Enforce the location of arrow function bodies with implicit returns. eslint: <a href="https://eslint.org/docs/rules/implicit-arrow-linebreak"><code>implicit-arrow-linebreak</code></a></p>
<pre><code class="language-javascript">// bad
(foo) =&gt;
  bar;

(foo) =&gt;
  (bar);

// good
(foo) =&gt; bar;
(foo) =&gt; (bar);
(foo) =&gt; (
   bar
)</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="classes--constructors">Classes &amp; Constructors</h2>
<p>  <a name="constructors--use-class"></a><a name="9.1"></a></p>
<ul>
<li><p><a href="#constructors--use-class">9.1</a> Always use <code>class</code>. Avoid manipulating <code>prototype</code> directly.</p>
<blockquote>
<p>Why? <code>class</code> syntax is more concise and easier to reason about.</p>
</blockquote>
<pre><code class="language-javascript">// bad
function Queue(contents = []) {
  this.queue = [...contents];
}
Queue.prototype.pop = function () {
  const value = this.queue[0];
  this.queue.splice(0, 1);
  return value;
};

// good
class Queue {
  constructor(contents = []) {
    this.queue = [...contents];
  }
  pop() {
    const value = this.queue[0];
    this.queue.splice(0, 1);
    return value;
  }
}</code></pre>
<p><a name="constructors--extends"></a><a name="9.2"></a></p>
</li>
<li><p><a href="#constructors--extends">9.2</a> Use <code>extends</code> for inheritance.</p>
<blockquote>
<p>Why? It is a built-in way to inherit prototype functionality without breaking <code>instanceof</code>.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const inherits = require(&#39;inherits&#39;);
function PeekableQueue(contents) {
  Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
  return this.queue[0];
};

// good
class PeekableQueue extends Queue {
  peek() {
    return this.queue[0];
  }
}</code></pre>
<p><a name="constructors--chaining"></a><a name="9.3"></a></p>
</li>
<li><p><a href="#constructors--chaining">9.3</a> Methods can return <code>this</code> to help with method chaining.</p>
<pre><code class="language-javascript">// bad
Jedi.prototype.jump = function () {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function (height) {
  this.height = height;
};

const luke = new Jedi();
luke.jump(); // =&gt; true
luke.setHeight(20); // =&gt; undefined

// good
class Jedi {
  jump() {
    this.jumping = true;
    return this;
  }

  setHeight(height) {
    this.height = height;
    return this;
  }
}

const luke = new Jedi();

luke.jump()
  .setHeight(20);</code></pre>
<p><a name="constructors--tostring"></a><a name="9.4"></a></p>
</li>
<li><p><a href="#constructors--tostring">9.4</a> It’s okay to write a custom <code>toString()</code> method, just make sure it works successfully and causes no side effects.</p>
<pre><code class="language-javascript">class Jedi {
  constructor(options = {}) {
    this.name = options.name || &#39;no name&#39;;
  }

  getName() {
    return this.name;
  }

  toString() {
    return `Jedi - ${this.getName()}`;
  }
}</code></pre>
<p><a name="constructors--no-useless"></a><a name="9.5"></a></p>
</li>
<li><p><a href="#constructors--no-useless">9.5</a> Classes have a default constructor if one is not specified. An empty constructor function or one that just delegates to a parent class is unnecessary. eslint: <a href="https://eslint.org/docs/rules/no-useless-constructor"><code>no-useless-constructor</code></a></p>
<pre><code class="language-javascript">// bad
class Jedi {
  constructor() {}

  getName() {
    return this.name;
  }
}

// bad
class Rey extends Jedi {
  constructor(...args) {
    super(...args);
  }
}

// good
class Rey extends Jedi {
  constructor(...args) {
    super(...args);
    this.name = &#39;Rey&#39;;
  }
}</code></pre>
<p><a name="classes--no-duplicate-members"></a></p>
</li>
<li><p><a href="#classes--no-duplicate-members">9.6</a> Avoid duplicate class members. eslint: <a href="https://eslint.org/docs/rules/no-dupe-class-members"><code>no-dupe-class-members</code></a></p>
<blockquote>
<p>Why? Duplicate class member declarations will silently prefer the last one - having duplicates is almost certainly a bug.</p>
</blockquote>
<pre><code class="language-javascript">// bad
class Foo {
  bar() { return 1; }
  bar() { return 2; }
}

// good
class Foo {
  bar() { return 1; }
}

// good
class Foo {
  bar() { return 2; }
}</code></pre>
<p><a name="classes--methods-use-this"></a></p>
</li>
<li><p><a href="#classes--methods-use-this">9.7</a> Class methods should use <code>this</code> or be made into a static method unless an external library or framework requires using specific non-static methods. Being an instance method should indicate that it behaves differently based on properties of the receiver. eslint: <a href="https://eslint.org/docs/rules/class-methods-use-this"><code>class-methods-use-this</code></a></p>
<pre><code class="language-javascript">// bad
class Foo {
  bar() {
    console.log(&#39;bar&#39;);
  }
}

// good - this is used
class Foo {
  bar() {
    console.log(this.bar);
  }
}

// good - constructor is exempt
class Foo {
  constructor() {
    // ...
  }
}

// good - static methods aren&#39;t expected to use this
class Foo {
  static bar() {
    console.log(&#39;bar&#39;);
  }
}</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="modules">Modules</h2>
<p>  <a name="modules--use-them"></a><a name="10.1"></a></p>
<ul>
<li><p><a href="#modules--use-them">10.1</a> Always use modules (<code>import</code>/<code>export</code>) over a non-standard module system. You can always transpile to your preferred module system.</p>
<blockquote>
<p>Why? Modules are the future, let’s start using the future now.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const AirbnbStyleGuide = require(&#39;./AirbnbStyleGuide&#39;);
module.exports = AirbnbStyleGuide.es6;

// ok
import AirbnbStyleGuide from &#39;./AirbnbStyleGuide&#39;;
export default AirbnbStyleGuide.es6;

// best
import { es6 } from &#39;./AirbnbStyleGuide&#39;;
export default es6;</code></pre>
<p><a name="modules--no-wildcard"></a><a name="10.2"></a></p>
</li>
<li><p><a href="#modules--no-wildcard">10.2</a> Do not use wildcard imports.</p>
<blockquote>
<p>Why? This makes sure you have a single default export.</p>
</blockquote>
<pre><code class="language-javascript">// bad
import * as AirbnbStyleGuide from &#39;./AirbnbStyleGuide&#39;;

// good
import AirbnbStyleGuide from &#39;./AirbnbStyleGuide&#39;;</code></pre>
<p><a name="modules--no-export-from-import"></a><a name="10.3"></a></p>
</li>
<li><p><a href="#modules--no-export-from-import">10.3</a> And do not export directly from an import.</p>
<blockquote>
<p>Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent.</p>
</blockquote>
<pre><code class="language-javascript">// bad
// filename es6.js
export { es6 as default } from &#39;./AirbnbStyleGuide&#39;;

// good
// filename es6.js
import { es6 } from &#39;./AirbnbStyleGuide&#39;;
export default es6;</code></pre>
<p><a name="modules--no-duplicate-imports"></a></p>
</li>
<li><p><a href="#modules--no-duplicate-imports">10.4</a> Only import from a path in one place.
eslint: <a href="https://eslint.org/docs/rules/no-duplicate-imports"><code>no-duplicate-imports</code></a></p>
<blockquote>
<p>Why? Having multiple lines that import from the same path can make code harder to maintain.</p>
</blockquote>
<pre><code class="language-javascript">// bad
import foo from &#39;foo&#39;;
// … some other imports … //
import { named1, named2 } from &#39;foo&#39;;

// good
import foo, { named1, named2 } from &#39;foo&#39;;

// good
import foo, {
  named1,
  named2,
} from &#39;foo&#39;;</code></pre>
<p><a name="modules--no-mutable-exports"></a></p>
</li>
<li><p><a href="#modules--no-mutable-exports">10.5</a> Do not export mutable bindings.
eslint: <a href="https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md"><code>import/no-mutable-exports</code></a></p>
<blockquote>
<p>Why? Mutation should be avoided in general, but in particular when exporting mutable bindings. While this technique may be needed for some special cases, in general, only constant references should be exported.</p>
</blockquote>
<pre><code class="language-javascript">// bad
let foo = 3;
export { foo };

// good
const foo = 3;
export { foo };</code></pre>
<p><a name="modules--prefer-default-export"></a></p>
</li>
<li><p><a href="#modules--prefer-default-export">10.6</a> In modules with a single export, prefer default export over named export.
eslint: <a href="https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md"><code>import/prefer-default-export</code></a></p>
<blockquote>
<p>Why? To encourage more files that only ever export one thing, which is better for readability and maintainability.</p>
</blockquote>
<pre><code class="language-javascript">// bad
export function foo() {}

// good
export default function foo() {}</code></pre>
<p><a name="modules--imports-first"></a></p>
</li>
<li><p><a href="#modules--imports-first">10.7</a> Put all <code>import</code>s above non-import statements.
eslint: <a href="https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/first.md"><code>import/first</code></a></p>
<blockquote>
<p>Why? Since <code>import</code>s are hoisted, keeping them all at the top prevents surprising behavior.</p>
</blockquote>
<pre><code class="language-javascript">// bad
import foo from &#39;foo&#39;;
foo.init();

import bar from &#39;bar&#39;;

// good
import foo from &#39;foo&#39;;
import bar from &#39;bar&#39;;

foo.init();</code></pre>
<p><a name="modules--multiline-imports-over-newlines"></a></p>
</li>
<li><p><a href="#modules--multiline-imports-over-newlines">10.8</a> Multiline imports should be indented just like multiline array and object literals.
eslint: <a href="https://eslint.org/docs/rules/object-curly-newline"><code>object-curly-newline</code></a></p>
<blockquote>
<p>Why? The curly braces follow the same indentation rules as every other curly brace block in the style guide, as do the trailing commas.</p>
</blockquote>
<pre><code class="language-javascript">// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from &#39;path&#39;;

// good
import {
  longNameA,
  longNameB,
  longNameC,
  longNameD,
  longNameE,
} from &#39;path&#39;;</code></pre>
<p><a name="modules--no-webpack-loader-syntax"></a></p>
</li>
<li><p><a href="#modules--no-webpack-loader-syntax">10.9</a> Disallow Webpack loader syntax in module import statements.
eslint: <a href="https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md"><code>import/no-webpack-loader-syntax</code></a></p>
<blockquote>
<p>Why? Since using Webpack syntax in the imports couples the code to a module bundler. Prefer using the loader syntax in <code>webpack.config.js</code>.</p>
</blockquote>
<pre><code class="language-javascript">// bad
import fooSass from &#39;css!sass!foo.scss&#39;;
import barCss from &#39;style!css!bar.css&#39;;

// good
import fooSass from &#39;foo.scss&#39;;
import barCss from &#39;bar.css&#39;;</code></pre>
<p><a name="modules--import-extensions"></a></p>
</li>
<li><p><a href="#modules--import-extensions">10.10</a> Do not include JavaScript filename extensions
eslint: <a href="https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/extensions.md"><code>import/extensions</code></a></p>
<blockquote>
<p>Why? Including extensions inhibits refactoring, and inappropriately hardcodes implementation details of the module you&#39;re importing in every consumer.</p>
</blockquote>
<pre><code class="language-javascript">// bad
import foo from &#39;./foo.js&#39;;
import bar from &#39;./bar.jsx&#39;;
import baz from &#39;./baz/index.jsx&#39;;

// good
import foo from &#39;./foo&#39;;
import bar from &#39;./bar&#39;;
import baz from &#39;./baz&#39;;</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="iterators-and-generators">Iterators and Generators</h2>
<p>  <a name="iterators--nope"></a><a name="11.1"></a></p>
<ul>
<li><p><a href="#iterators--nope">11.1</a> Don’t use iterators. Prefer JavaScript’s higher-order functions instead of loops like <code>for-in</code> or <code>for-of</code>. eslint: <a href="https://eslint.org/docs/rules/no-iterator"><code>no-iterator</code></a> <a href="https://eslint.org/docs/rules/no-restricted-syntax"><code>no-restricted-syntax</code></a></p>
<blockquote>
<p>Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.</p>
</blockquote>
<blockquote>
<p>Use <code>map()</code> / <code>every()</code> / <code>filter()</code> / <code>find()</code> / <code>findIndex()</code> / <code>reduce()</code> / <code>some()</code> / ... to iterate over arrays, and <code>Object.keys()</code> / <code>Object.values()</code> / <code>Object.entries()</code> to produce arrays so you can iterate over objects.</p>
</blockquote>
<pre><code class="language-javascript">const numbers = [1, 2, 3, 4, 5];

// bad
let sum = 0;
for (let num of numbers) {
  sum += num;
}
sum === 15;

// good
let sum = 0;
numbers.forEach((num) =&gt; {
  sum += num;
});
sum === 15;

// best (use the functional force)
const sum = numbers.reduce((total, num) =&gt; total + num, 0);
sum === 15;

// bad
const increasedByOne = [];
for (let i = 0; i &lt; numbers.length; i++) {
  increasedByOne.push(numbers[i] + 1);
}

// good
const increasedByOne = [];
numbers.forEach((num) =&gt; {
  increasedByOne.push(num + 1);
});

// best (keeping it functional)
const increasedByOne = numbers.map((num) =&gt; num + 1);</code></pre>
<p><a name="generators--nope"></a><a name="11.2"></a></p>
</li>
<li><p><a href="#generators--nope">11.2</a> Don’t use generators for now.</p>
<blockquote>
<p>Why? They don’t transpile well to ES5.</p>
</blockquote>
<p><a name="generators--spacing"></a></p>
</li>
<li><p><a href="#generators--spacing">11.3</a> If you must use generators, or if you disregard <a href="#generators--nope">our advice</a>, make sure their function signature is spaced properly. eslint: <a href="https://eslint.org/docs/rules/generator-star-spacing"><code>generator-star-spacing</code></a></p>
<blockquote>
<p>Why? <code>function</code> and <code>*</code> are part of the same conceptual keyword - <code>*</code> is not a modifier for <code>function</code>, <code>function*</code> is a unique construct, different from <code>function</code>.</p>
</blockquote>
<pre><code class="language-javascript">// bad
function * foo() {
  // ...
}

// bad
const bar = function * () {
  // ...
};

// bad
const baz = function *() {
  // ...
};

// bad
const quux = function*() {
  // ...
};

// bad
function*foo() {
  // ...
}

// bad
function *foo() {
  // ...
}

// very bad
function
*
foo() {
  // ...
}

// very bad
const wat = function
*
() {
  // ...
};

// good
function* foo() {
  // ...
}

// good
const foo = function* () {
  // ...
};</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="properties">Properties</h2>
<p>  <a name="properties--dot"></a><a name="12.1"></a></p>
<ul>
<li><p><a href="#properties--dot">12.1</a> Use dot notation when accessing properties. eslint: <a href="https://eslint.org/docs/rules/dot-notation"><code>dot-notation</code></a></p>
<pre><code class="language-javascript">const luke = {
  jedi: true,
  age: 28,
};

// bad
const isJedi = luke[&#39;jedi&#39;];

// good
const isJedi = luke.jedi;</code></pre>
<p><a name="properties--bracket"></a><a name="12.2"></a></p>
</li>
<li><p><a href="#properties--bracket">12.2</a> Use bracket notation <code>[]</code> when accessing properties with a variable.</p>
<pre><code class="language-javascript">const luke = {
  jedi: true,
  age: 28,
};

function getProp(prop) {
  return luke[prop];
}

const isJedi = getProp(&#39;jedi&#39;);</code></pre>
<p><a name="es2016-properties--exponentiation-operator"></a></p>
</li>
<li><p><a href="#es2016-properties--exponentiation-operator">12.3</a> Use exponentiation operator <code>**</code> when calculating exponentiations. eslint: <a href="https://eslint.org/docs/rules/prefer-exponentiation-operator"><code>prefer-exponentiation-operator</code></a>.</p>
<pre><code class="language-javascript">// bad
const binary = Math.pow(2, 10);

// good
const binary = 2 ** 10;</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="variables">Variables</h2>
<p>  <a name="variables--const"></a><a name="13.1"></a></p>
<ul>
<li><p><a href="#variables--const">13.1</a> Always use <code>const</code> or <code>let</code> to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. eslint: <a href="https://eslint.org/docs/rules/no-undef"><code>no-undef</code></a> <a href="https://eslint.org/docs/rules/prefer-const"><code>prefer-const</code></a></p>
<pre><code class="language-javascript">// bad
superPower = new SuperPower();

// good
const superPower = new SuperPower();</code></pre>
<p><a name="variables--one-const"></a><a name="13.2"></a></p>
</li>
<li><p><a href="#variables--one-const">13.2</a> Use one <code>const</code> or <code>let</code> declaration per variable or assignment. eslint: <a href="https://eslint.org/docs/rules/one-var"><code>one-var</code></a></p>
<blockquote>
<p>Why? It’s easier to add new variable declarations this way, and you never have to worry about swapping out a <code>;</code> for a <code>,</code> or introducing punctuation-only diffs. You can also step through each declaration with the debugger, instead of jumping through all of them at once.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const items = getItems(),
    goSportsTeam = true,
    dragonball = &#39;z&#39;;

// bad
// (compare to above, and try to spot the mistake)
const items = getItems(),
    goSportsTeam = true;
    dragonball = &#39;z&#39;;

// good
const items = getItems();
const goSportsTeam = true;
const dragonball = &#39;z&#39;;</code></pre>
<p><a name="variables--const-let-group"></a><a name="13.3"></a></p>
</li>
<li><p><a href="#variables--const-let-group">13.3</a> Group all your <code>const</code>s and then group all your <code>let</code>s.</p>
<blockquote>
<p>Why? This is helpful when later on you might need to assign a variable depending on one of the previously assigned variables.</p>
</blockquote>
<pre><code class="language-javascript">// bad
let i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;

// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;</code></pre>
<p><a name="variables--define-where-used"></a><a name="13.4"></a></p>
</li>
<li><p><a href="#variables--define-where-used">13.4</a> Assign variables where you need them, but place them in a reasonable place.</p>
<blockquote>
<p>Why? <code>let</code> and <code>const</code> are block scoped and not function scoped.</p>
</blockquote>
<pre><code class="language-javascript">// bad - unnecessary function call
function checkName(hasName) {
  const name = getName();

  if (hasName === &#39;test&#39;) {
    return false;
  }

  if (name === &#39;test&#39;) {
    this.setName(&#39;&#39;);
    return false;
  }

  return name;
}

// good
function checkName(hasName) {
  if (hasName === &#39;test&#39;) {
    return false;
  }

  const name = getName();

  if (name === &#39;test&#39;) {
    this.setName(&#39;&#39;);
    return false;
  }

  return name;
}</code></pre>
<p><a name="variables--no-chain-assignment"></a><a name="13.5"></a></p>
</li>
<li><p><a href="#variables--no-chain-assignment">13.5</a> Don’t chain variable assignments. eslint: <a href="https://eslint.org/docs/rules/no-multi-assign"><code>no-multi-assign</code></a></p>
<blockquote>
<p>Why? Chaining variable assignments creates implicit global variables.</p>
</blockquote>
<pre><code class="language-javascript">// bad
(function example() {
  // JavaScript interprets this as
  // let a = ( b = ( c = 1 ) );
  // The let keyword only applies to variable a; variables b and c become
  // global variables.
  let a = b = c = 1;
}());

console.log(a); // throws ReferenceError
console.log(b); // 1
console.log(c); // 1

// good
(function example() {
  let a = 1;
  let b = a;
  let c = a;
}());

console.log(a); // throws ReferenceError
console.log(b); // throws ReferenceError
console.log(c); // throws ReferenceError

// the same applies for `const`</code></pre>
<p><a name="variables--unary-increment-decrement"></a><a name="13.6"></a></p>
</li>
<li><p><a href="#variables--unary-increment-decrement">13.6</a> Avoid using unary increments and decrements (<code>++</code>, <code>--</code>). eslint <a href="https://eslint.org/docs/rules/no-plusplus"><code>no-plusplus</code></a></p>
<blockquote>
<p>Why? Per the eslint documentation, unary increment and decrement statements are subject to automatic semicolon insertion and can cause silent errors with incrementing or decrementing values within an application. It is also more expressive to mutate your values with statements like <code>num += 1</code> instead of <code>num++</code> or <code>num ++</code>. Disallowing unary increment and decrement statements also prevents you from pre-incrementing/pre-decrementing values unintentionally which can also cause unexpected behavior in your programs.</p>
</blockquote>
<pre><code class="language-javascript">// bad

const array = [1, 2, 3];
let num = 1;
num++;
--num;

let sum = 0;
let truthyCount = 0;
for (let i = 0; i &lt; array.length; i++) {
  let value = array[i];
  sum += value;
  if (value) {
    truthyCount++;
  }
}

// good

const array = [1, 2, 3];
let num = 1;
num += 1;
num -= 1;

const sum = array.reduce((a, b) =&gt; a + b, 0);
const truthyCount = array.filter(Boolean).length;</code></pre>
</li>
</ul>
<p><a name="variables--linebreak"></a></p>
<ul>
<li><p><a href="#variables--linebreak">13.7</a> Avoid linebreaks before or after <code>=</code> in an assignment. If your assignment violates <a href="https://eslint.org/docs/rules/max-len"><code>max-len</code></a>, surround the value in parens. eslint <a href="https://eslint.org/docs/rules/operator-linebreak"><code>operator-linebreak</code></a>.</p>
<blockquote>
<p>Why? Linebreaks surrounding <code>=</code> can obfuscate the value of an assignment.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const foo =
  superLongLongLongLongLongLongLongLongFunctionName();

// bad
const foo
  = &#39;superLongLongLongLongLongLongLongLongString&#39;;

// good
const foo = (
  superLongLongLongLongLongLongLongLongFunctionName()
);

// good
const foo = &#39;superLongLongLongLongLongLongLongLongString&#39;;</code></pre>
</li>
</ul>
<p><a name="variables--no-unused-vars"></a></p>
<ul>
<li><p><a href="#variables--no-unused-vars">13.8</a> Disallow unused variables. eslint: <a href="https://eslint.org/docs/rules/no-unused-vars"><code>no-unused-vars</code></a></p>
<blockquote>
<p>Why? Variables that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring. Such variables take up space in the code and can lead to confusion by readers.</p>
</blockquote>
<pre><code class="language-javascript">// bad

const some_unused_var = 42;

// Write-only variables are not considered as used.
let y = 10;
y = 5;

// A read for a modification of itself is not considered as used.
let z = 0;
z = z + 1;

// Unused function arguments.
function getX(x, y) {
    return x;
}

// good

function getXPlusY(x, y) {
  return x + y;
}

const x = 1;
const y = a + 2;

alert(getXPlusY(x, y));

// &#39;type&#39; is ignored even if unused because it has a rest property sibling.
// This is a form of extracting an object that omits the specified keys.
const { type, ...coords } = data;
// &#39;coords&#39; is now the &#39;data&#39; object without its &#39;type&#39; property.</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="hoisting">Hoisting</h2>
<p>  <a name="hoisting--about"></a><a name="14.1"></a></p>
<ul>
<li><p><a href="#hoisting--about">14.1</a> <code>var</code> declarations get hoisted to the top of their closest enclosing function scope, their assignment does not. <code>const</code> and <code>let</code> declarations are blessed with a new concept called <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#temporal_dead_zone_tdz">Temporal Dead Zones (TDZ)</a>. It’s important to know why <a href="https://web.archive.org/web/20200121061528/http://es-discourse.com/t/why-typeof-is-no-longer-safe/15">typeof is no longer safe</a>.</p>
<pre><code class="language-javascript">// we know this wouldn’t work (assuming there
// is no notDefined global variable)
function example() {
  console.log(notDefined); // =&gt; throws a ReferenceError
}

// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
  console.log(declaredButNotAssigned); // =&gt; undefined
  var declaredButNotAssigned = true;
}

// the interpreter is hoisting the variable
// declaration to the top of the scope,
// which means our example could be rewritten as:
function example() {
  let declaredButNotAssigned;
  console.log(declaredButNotAssigned); // =&gt; undefined
  declaredButNotAssigned = true;
}

// using const and let
function example() {
  console.log(declaredButNotAssigned); // =&gt; throws a ReferenceError
  console.log(typeof declaredButNotAssigned); // =&gt; throws a ReferenceError
  const declaredButNotAssigned = true;
}</code></pre>
<p><a name="hoisting--anon-expressions"></a><a name="14.2"></a></p>
</li>
<li><p><a href="#hoisting--anon-expressions">14.2</a> Anonymous function expressions hoist their variable name, but not the function assignment.</p>
<pre><code class="language-javascript">function example() {
  console.log(anonymous); // =&gt; undefined

  anonymous(); // =&gt; TypeError anonymous is not a function

  var anonymous = function () {
    console.log(&#39;anonymous function expression&#39;);
  };
}</code></pre>
<p><a name="hoisting--named-expresions"></a><a name="hoisting--named-expressions"></a><a name="14.3"></a></p>
</li>
<li><p><a href="#hoisting--named-expressions">14.3</a> Named function expressions hoist the variable name, not the function name or the function body.</p>
<pre><code class="language-javascript">function example() {
  console.log(named); // =&gt; undefined

  named(); // =&gt; TypeError named is not a function

  superPower(); // =&gt; ReferenceError superPower is not defined

  var named = function superPower() {
    console.log(&#39;Flying&#39;);
  };
}

// the same is true when the function name
// is the same as the variable name.
function example() {
  console.log(named); // =&gt; undefined

  named(); // =&gt; TypeError named is not a function

  var named = function named() {
    console.log(&#39;named&#39;);
  };
}</code></pre>
<p><a name="hoisting--declarations"></a><a name="14.4"></a></p>
</li>
<li><p><a href="#hoisting--declarations">14.4</a> Function declarations hoist their name and the function body.</p>
<pre><code class="language-javascript">function example() {
  superPower(); // =&gt; Flying

  function superPower() {
    console.log(&#39;Flying&#39;);
  }
}</code></pre>
<p><a name="no-use-before-define"></a></p>
</li>
<li><p><a href="#no-use-before-define">14.5</a> Variables, classes, and functions should be defined before they can be used. eslint: <a href="https://eslint.org/docs/latest/rules/no-use-before-define"><code>no-use-before-define</code></a></p>
<blockquote>
<p>Why? When variables, classes, or functions are declared after being used, it can harm readability since a reader won&#39;t know what a thing that&#39;s referenced is. It&#39;s much clearer for a reader to first encounter the source of a thing (whether imported from another module, or defined in the file) before encountering a use of the thing.</p>
</blockquote>
<pre><code class="language-javascript">// bad

// Variable a is being used before it is being defined.
console.log(a); // this will be undefined, since while the declaration is hoisted, the initialization is not
var a = 10;

// Function fun is being called before being defined.
fun();
function fun() {}

// Class A is being used before being defined.
new A(); // ReferenceError: Cannot access &#39;A&#39; before initialization
class A {
}

// `let` and `const` are hoisted, but they don&#39;t have a default initialization.
// The variables &#39;a&#39; and &#39;b&#39; are in a Temporal Dead Zone where JavaScript
// knows they exist (declaration is hoisted) but they are not accessible
// (as they are not yet initialized).

console.log(a); // ReferenceError: Cannot access &#39;a&#39; before initialization
console.log(b); // ReferenceError: Cannot access &#39;b&#39; before initialization
let a = 10;
const b = 5;

</code></pre>
</li>
</ul>
<pre><code>// good

var a = 10;
console.log(a); // 10

function fun() {}
fun();

class A {
}
new A();

let a = 10;
const b = 5;
console.log(a); // 10
console.log(b); // 5
```</code></pre><ul>
<li>For more information refer to <a href="https://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/">JavaScript Scoping &amp; Hoisting</a> by <a href="https://www.adequatelygood.com/">Ben Cherry</a>.</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="comparison-operators--equality">Comparison Operators &amp; Equality</h2>
<p>  <a name="comparison--eqeqeq"></a><a name="15.1"></a></p>
<ul>
<li><p><a href="#comparison--eqeqeq">15.1</a> Use <code>===</code> and <code>!==</code> over <code>==</code> and <code>!=</code>. eslint: <a href="https://eslint.org/docs/rules/eqeqeq"><code>eqeqeq</code></a></p>
<p><a name="comparison--if"></a><a name="15.2"></a></p>
</li>
<li><p><a href="#comparison--if">15.2</a> Conditional statements such as the <code>if</code> statement evaluate their expression using coercion with the <code>ToBoolean</code> abstract method and always follow these simple rules:</p>
<ul>
<li><strong>Objects</strong> evaluate to <strong>true</strong></li>
<li><strong>Undefined</strong> evaluates to <strong>false</strong></li>
<li><strong>Null</strong> evaluates to <strong>false</strong></li>
<li><strong>Booleans</strong> evaluate to <strong>the value of the boolean</strong></li>
<li><strong>Numbers</strong> evaluate to <strong>false</strong> if <strong>+0, -0, or NaN</strong>, otherwise <strong>true</strong></li>
<li><strong>Strings</strong> evaluate to <strong>false</strong> if an empty string <code>&#39;&#39;</code>, otherwise <strong>true</strong></li>
</ul>
<pre><code class="language-javascript">if ([0] &amp;&amp; []) {
  // true
  // an array (even an empty one) is an object, objects will evaluate to true
}</code></pre>
<p><a name="comparison--shortcuts"></a><a name="15.3"></a></p>
</li>
<li><p><a href="#comparison--shortcuts">15.3</a> Use shortcuts for booleans, but explicit comparisons for strings and numbers.</p>
<pre><code class="language-javascript">// bad
if (isValid === true) {
  // ...
}

// good
if (isValid) {
  // ...
}

// bad
if (name) {
  // ...
}

// good
if (name !== &#39;&#39;) {
  // ...
}

// bad
if (collection.length) {
  // ...
}

// good
if (collection.length &gt; 0) {
  // ...
}</code></pre>
<p><a name="comparison--moreinfo"></a><a name="15.4"></a></p>
</li>
<li><p><a href="#comparison--moreinfo">15.4</a> For more information see <a href="https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108">Truth, Equality, and JavaScript</a> by Angus Croll.</p>
<p><a name="comparison--switch-blocks"></a><a name="15.5"></a></p>
</li>
<li><p><a href="#comparison--switch-blocks">15.5</a> Use braces to create blocks in <code>case</code> and <code>default</code> clauses that contain lexical declarations (e.g. <code>let</code>, <code>const</code>, <code>function</code>, and <code>class</code>). eslint: <a href="https://eslint.org/docs/rules/no-case-declarations"><code>no-case-declarations</code></a></p>
<blockquote>
<p>Why? Lexical declarations are visible in the entire <code>switch</code> block but only get initialized when assigned, which only happens when its <code>case</code> is reached. This causes problems when multiple <code>case</code> clauses attempt to define the same thing.</p>
</blockquote>
<pre><code class="language-javascript">// bad
switch (foo) {
  case 1:
    let x = 1;
    break;
  case 2:
    const y = 2;
    break;
  case 3:
    function f() {
      // ...
    }
    break;
  default:
    class C {}
}

// good
switch (foo) {
  case 1: {
    let x = 1;
    break;
  }
  case 2: {
    const y = 2;
    break;
  }
  case 3: {
    function f() {
      // ...
    }
    break;
  }
  case 4:
    bar();
    break;
  default: {
    class C {}
  }
}</code></pre>
<p><a name="comparison--nested-ternaries"></a><a name="15.6"></a></p>
</li>
<li><p><a href="#comparison--nested-ternaries">15.6</a> Ternaries should not be nested and generally be single line expressions. eslint: <a href="https://eslint.org/docs/rules/no-nested-ternary"><code>no-nested-ternary</code></a></p>
<pre><code class="language-javascript">// bad
const foo = maybe1 &gt; maybe2
  ? &quot;bar&quot;
  : value1 &gt; value2 ? &quot;baz&quot; : null;

// split into 2 separated ternary expressions
const maybeNull = value1 &gt; value2 ? &#39;baz&#39; : null;

// better
const foo = maybe1 &gt; maybe2
  ? &#39;bar&#39;
  : maybeNull;

// best
const foo = maybe1 &gt; maybe2 ? &#39;bar&#39; : maybeNull;</code></pre>
<p><a name="comparison--unneeded-ternary"></a><a name="15.7"></a></p>
</li>
<li><p><a href="#comparison--unneeded-ternary">15.7</a> Avoid unneeded ternary statements. eslint: <a href="https://eslint.org/docs/rules/no-unneeded-ternary"><code>no-unneeded-ternary</code></a></p>
<pre><code class="language-javascript">// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
const quux = a != null ? a : b;

// good
const foo = a || b;
const bar = !!c;
const baz = !c;
const quux = a ?? b;</code></pre>
<p><a name="comparison--no-mixed-operators"></a></p>
</li>
<li><p><a href="#comparison--no-mixed-operators">15.8</a> When mixing operators, enclose them in parentheses. The only exception is the standard arithmetic operators: <code>+</code>, <code>-</code>, and <code>**</code> since their precedence is broadly understood. We recommend enclosing <code>/</code> and <code>*</code> in parentheses because their precedence can be ambiguous when they are mixed.
eslint: <a href="https://eslint.org/docs/rules/no-mixed-operators"><code>no-mixed-operators</code></a></p>
<blockquote>
<p>Why? This improves readability and clarifies the developer’s intention.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const foo = a &amp;&amp; b &lt; 0 || c &gt; 0 || d + 1 === 0;

// bad
const bar = a ** b - 5 % d;

// bad
// one may be confused into thinking (a || b) &amp;&amp; c
if (a || b &amp;&amp; c) {
  return d;
}

// bad
const bar = a + b / c * d;

// good
const foo = (a &amp;&amp; b &lt; 0) || c &gt; 0 || (d + 1 === 0);

// good
const bar = a ** b - (5 % d);

// good
if (a || (b &amp;&amp; c)) {
  return d;
}

// good
const bar = a + (b / c) * d;</code></pre>
<p><a name="nullish-coalescing-operator"></a></p>
</li>
<li><p><a href="#nullish-coalescing-operator">15.9</a> The nullish coalescing operator (<code>??</code>) is a logical operator that returns its right-hand side operand when its left-hand side operand is <code>null</code> or <code>undefined</code>. Otherwise, it returns the left-hand side operand.</p>
<blockquote>
<p>Why? It provides precision by distinguishing null/undefined from other falsy values, enhancing code clarity and predictability.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const value = 0 ?? &#39;default&#39;;
// returns 0, not &#39;default&#39;

// bad
const value = &#39;&#39; ?? &#39;default&#39;;
// returns &#39;&#39;, not &#39;default&#39;

// good
const value = null ?? &#39;default&#39;;
// returns &#39;default&#39;

// good
const user = {
  name: &#39;John&#39;,
  age: null
};
const age = user.age ?? 18;
// returns 18</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="blocks">Blocks</h2>
<p>  <a name="blocks--braces"></a><a name="16.1"></a></p>
<ul>
<li><p><a href="#blocks--braces">16.1</a> Use braces with all multiline blocks. eslint: <a href="https://eslint.org/docs/rules/nonblock-statement-body-position"><code>nonblock-statement-body-position</code></a></p>
<pre><code class="language-javascript">// bad
if (test)
  return false;

// good
if (test) return false;

// good
if (test) {
  return false;
}

// bad
function foo() { return false; }

// good
function bar() {
  return false;
}</code></pre>
<p><a name="blocks--cuddled-elses"></a><a name="16.2"></a></p>
</li>
<li><p><a href="#blocks--cuddled-elses">16.2</a> If you’re using multiline blocks with <code>if</code> and <code>else</code>, put <code>else</code> on the same line as your <code>if</code> block’s closing brace. eslint: <a href="https://eslint.org/docs/rules/brace-style"><code>brace-style</code></a></p>
<pre><code class="language-javascript">// bad
if (test) {
  thing1();
  thing2();
}
else {
  thing3();
}

// good
if (test) {
  thing1();
  thing2();
} else {
  thing3();
}</code></pre>
<p><a name="blocks--no-else-return"></a><a name="16.3"></a></p>
</li>
<li><p><a href="#blocks--no-else-return">16.3</a> If an <code>if</code> block always executes a <code>return</code> statement, the subsequent <code>else</code> block is unnecessary. A <code>return</code> in an <code>else if</code> block following an <code>if</code> block that contains a <code>return</code> can be separated into multiple <code>if</code> blocks. eslint: <a href="https://eslint.org/docs/rules/no-else-return"><code>no-else-return</code></a></p>
<pre><code class="language-javascript">// bad
function foo() {
  if (x) {
    return x;
  } else {
    return y;
  }
}

// bad
function cats() {
  if (x) {
    return x;
  } else if (y) {
    return y;
  }
}

// bad
function dogs() {
  if (x) {
    return x;
  } else {
    if (y) {
      return y;
    }
  }
}

// good
function foo() {
  if (x) {
    return x;
  }

  return y;
}

// good
function cats() {
  if (x) {
    return x;
  }

  if (y) {
    return y;
  }
}

// good
function dogs(x) {
  if (x) {
    if (z) {
      return y;
    }
  } else {
    return z;
  }
}</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="control-statements">Control Statements</h2>
<p>  <a name="control-statements"></a></p>
<ul>
<li><p><a href="#control-statements">17.1</a> In case your control statement (<code>if</code>, <code>while</code> etc.) gets too long or exceeds the maximum line length, each (grouped) condition could be put into a new line. The logical operator should begin the line.</p>
<blockquote>
<p>Why? Requiring operators at the beginning of the line keeps the operators aligned and follows a pattern similar to method chaining. This also improves readability by making it easier to visually follow complex logic.</p>
</blockquote>
<pre><code class="language-javascript">// bad
if ((foo === 123 || bar === &#39;abc&#39;) &amp;&amp; doesItLookGoodWhenItBecomesThatLong() &amp;&amp; isThisReallyHappening()) {
  thing1();
}

// bad
if (foo === 123 &amp;&amp;
  bar === &#39;abc&#39;) {
  thing1();
}

// bad
if (foo === 123
  &amp;&amp; bar === &#39;abc&#39;) {
  thing1();
}

// bad
if (
  foo === 123 &amp;&amp;
  bar === &#39;abc&#39;
) {
  thing1();
}

// good
if (
  foo === 123
  &amp;&amp; bar === &#39;abc&#39;
) {
  thing1();
}

// good
if (
  (foo === 123 || bar === &#39;abc&#39;)
  &amp;&amp; doesItLookGoodWhenItBecomesThatLong()
  &amp;&amp; isThisReallyHappening()
) {
  thing1();
}

// good
if (foo === 123 &amp;&amp; bar === &#39;abc&#39;) {
  thing1();
}</code></pre>
<p><a name="control-statement--value-selection"></a><a name="control-statements--value-selection"></a></p>
</li>
<li><p><a href="#control-statements--value-selection">17.2</a> Don&#39;t use selection operators in place of control statements.</p>
<pre><code class="language-javascript">// bad
!isRunning &amp;&amp; startRunning();

// good
if (!isRunning) {
  startRunning();
}</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="comments">Comments</h2>
<p>  <a name="comments--multiline"></a><a name="17.1"></a></p>
<ul>
<li><p><a href="#comments--multiline">18.1</a> Use <code>/** ... */</code> for multiline comments.</p>
<pre><code class="language-javascript">// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {

  // ...

  return element;
}

// good
/**
 * make() returns a new element
 * based on the passed-in tag name
 */
function make(tag) {

  // ...

  return element;
}</code></pre>
<p><a name="comments--singleline"></a><a name="17.2"></a></p>
</li>
<li><p><a href="#comments--singleline">18.2</a> Use <code>//</code> for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it’s on the first line of a block.</p>
<pre><code class="language-javascript">// bad
const active = true;  // is current tab

// good
// is current tab
const active = true;

// bad
function getType() {
  console.log(&#39;fetching type...&#39;);
  // set the default type to &#39;no type&#39;
  const type = this.type || &#39;no type&#39;;

  return type;
}

// good
function getType() {
  console.log(&#39;fetching type...&#39;);

  // set the default type to &#39;no type&#39;
  const type = this.type || &#39;no type&#39;;

  return type;
}

// also good
function getType() {
  // set the default type to &#39;no type&#39;
  const type = this.type || &#39;no type&#39;;

  return type;
}</code></pre>
<p><a name="comments--spaces"></a></p>
</li>
<li><p><a href="#comments--spaces">18.3</a> Start all comments with a space to make it easier to read. eslint: <a href="https://eslint.org/docs/rules/spaced-comment"><code>spaced-comment</code></a></p>
<pre><code class="language-javascript">// bad
//is current tab
const active = true;

// good
// is current tab
const active = true;

// bad
/**
 *make() returns a new element
 *based on the passed-in tag name
 */
function make(tag) {

  // ...

  return element;
}

// good
/**
 * make() returns a new element
 * based on the passed-in tag name
 */
function make(tag) {

  // ...

  return element;
}</code></pre>
<p><a name="comments--actionitems"></a><a name="17.3"></a></p>
</li>
<li><p><a href="#comments--actionitems">18.4</a> Prefixing your comments with <code>FIXME</code> or <code>TODO</code> helps other developers quickly understand if you’re pointing out a problem that needs to be revisited, or if you’re suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are <code>FIXME: -- need to figure this out</code> or <code>TODO: -- need to implement</code>.</p>
<p><a name="comments--fixme"></a><a name="17.4"></a></p>
</li>
<li><p><a href="#comments--fixme">18.5</a> Use <code>// FIXME:</code> to annotate problems.</p>
<pre><code class="language-javascript">class Calculator extends Abacus {
  constructor() {
    super();

    // FIXME: shouldn’t use a global here
    total = 0;
  }
}</code></pre>
<p><a name="comments--todo"></a><a name="17.5"></a></p>
</li>
<li><p><a href="#comments--todo">18.6</a> Use <code>// TODO:</code> to annotate solutions to problems.</p>
<pre><code class="language-javascript">class Calculator extends Abacus {
  constructor() {
    super();

    // TODO: total should be configurable by an options param
    this.total = 0;
  }
}</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="whitespace">Whitespace</h2>
<p>  <a name="whitespace--spaces"></a><a name="18.1"></a></p>
<ul>
<li><p><a href="#whitespace--spaces">19.1</a> Use soft tabs (space character) set to 2 spaces. eslint: <a href="https://eslint.org/docs/rules/indent"><code>indent</code></a></p>
<pre><code class="language-javascript">// bad
function foo() {
∙∙∙∙let name;
}

// bad
function bar() {
∙let name;
}

// good
function baz() {
∙∙let name;
}</code></pre>
<p><a name="whitespace--before-blocks"></a><a name="18.2"></a></p>
</li>
<li><p><a href="#whitespace--before-blocks">19.2</a> Place 1 space before the leading brace. eslint: <a href="https://eslint.org/docs/rules/space-before-blocks"><code>space-before-blocks</code></a></p>
<pre><code class="language-javascript">// bad
function test(){
  console.log(&#39;test&#39;);
}

// good
function test() {
  console.log(&#39;test&#39;);
}

// bad
dog.set(&#39;attr&#39;,{
  age: &#39;1 year&#39;,
  breed: &#39;Bernese Mountain Dog&#39;,
});

// good
dog.set(&#39;attr&#39;, {
  age: &#39;1 year&#39;,
  breed: &#39;Bernese Mountain Dog&#39;,
});</code></pre>
<p><a name="whitespace--around-keywords"></a><a name="18.3"></a></p>
</li>
<li><p><a href="#whitespace--around-keywords">19.3</a> Place 1 space before the opening parenthesis in control statements (<code>if</code>, <code>while</code> etc.). Place no space between the argument list and the function name in function calls and declarations. eslint: <a href="https://eslint.org/docs/rules/keyword-spacing"><code>keyword-spacing</code></a></p>
<pre><code class="language-javascript">// bad
if(isJedi) {
  fight ();
}

// good
if (isJedi) {
  fight();
}

// bad
function fight () {
  console.log (&#39;Swooosh!&#39;);
}

// good
function fight() {
  console.log(&#39;Swooosh!&#39;);
}</code></pre>
<p><a name="whitespace--infix-ops"></a><a name="18.4"></a></p>
</li>
<li><p><a href="#whitespace--infix-ops">19.4</a> Set off operators with spaces. eslint: <a href="https://eslint.org/docs/rules/space-infix-ops"><code>space-infix-ops</code></a></p>
<pre><code class="language-javascript">// bad
const x=y+5;

// good
const x = y + 5;</code></pre>
<p><a name="whitespace--newline-at-end"></a><a name="18.5"></a></p>
</li>
<li><p><a href="#whitespace--newline-at-end">19.5</a> End files with a single newline character. eslint: <a href="https://eslint.org/docs/rules/eol-last"><code>eol-last</code></a></p>
<pre><code class="language-javascript">// bad
import { es6 } from &#39;./AirbnbStyleGuide&#39;;
  // ...
export default es6;</code></pre>
<pre><code class="language-javascript">// bad
import { es6 } from &#39;./AirbnbStyleGuide&#39;;
  // ...
export default es6;↵
↵</code></pre>
<pre><code class="language-javascript">// good
import { es6 } from &#39;./AirbnbStyleGuide&#39;;
  // ...
export default es6;↵</code></pre>
<p><a name="whitespace--chains"></a><a name="18.6"></a></p>
</li>
<li><p><a href="#whitespace--chains">19.6</a> Use indentation when making long method chains (more than 2 method chains). Use a leading dot, which
emphasizes that the line is a method call, not a new statement. eslint: <a href="https://eslint.org/docs/rules/newline-per-chained-call"><code>newline-per-chained-call</code></a> <a href="https://eslint.org/docs/rules/no-whitespace-before-property"><code>no-whitespace-before-property</code></a></p>
<pre><code class="language-javascript">// bad
$(&#39;#items&#39;).find(&#39;.selected&#39;).highlight().end().find(&#39;.open&#39;).updateCount();

// bad
$(&#39;#items&#39;).
  find(&#39;.selected&#39;).
    highlight().
    end().
  find(&#39;.open&#39;).
    updateCount();

// good
$(&#39;#items&#39;)
  .find(&#39;.selected&#39;)
    .highlight()
    .end()
  .find(&#39;.open&#39;)
    .updateCount();

// bad
const leds = stage.selectAll(&#39;.led&#39;).data(data).enter().append(&#39;svg:svg&#39;).classed(&#39;led&#39;, true)
    .attr(&#39;width&#39;, (radius + margin) * 2).append(&#39;svg:g&#39;)
    .attr(&#39;transform&#39;, `translate(${radius + margin}, ${radius + margin})`)
    .call(tron.led);

// good
const leds = stage.selectAll(&#39;.led&#39;)
    .data(data)
  .enter().append(&#39;svg:svg&#39;)
    .classed(&#39;led&#39;, true)
    .attr(&#39;width&#39;, (radius + margin) * 2)
  .append(&#39;svg:g&#39;)
    .attr(&#39;transform&#39;, `translate(${radius + margin}, ${radius + margin})`)
    .call(tron.led);

// good
const leds = stage.selectAll(&#39;.led&#39;).data(data);
const svg = leds.enter().append(&#39;svg:svg&#39;);
svg.classed(&#39;led&#39;, true).attr(&#39;width&#39;, (radius + margin) * 2);
const g = svg.append(&#39;svg:g&#39;);
g.attr(&#39;transform&#39;, `translate(${radius + margin}, ${radius + margin})`).call(tron.led);</code></pre>
<p><a name="whitespace--after-blocks"></a><a name="18.7"></a></p>
</li>
<li><p><a href="#whitespace--after-blocks">19.7</a> Leave a blank line after blocks and before the next statement.</p>
<pre><code class="language-javascript">// bad
if (foo) {
  return bar;
}
return baz;

// good
if (foo) {
  return bar;
}

return baz;

// bad
const obj = {
  foo() {
  },
  bar() {
  },
};
return obj;

// good
const obj = {
  foo() {
  },

  bar() {
  },
};

return obj;

// bad
const arr = [
  function foo() {
  },
  function bar() {
  },
];
return arr;

// good
const arr = [
  function foo() {
  },

  function bar() {
  },
];

return arr;</code></pre>
<p><a name="whitespace--padded-blocks"></a><a name="18.8"></a></p>
</li>
<li><p><a href="#whitespace--padded-blocks">19.8</a> Do not pad your blocks with blank lines. eslint: <a href="https://eslint.org/docs/rules/padded-blocks"><code>padded-blocks</code></a></p>
<pre><code class="language-javascript">// bad
function bar() {

  console.log(foo);

}

// bad
if (baz) {

  console.log(quux);
} else {
  console.log(foo);

}

// bad
class Foo {

  constructor(bar) {
    this.bar = bar;
  }
}

// good
function bar() {
  console.log(foo);
}

// good
if (baz) {
  console.log(quux);
} else {
  console.log(foo);
}</code></pre>
<p><a name="whitespace--no-multiple-blanks"></a></p>
</li>
<li><p><a href="#whitespace--no-multiple-blanks">19.9</a> Do not use multiple blank lines to pad your code. eslint: <a href="https://eslint.org/docs/rules/no-multiple-empty-lines"><code>no-multiple-empty-lines</code></a></p>
<!-- markdownlint-disable MD012 -->
<pre><code class="language-javascript">// bad
class Person {
  constructor(fullName, email, birthday) {
    this.fullName = fullName;

</code></pre>
</li>
</ul>
<pre><code>    this.email = email;


    this.setAge(birthday);
  }


  setAge(birthday) {
    const today = new Date();


    const age = this.getAge(today, birthday);


    this.age = age;
  }


  getAge(today, birthday) {
    // ..
  }
}

// good
class Person {
  constructor(fullName, email, birthday) {
    this.fullName = fullName;
    this.email = email;
    this.setAge(birthday);
  }

  setAge(birthday) {
    const today = new Date();
    const age = getAge(today, birthday);
    this.age = age;
  }

  getAge(today, birthday) {
    // ..
  }
}
```</code></pre><p>  <a name="whitespace--in-parens"></a><a name="18.9"></a></p>
<ul>
<li><p><a href="#whitespace--in-parens">19.10</a> Do not add spaces inside parentheses. eslint: <a href="https://eslint.org/docs/rules/space-in-parens"><code>space-in-parens</code></a></p>
<pre><code class="language-javascript">// bad
function bar( foo ) {
  return foo;
}

// good
function bar(foo) {
  return foo;
}

// bad
if ( foo ) {
  console.log(foo);
}

// good
if (foo) {
  console.log(foo);
}</code></pre>
<p><a name="whitespace--in-brackets"></a><a name="18.10"></a></p>
</li>
<li><p><a href="#whitespace--in-brackets">19.11</a> Do not add spaces inside brackets. eslint: <a href="https://eslint.org/docs/rules/array-bracket-spacing"><code>array-bracket-spacing</code></a></p>
<pre><code class="language-javascript">// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);

// good
const foo = [1, 2, 3];
console.log(foo[0]);</code></pre>
<p><a name="whitespace--in-braces"></a><a name="18.11"></a></p>
</li>
<li><p><a href="#whitespace--in-braces">19.12</a> Add spaces inside curly braces. eslint: <a href="https://eslint.org/docs/rules/object-curly-spacing"><code>object-curly-spacing</code></a></p>
<pre><code class="language-javascript">// bad
const foo = {clark: &#39;kent&#39;};

// good
const foo = { clark: &#39;kent&#39; };</code></pre>
<p><a name="whitespace--max-len"></a><a name="18.12"></a></p>
</li>
<li><p><a href="#whitespace--max-len">19.13</a> Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per <a href="#strings--line-length">above</a>, long strings are exempt from this rule, and should not be broken up. eslint: <a href="https://eslint.org/docs/rules/max-len"><code>max-len</code></a></p>
<blockquote>
<p>Why? This ensures readability and maintainability.</p>
</blockquote>
<pre><code class="language-javascript">// bad
const foo = jsonData &amp;&amp; jsonData.foo &amp;&amp; jsonData.foo.bar &amp;&amp; jsonData.foo.bar.baz &amp;&amp; jsonData.foo.bar.baz.quux &amp;&amp; jsonData.foo.bar.baz.quux.xyzzy;

// bad
$.ajax({ method: &#39;POST&#39;, url: &#39;https://airbnb.com/&#39;, data: { name: &#39;John&#39; } }).done(() =&gt; console.log(&#39;Congratulations!&#39;)).fail(() =&gt; console.log(&#39;You have failed this city.&#39;));

// good
const foo = jsonData
  &amp;&amp; jsonData.foo
  &amp;&amp; jsonData.foo.bar
  &amp;&amp; jsonData.foo.bar.baz
  &amp;&amp; jsonData.foo.bar.baz.quux
  &amp;&amp; jsonData.foo.bar.baz.quux.xyzzy;

// better
const foo = jsonData
  ?.foo
  ?.bar
  ?.baz
  ?.quux
  ?.xyzzy;

// good
$.ajax({
  method: &#39;POST&#39;,
  url: &#39;https://airbnb.com/&#39;,
  data: { name: &#39;John&#39; },
})
  .done(() =&gt; console.log(&#39;Congratulations!&#39;))
  .fail(() =&gt; console.log(&#39;You have failed this city.&#39;));</code></pre>
<p><a name="whitespace--block-spacing"></a></p>
</li>
<li><p><a href="#whitespace--block-spacing">19.14</a> Require consistent spacing inside an open block token and the next token on the same line. This rule also enforces consistent spacing inside a close block token and previous token on the same line. eslint: <a href="https://eslint.org/docs/rules/block-spacing"><code>block-spacing</code></a></p>
<pre><code class="language-javascript">// bad
function foo() {return true;}
if (foo) { bar = 0;}

// good
function foo() { return true; }
if (foo) { bar = 0; }</code></pre>
<p><a name="whitespace--comma-spacing"></a></p>
</li>
<li><p><a href="#whitespace--comma-spacing">19.15</a> Avoid spaces before commas and require a space after commas. eslint: <a href="https://eslint.org/docs/rules/comma-spacing"><code>comma-spacing</code></a></p>
<pre><code class="language-javascript">// bad
const foo = 1,bar = 2;
const arr = [1 , 2];

// good
const foo = 1, bar = 2;
const arr = [1, 2];</code></pre>
<p><a name="whitespace--computed-property-spacing"></a></p>
</li>
<li><p><a href="#whitespace--computed-property-spacing">19.16</a> Enforce spacing inside of computed property brackets. eslint: <a href="https://eslint.org/docs/rules/computed-property-spacing"><code>computed-property-spacing</code></a></p>
<pre><code class="language-javascript">// bad
obj[foo ]
obj[ &#39;foo&#39;]
const x = {[ b ]: a}
obj[foo[ bar ]]

// good
obj[foo]
obj[&#39;foo&#39;]
const x = { [b]: a }
obj[foo[bar]]</code></pre>
<p><a name="whitespace--func-call-spacing"></a></p>
</li>
<li><p><a href="#whitespace--func-call-spacing">19.17</a> Avoid spaces between functions and their invocations. eslint: <a href="https://eslint.org/docs/rules/func-call-spacing"><code>func-call-spacing</code></a></p>
<pre><code class="language-javascript">// bad
func ();

func
();

// good
func();</code></pre>
<p><a name="whitespace--key-spacing"></a></p>
</li>
<li><p><a href="#whitespace--key-spacing">19.18</a> Enforce spacing between keys and values in object literal properties. eslint: <a href="https://eslint.org/docs/rules/key-spacing"><code>key-spacing</code></a></p>
<pre><code class="language-javascript">// bad
const obj = { foo : 42 };
const obj2 = { foo:42 };

// good
const obj = { foo: 42 };</code></pre>
<p><a name="whitespace--no-trailing-spaces"></a></p>
</li>
<li><p><a href="#whitespace--no-trailing-spaces">19.19</a> Avoid trailing spaces at the end of lines. eslint: <a href="https://eslint.org/docs/rules/no-trailing-spaces"><code>no-trailing-spaces</code></a></p>
<p><a name="whitespace--no-multiple-empty-lines"></a></p>
</li>
<li><p><a href="#whitespace--no-multiple-empty-lines">19.20</a> Avoid multiple empty lines, only allow one newline at the end of files, and avoid a newline at the beginning of files. eslint: <a href="https://eslint.org/docs/rules/no-multiple-empty-lines"><code>no-multiple-empty-lines</code></a></p>
<!-- markdownlint-disable MD012 -->
<pre><code class="language-javascript">// bad - multiple empty lines
const x = 1;

</code></pre>
</li>
</ul>
<pre><code>const y = 2;

// bad - 2+ newlines at end of file
const x = 1;
const y = 2;


// bad - 1+ newline(s) at beginning of file

const x = 1;
const y = 2;

// good
const x = 1;
const y = 2;

```
&lt;!-- markdownlint-enable MD012 --&gt;</code></pre><p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="commas">Commas</h2>
<p>  <a name="commas--leading-trailing"></a><a name="19.1"></a></p>
<ul>
<li><p><a href="#commas--leading-trailing">20.1</a> Leading commas: <strong>Nope.</strong> eslint: <a href="https://eslint.org/docs/rules/comma-style"><code>comma-style</code></a></p>
<pre><code class="language-javascript">// bad
const story = [
    once
  , upon
  , aTime
];

// good
const story = [
  once,
  upon,
  aTime,
];

// bad
const hero = {
    firstName: &#39;Ada&#39;
  , lastName: &#39;Lovelace&#39;
  , birthYear: 1815
  , superPower: &#39;computers&#39;
};

// good
const hero = {
  firstName: &#39;Ada&#39;,
  lastName: &#39;Lovelace&#39;,
  birthYear: 1815,
  superPower: &#39;computers&#39;,
};</code></pre>
<p><a name="commas--dangling"></a><a name="19.2"></a></p>
</li>
<li><p><a href="#commas--dangling">20.2</a> Additional trailing comma: <strong>Yup.</strong> eslint: <a href="https://eslint.org/docs/rules/comma-dangle"><code>comma-dangle</code></a></p>
<blockquote>
<p>Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don’t have to worry about the <a href="https://github.com/airbnb/javascript/blob/es5-deprecated/es5/README.md#commas">trailing comma problem</a> in legacy browsers.</p>
</blockquote>
<pre><code class="language-diff">// bad - git diff without trailing comma
const hero = {
     firstName: &#39;Florence&#39;,
-    lastName: &#39;Nightingale&#39;
+    lastName: &#39;Nightingale&#39;,
+    inventorOf: [&#39;coxcomb chart&#39;, &#39;modern nursing&#39;]
};

// good - git diff with trailing comma
const hero = {
     firstName: &#39;Florence&#39;,
     lastName: &#39;Nightingale&#39;,
+    inventorOf: [&#39;coxcomb chart&#39;, &#39;modern nursing&#39;],
};</code></pre>
<pre><code class="language-javascript">// bad
const hero = {
  firstName: &#39;Dana&#39;,
  lastName: &#39;Scully&#39;
};

const heroes = [
  &#39;Batman&#39;,
  &#39;Superman&#39;
];

// good
const hero = {
  firstName: &#39;Dana&#39;,
  lastName: &#39;Scully&#39;,
};

const heroes = [
  &#39;Batman&#39;,
  &#39;Superman&#39;,
];

// bad
function createHero(
  firstName,
  lastName,
  inventorOf
) {
  // does nothing
}

// good
function createHero(
  firstName,
  lastName,
  inventorOf,
) {
  // does nothing
}

// good (note that a comma must not appear after a &quot;rest&quot; element)
function createHero(
  firstName,
  lastName,
  inventorOf,
  ...heroArgs
) {
  // does nothing
}

// bad
createHero(
  firstName,
  lastName,
  inventorOf
);

// good
createHero(
  firstName,
  lastName,
  inventorOf,
);

// good (note that a comma must not appear after a &quot;rest&quot; element)
createHero(
  firstName,
  lastName,
  inventorOf,
  ...heroArgs
);</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="semicolons">Semicolons</h2>
<p>  <a name="semicolons--required"></a><a name="20.1"></a></p>
<ul>
<li><p><a href="#semicolons--required">21.1</a> <strong>Yup.</strong> eslint: <a href="https://eslint.org/docs/rules/semi"><code>semi</code></a></p>
<blockquote>
<p>Why? When JavaScript encounters a line break without a semicolon, it uses a set of rules called <a href="https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion">Automatic Semicolon Insertion</a> to determine whether it should regard that line break as the end of a statement, and (as the name implies) place a semicolon into your code before the line break if it thinks so. ASI contains a few eccentric behaviors, though, and your code will break if JavaScript misinterprets your line break. These rules will become more complicated as new features become a part of JavaScript. Explicitly terminating your statements and configuring your linter to catch missing semicolons will help prevent you from encountering issues.</p>
</blockquote>
<pre><code class="language-javascript">// bad - raises exception
const luke = {}
const leia = {}
[luke, leia].forEach((jedi) =&gt; jedi.father = &#39;vader&#39;)

// bad - raises exception
const reaction = &quot;No! That’s impossible!&quot;
(async function meanwhileOnTheFalcon() {
  // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
  // ...
}())

// bad - returns `undefined` instead of the value on the next line - always happens when `return` is on a line by itself because of ASI!
function foo() {
  return
    &#39;search your feelings, you know it to be foo&#39;
}

// good
const luke = {};
const leia = {};
[luke, leia].forEach((jedi) =&gt; {
  jedi.father = &#39;vader&#39;;
});

// good
const reaction = &#39;No! That’s impossible!&#39;;
(async function meanwhileOnTheFalcon() {
  // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
  // ...
}());

// good
function foo() {
  return &#39;search your feelings, you know it to be foo&#39;;
}</code></pre>
<p><a href="https://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214#7365214">Read more</a>.</p>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="type-casting--coercion">Type Casting &amp; Coercion</h2>
<p>  <a name="coercion--explicit"></a><a name="21.1"></a></p>
<ul>
<li><p><a href="#coercion--explicit">22.1</a> Perform type coercion at the beginning of the statement.</p>
<p><a name="coercion--strings"></a><a name="21.2"></a></p>
</li>
<li><p><a href="#coercion--strings">22.2</a> Strings: eslint: <a href="https://eslint.org/docs/rules/no-new-wrappers"><code>no-new-wrappers</code></a></p>
<pre><code class="language-javascript">// =&gt; this.reviewScore = 9;

// bad
const totalScore = new String(this.reviewScore); // typeof totalScore is &quot;object&quot; not &quot;string&quot;

// bad
const totalScore = this.reviewScore + &#39;&#39;; // invokes this.reviewScore.valueOf()

// bad
const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string

// good
const totalScore = String(this.reviewScore);</code></pre>
<p><a name="coercion--numbers"></a><a name="21.3"></a></p>
</li>
<li><p><a href="#coercion--numbers">22.3</a> Numbers: Use <code>Number</code> for type casting and <code>parseInt</code> always with a radix for parsing strings. eslint: <a href="https://eslint.org/docs/rules/radix"><code>radix</code></a> <a href="https://eslint.org/docs/rules/no-new-wrappers"><code>no-new-wrappers</code></a></p>
<blockquote>
<p>Why? The <code>parseInt</code> function produces an integer value dictated by interpretation of the contents of the string argument according to the specified radix. Leading whitespace in string is ignored. If radix is <code>undefined</code> or <code>0</code>, it is assumed to be <code>10</code> except when the number begins with the character pairs <code>0x</code> or <code>0X</code>, in which case a radix of 16 is assumed. This differs from ECMAScript 3, which merely discouraged (but allowed) octal interpretation. Many implementations have not adopted this behavior as of 2013. And, because older browsers must be supported, always specify a radix.</p>
</blockquote>
<pre><code class="language-javascript">const inputValue = &#39;4&#39;;

// bad
const val = new Number(inputValue);

// bad
const val = +inputValue;

// bad
const val = inputValue &gt;&gt; 0;

// bad
const val = parseInt(inputValue);

// good
const val = Number(inputValue);

// good
const val = parseInt(inputValue, 10);</code></pre>
<p><a name="coercion--comment-deviations"></a><a name="21.4"></a></p>
</li>
<li><p><a href="#coercion--comment-deviations">22.4</a> If for whatever reason you are doing something wild and <code>parseInt</code> is your bottleneck and need to use Bitshift for <a href="https://web.archive.org/web/20200414205431/https://jsperf.com/coercion-vs-casting/3">performance reasons</a>, leave a comment explaining why and what you’re doing.</p>
<pre><code class="language-javascript">// good
/**
 * parseInt was the reason my code was slow.
 * Bitshifting the String to coerce it to a
 * Number made it a lot faster.
 */
const val = inputValue &gt;&gt; 0;</code></pre>
<p><a name="coercion--bitwise"></a><a name="21.5"></a></p>
</li>
<li><p><a href="#coercion--bitwise">22.5</a> <strong>Note:</strong> Be careful when using bitshift operations. Numbers are represented as <a href="https://es5.github.io/#x4.3.19">64-bit values</a>, but bitshift operations always return a 32-bit integer (<a href="https://es5.github.io/#x11.7">source</a>). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. <a href="https://github.com/airbnb/javascript/issues/109">Discussion</a>. Largest signed 32-bit Int is 2,147,483,647:</p>
<pre><code class="language-javascript">2147483647 &gt;&gt; 0; // =&gt; 2147483647
2147483648 &gt;&gt; 0; // =&gt; -2147483648
2147483649 &gt;&gt; 0; // =&gt; -2147483647</code></pre>
<p><a name="coercion--booleans"></a><a name="21.6"></a></p>
</li>
<li><p><a href="#coercion--booleans">22.6</a> Booleans: eslint: <a href="https://eslint.org/docs/rules/no-new-wrappers"><code>no-new-wrappers</code></a></p>
<pre><code class="language-javascript">const age = 0;

// bad
const hasAge = new Boolean(age);

// good
const hasAge = Boolean(age);

// best
const hasAge = !!age;</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="naming-conventions">Naming Conventions</h2>
<p>  <a name="naming--descriptive"></a><a name="22.1"></a></p>
<ul>
<li><p><a href="#naming--descriptive">23.1</a> Avoid single letter names. Be descriptive with your naming. eslint: <a href="https://eslint.org/docs/rules/id-length"><code>id-length</code></a></p>
<pre><code class="language-javascript">// bad
function q() {
  // ...
}

// good
function query() {
  // ...
}</code></pre>
<p><a name="naming--camelCase"></a><a name="22.2"></a></p>
</li>
<li><p><a href="#naming--camelCase">23.2</a> Use camelCase when naming objects, functions, and instances. eslint: <a href="https://eslint.org/docs/rules/camelcase"><code>camelcase</code></a></p>
<pre><code class="language-javascript">// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}

// good
const thisIsMyObject = {};
function thisIsMyFunction() {}</code></pre>
<p><a name="naming--PascalCase"></a><a name="22.3"></a></p>
</li>
<li><p><a href="#naming--PascalCase">23.3</a> Use PascalCase only when naming constructors or classes. eslint: <a href="https://eslint.org/docs/rules/new-cap"><code>new-cap</code></a></p>
<pre><code class="language-javascript">// bad
function user(options) {
  this.name = options.name;
}

const bad = new user({
  name: &#39;nope&#39;,
});

// good
class User {
  constructor(options) {
    this.name = options.name;
  }
}

const good = new User({
  name: &#39;yup&#39;,
});</code></pre>
<p><a name="naming--leading-underscore"></a><a name="22.4"></a></p>
</li>
<li><p><a href="#naming--leading-underscore">23.4</a> Do not use trailing or leading underscores. eslint: <a href="https://eslint.org/docs/rules/no-underscore-dangle"><code>no-underscore-dangle</code></a></p>
<blockquote>
<p>Why? JavaScript does not have the concept of privacy in terms of properties or methods. Although a leading underscore is a common convention to mean “private”, in fact, these properties are fully public, and as such, are part of your public API contract. This convention might lead developers to wrongly think that a change won’t count as breaking, or that tests aren’t needed. tl;dr: if you want something to be “private”, it must not be observably present.</p>
</blockquote>
<pre><code class="language-javascript">// bad
this.__firstName__ = &#39;Panda&#39;;
this.firstName_ = &#39;Panda&#39;;
this._firstName = &#39;Panda&#39;;

// good
this.firstName = &#39;Panda&#39;;

// good, in environments where WeakMaps are available
// see https://compat-table.github.io/compat-table/es6/#test-WeakMap
const firstNames = new WeakMap();
firstNames.set(this, &#39;Panda&#39;);</code></pre>
<p><a name="naming--self-this"></a><a name="22.5"></a></p>
</li>
<li><p><a href="#naming--self-this">23.5</a> Don’t save references to <code>this</code>. Use arrow functions or <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">Function#bind</a>.</p>
<pre><code class="language-javascript">// bad
function foo() {
  const self = this;
  return function () {
    console.log(self);
  };
}

// bad
function foo() {
  const that = this;
  return function () {
    console.log(that);
  };
}

// good
function foo() {
  return () =&gt; {
    console.log(this);
  };
}</code></pre>
<p><a name="naming--filename-matches-export"></a><a name="22.6"></a></p>
</li>
<li><p><a href="#naming--filename-matches-export">23.6</a> A base filename should exactly match the name of its default export.</p>
<pre><code class="language-javascript">// file 1 contents
class CheckBox {
  // ...
}
export default CheckBox;

// file 2 contents
export default function fortyTwo() { return 42; }

// file 3 contents
export default function insideDirectory() {}

// in some other file
// bad
import CheckBox from &#39;./checkBox&#39;; // PascalCase import/export, camelCase filename
import FortyTwo from &#39;./FortyTwo&#39;; // PascalCase import/filename, camelCase export
import InsideDirectory from &#39;./InsideDirectory&#39;; // PascalCase import/filename, camelCase export

// bad
import CheckBox from &#39;./check_box&#39;; // PascalCase import/export, snake_case filename
import forty_two from &#39;./forty_two&#39;; // snake_case import/filename, camelCase export
import inside_directory from &#39;./inside_directory&#39;; // snake_case import, camelCase export
import index from &#39;./inside_directory/index&#39;; // requiring the index file explicitly
import insideDirectory from &#39;./insideDirectory/index&#39;; // requiring the index file explicitly

// good
import CheckBox from &#39;./CheckBox&#39;; // PascalCase export/import/filename
import fortyTwo from &#39;./fortyTwo&#39;; // camelCase export/import/filename
import insideDirectory from &#39;./insideDirectory&#39;; // camelCase export/import/directory name/implicit &quot;index&quot;
// ^ supports both insideDirectory.js and insideDirectory/index.js</code></pre>
<p><a name="naming--camelCase-default-export"></a><a name="22.7"></a></p>
</li>
<li><p><a href="#naming--camelCase-default-export">23.7</a> Use camelCase when you export-default a function. Your filename should be identical to your function’s name.</p>
<pre><code class="language-javascript">function makeStyleGuide() {
  // ...
}

export default makeStyleGuide;</code></pre>
<p><a name="naming--PascalCase-singleton"></a><a name="22.8"></a></p>
</li>
<li><p><a href="#naming--PascalCase-singleton">23.8</a> Use PascalCase when you export a constructor / class / singleton / function library / bare object.</p>
<pre><code class="language-javascript">const AirbnbStyleGuide = {
  es6: {
  },
};

export default AirbnbStyleGuide;</code></pre>
<p><a name="naming--Acronyms-and-Initialisms"></a></p>
</li>
<li><p><a href="#naming--Acronyms-and-Initialisms">23.9</a> Acronyms and initialisms should always be all uppercased, or all lowercased.</p>
<blockquote>
<p>Why? Names are for readability, not to appease a computer algorithm.</p>
</blockquote>
<pre><code class="language-javascript">// bad
import SmsContainer from &#39;./containers/SmsContainer&#39;;

// bad
const HttpRequests = [
  // ...
];

// good
import SMSContainer from &#39;./containers/SMSContainer&#39;;

// good
const HTTPRequests = [
  // ...
];

// also good
const httpRequests = [
  // ...
];

// best
import TextMessageContainer from &#39;./containers/TextMessageContainer&#39;;

// best
const requests = [
  // ...
];</code></pre>
<p><a name="naming--uppercase"></a></p>
</li>
<li><p><a href="#naming--uppercase">23.10</a> You may optionally uppercase a constant only if it (1) is exported, (2) is a <code>const</code> (it can not be reassigned), and (3) the programmer can trust it (and its nested properties) to never change.</p>
<blockquote>
<p>Why? This is an additional tool to assist in situations where the programmer would be unsure if a variable might ever change. UPPERCASE_VARIABLES are letting the programmer know that they can trust the variable (and its properties) not to change.</p>
</blockquote>
<ul>
<li>What about all <code>const</code> variables? - This is unnecessary, so uppercasing should not be used for constants within a file. It should be used for exported constants however.</li>
<li>What about exported objects? - Uppercase at the top level of export (e.g. <code>EXPORTED_OBJECT.key</code>) and maintain that all nested properties do not change.</li>
</ul>
<pre><code class="language-javascript">// bad
const PRIVATE_VARIABLE = &#39;should not be unnecessarily uppercased within a file&#39;;

// bad
export const THING_TO_BE_CHANGED = &#39;should obviously not be uppercased&#39;;

// bad
export let REASSIGNABLE_VARIABLE = &#39;do not use let with uppercase variables&#39;;

// ---

// allowed but does not supply semantic value
export const apiKey = &#39;SOMEKEY&#39;;

// better in most cases
export const API_KEY = &#39;SOMEKEY&#39;;

// ---

// bad - unnecessarily uppercases key while adding no semantic value
export const MAPPING = {
  KEY: &#39;value&#39;
};

// good
export const MAPPING = {
  key: &#39;value&#39;,
};</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="accessors">Accessors</h2>
<p>  <a name="accessors--not-required"></a><a name="23.1"></a></p>
<ul>
<li><p><a href="#accessors--not-required">24.1</a> Accessor functions for properties are not required.</p>
<p><a name="accessors--no-getters-setters"></a><a name="23.2"></a></p>
</li>
<li><p><a href="#accessors--no-getters-setters">24.2</a> Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use <code>getVal()</code> and <code>setVal(&#39;hello&#39;)</code>.</p>
<pre><code class="language-javascript">// bad
class Dragon {
  get age() {
    // ...
  }

  set age(value) {
    // ...
  }
}

// good
class Dragon {
  getAge() {
    // ...
  }

  setAge(value) {
    // ...
  }
}</code></pre>
<p><a name="accessors--boolean-prefix"></a><a name="23.3"></a></p>
</li>
<li><p><a href="#accessors--boolean-prefix">24.3</a> If the property/method is a <code>boolean</code>, use <code>isVal()</code> or <code>hasVal()</code>.</p>
<pre><code class="language-javascript">// bad
if (!dragon.age()) {
  return false;
}

// good
if (!dragon.hasAge()) {
  return false;
}</code></pre>
<p><a name="accessors--consistent"></a><a name="23.4"></a></p>
</li>
<li><p><a href="#accessors--consistent">24.4</a> It’s okay to create <code>get()</code> and <code>set()</code> functions, but be consistent.</p>
<pre><code class="language-javascript">class Jedi {
  constructor(options = {}) {
    const lightsaber = options.lightsaber || &#39;blue&#39;;
    this.set(&#39;lightsaber&#39;, lightsaber);
  }

  set(key, val) {
    this[key] = val;
  }

  get(key) {
    return this[key];
  }
}</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="events">Events</h2>
<p>  <a name="events--hash"></a><a name="24.1"></a></p>
<ul>
<li><p><a href="#events--hash">25.1</a> When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass an object literal (also known as a &quot;hash&quot;) instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of:</p>
<pre><code class="language-javascript">// bad
$(this).trigger(&#39;listingUpdated&#39;, listing.id);

// ...

$(this).on(&#39;listingUpdated&#39;, (e, listingID) =&gt; {
  // do something with listingID
});</code></pre>
<p>prefer:</p>
<pre><code class="language-javascript">// good
$(this).trigger(&#39;listingUpdated&#39;, { listingID: listing.id });

// ...

$(this).on(&#39;listingUpdated&#39;, (e, data) =&gt; {
  // do something with data.listingID
});</code></pre>
</li>
<li><p>*<a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a>**</p>
</li>
</ul>
<h2 id="jquery">jQuery</h2>
<p>  <a name="jquery--dollar-prefix"></a><a name="25.1"></a></p>
<ul>
<li><p><a href="#jquery--dollar-prefix">26.1</a> Prefix jQuery object variables with a <code>$</code>.</p>
<pre><code class="language-javascript">// bad
const sidebar = $(&#39;.sidebar&#39;);

// good
const $sidebar = $(&#39;.sidebar&#39;);

// good
const $sidebarBtn = $(&#39;.sidebar-btn&#39;);</code></pre>
<p><a name="jquery--cache"></a><a name="25.2"></a></p>
</li>
<li><p><a href="#jquery--cache">26.2</a> Cache jQuery lookups.</p>
<pre><code class="language-javascript">// bad
function setSidebar() {
  $(&#39;.sidebar&#39;).hide();

  // ...

  $(&#39;.sidebar&#39;).css({
    &#39;background-color&#39;: &#39;pink&#39;,
  });
}

// good
function setSidebar() {
  const $sidebar = $(&#39;.sidebar&#39;);
  $sidebar.hide();

  // ...

  $sidebar.css({
    &#39;background-color&#39;: &#39;pink&#39;,
  });
}</code></pre>
<p><a name="jquery--queries"></a><a name="25.3"></a></p>
</li>
<li><p><a href="#jquery--queries">26.3</a> For DOM queries use Cascading <code>$(&#39;.sidebar ul&#39;)</code> or parent &gt; child <code>$(&#39;.sidebar &gt; ul&#39;)</code>. <a href="https://web.archive.org/web/20200414183810/https://jsperf.com/jquery-find-vs-context-sel/16">jsPerf</a></p>
<p><a name="jquery--find"></a><a name="25.4"></a></p>
</li>
<li><p><a href="#jquery--find">26.4</a> Use <code>find</code> with scoped jQuery object queries.</p>
<pre><code class="language-javascript">// bad
$(&#39;ul&#39;, &#39;.sidebar&#39;).hide();

// bad
$(&#39;.sidebar&#39;).find(&#39;ul&#39;).hide();

// good
$(&#39;.sidebar ul&#39;).hide();

// good
$(&#39;.sidebar &gt; ul&#39;).hide();

// good
$sidebar.find(&#39;ul&#39;).hide();</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="ecmascript-5-compatibility">ECMAScript 5 Compatibility</h2>
<p>  <a name="es5-compat--kangax"></a><a name="26.1"></a></p>
<ul>
<li><a href="#es5-compat--kangax">27.1</a> Refer to <a href="https://twitter.com/kangax/">Kangax</a>’s ES5 <a href="https://compat-table.github.io/compat-table/es5/">compatibility table</a>.</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<p><a name="ecmascript-6-styles"></a></p>
<h2 id="ecmascript-6-es-2015-styles">ECMAScript 6+ (ES 2015+) Styles</h2>
<p>  <a name="es6-styles"></a><a name="27.1"></a></p>
<ul>
<li><a href="#es6-styles">28.1</a> This is a collection of links to the various ES6+ features.</li>
</ul>
<ol>
<li><p><a href="#arrow-functions">Arrow Functions</a></p>
</li>
<li><p><a href="#classes--constructors">Classes</a></p>
</li>
<li><p><a href="#es6-object-shorthand">Object Shorthand</a></p>
</li>
<li><p><a href="#es6-object-concise">Object Concise</a></p>
</li>
<li><p><a href="#es6-computed-properties">Object Computed Properties</a></p>
</li>
<li><p><a href="#es6-template-literals">Template Strings</a></p>
</li>
<li><p><a href="#destructuring">Destructuring</a></p>
</li>
<li><p><a href="#es6-default-parameters">Default Parameters</a></p>
</li>
<li><p><a href="#es6-rest">Rest</a></p>
</li>
<li><p><a href="#es6-array-spreads">Array Spreads</a></p>
</li>
<li><p><a href="#references">Let and Const</a></p>
</li>
<li><p><a href="#es2016-properties--exponentiation-operator">Exponentiation Operator</a></p>
</li>
<li><p><a href="#iterators-and-generators">Iterators and Generators</a></p>
</li>
<li><p><a href="#modules">Modules</a></p>
<p><a name="tc39-proposals"></a></p>
<ul>
<li><p><a href="#tc39-proposals">28.2</a> Do not use <a href="https://github.com/tc39/proposals">TC39 proposals</a> that have not reached stage 3.</p>
<blockquote>
<p>Why? <a href="https://tc39.github.io/process-document/">They are not finalized</a>, and they are subject to change or to be withdrawn entirely. We want to use JavaScript, and proposals are not JavaScript yet.</p>
</blockquote>
</li>
</ul>
</li>
</ol>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="standard-library">Standard Library</h2>
<p>  The <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects">Standard Library</a>
  contains utilities that are functionally broken but remain for legacy reasons.</p>
<p>  <a name="standard-library--isnan"></a></p>
<ul>
<li><p><a href="#standard-library--isnan">29.1</a> Use <code>Number.isNaN</code> instead of global <code>isNaN</code>.
eslint: <a href="https://eslint.org/docs/rules/no-restricted-globals"><code>no-restricted-globals</code></a></p>
<blockquote>
<p>Why? The global <code>isNaN</code> coerces non-numbers to numbers, returning true for anything that coerces to NaN.
If this behavior is desired, make it explicit.</p>
</blockquote>
<pre><code class="language-javascript">// bad
isNaN(&#39;1.2&#39;); // false
isNaN(&#39;1.2.3&#39;); // true

// good
Number.isNaN(&#39;1.2.3&#39;); // false
Number.isNaN(Number(&#39;1.2.3&#39;)); // true</code></pre>
<p><a name="standard-library--isfinite"></a></p>
</li>
<li><p><a href="#standard-library--isfinite">29.2</a> Use <code>Number.isFinite</code> instead of global <code>isFinite</code>.
eslint: <a href="https://eslint.org/docs/rules/no-restricted-globals"><code>no-restricted-globals</code></a></p>
<blockquote>
<p>Why? The global <code>isFinite</code> coerces non-numbers to numbers, returning true for anything that coerces to a finite number.
If this behavior is desired, make it explicit.</p>
</blockquote>
<pre><code class="language-javascript">// bad
isFinite(&#39;2e3&#39;); // true

// good
Number.isFinite(&#39;2e3&#39;); // false
Number.isFinite(parseInt(&#39;2e3&#39;, 10)); // true</code></pre>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="testing">Testing</h2>
<p>  <a name="testing--yup"></a><a name="28.1"></a></p>
<ul>
<li><p><a href="#testing--yup">30.1</a> <strong>Yup.</strong></p>
<pre><code class="language-javascript">function foo() {
  return true;
}</code></pre>
<p><a name="testing--for-real"></a><a name="28.2"></a></p>
</li>
<li><p><a href="#testing--for-real">30.2</a> <strong>No, but seriously</strong>:</p>
<ul>
<li>Whichever testing framework you use, you should be writing tests!</li>
<li>Strive to write many small pure functions, and minimize where mutations occur.</li>
<li>Be cautious about stubs and mocks - they can make your tests more brittle.</li>
<li>We primarily use <a href="https://www.npmjs.com/package/mocha"><code>mocha</code></a> and <a href="https://www.npmjs.com/package/jest"><code>jest</code></a> at Airbnb. <a href="https://www.npmjs.com/package/tape"><code>tape</code></a> is also used occasionally for small, separate modules.</li>
<li>100% test coverage is a good goal to strive for, even if it’s not always practical to reach it.</li>
<li>Whenever you fix a bug, <em>write a regression test</em>. A bug fixed without a regression test is almost certainly going to break again in the future.</li>
</ul>
</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="performance">Performance</h2>
<ul>
<li><a href="https://www.kellegous.com/j/2013/01/26/layout-performance/">On Layout &amp; Web Performance</a></li>
<li><a href="https://web.archive.org/web/20200414200857/https://jsperf.com/string-vs-array-concat/2">String vs Array Concat</a></li>
<li><a href="https://web.archive.org/web/20200414190827/https://jsperf.com/try-catch-in-loop-cost/12">Try/Catch Cost In a Loop</a></li>
<li><a href="https://web.archive.org/web/20200414205426/https://jsperf.com/bang-function">Bang Function</a></li>
<li><a href="https://web.archive.org/web/20200414200850/https://jsperf.com/jquery-find-vs-context-sel/164">jQuery Find vs Context, Selector</a></li>
<li><a href="https://web.archive.org/web/20200414205428/https://jsperf.com/innerhtml-vs-textcontent-for-script-text">innerHTML vs textContent for script text</a></li>
<li><a href="https://web.archive.org/web/20200414203914/https://jsperf.com/ya-string-concat/38">Long String Concatenation</a></li>
<li><a href="https://www.quora.com/JavaScript-programming-language-Are-Javascript-functions-like-map-reduce-and-filter-already-optimized-for-traversing-array/answer/Quildreen-Motta">Are JavaScript functions like <code>map()</code>, <code>reduce()</code>, and <code>filter()</code> optimized for traversing arrays?</a></li>
<li>Loading...</li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="resources">Resources</h2>
<p><strong>Learning ES6+</strong></p>
<ul>
<li><a href="https://tc39.github.io/ecma262/">Latest ECMA spec</a></li>
<li><a href="https://exploringjs.com/">ExploringJS</a></li>
<li><a href="https://compat-table.github.io/compat-table/es6/">ES6 Compatibility Table</a></li>
<li><a href="https://web.archive.org/web/20240404212626/http://es6-features.org/">Comprehensive Overview of ES6 Features</a></li>
<li><a href="https://roadmap.sh/javascript">JavaScript Roadmap</a></li>
</ul>
<p><strong>Read This</strong></p>
<ul>
<li><a href="https://www.ecma-international.org/ecma-262/6.0/index.html">Standard ECMA-262</a></li>
</ul>
<p><strong>Tools</strong></p>
<ul>
<li>Code Style Linters<ul>
<li><a href="https://eslint.org/">ESlint</a> - <a href="https://github.com/airbnb/javascript/blob/master/linters/.eslintrc">Airbnb Style .eslintrc</a></li>
<li><a href="https://jshint.com/">JSHint</a> - <a href="https://github.com/airbnb/javascript/blob/master/linters/.jshintrc">Airbnb Style .jshintrc</a></li>
</ul>
</li>
<li>Neutrino Preset - <a href="https://neutrinojs.org/packages/airbnb/">@neutrinojs/airbnb</a></li>
</ul>
<p><strong>Other Style Guides</strong></p>
<ul>
<li><a href="https://google.github.io/styleguide/jsguide.html">Google JavaScript Style Guide</a></li>
<li><a href="https://google.github.io/styleguide/javascriptguide.xml">Google JavaScript Style Guide (Old)</a></li>
<li><a href="https://contribute.jquery.org/style-guide/js/">jQuery Core Style Guidelines</a></li>
<li><a href="https://github.com/rwaldron/idiomatic.js">Principles of Writing Consistent, Idiomatic JavaScript</a></li>
<li><a href="https://standardjs.com">StandardJS</a></li>
</ul>
<p><strong>Other Styles</strong></p>
<ul>
<li><a href="https://gist.github.com/cjohansen/4135065">Naming this in nested functions</a> - Christian Johansen</li>
<li><a href="https://github.com/airbnb/javascript/issues/52">Conditional Callbacks</a> - Ross Allen</li>
<li><a href="http://sideeffect.kr/popularconvention/#javascript">Popular JavaScript Coding Conventions on GitHub</a> - JeongHoon Byun</li>
<li><a href="https://benalman.com/news/2012/05/multiple-var-statements-javascript/">Multiple var statements in JavaScript, not superfluous</a> - Ben Alman</li>
</ul>
<p><strong>Further Reading</strong></p>
<ul>
<li><a href="https://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/">Understanding JavaScript Closures</a> - Angus Croll</li>
<li><a href="https://www.2ality.com/2013/06/basic-javascript.html">Basic JavaScript for the impatient programmer</a> - Dr. Axel Rauschmayer</li>
<li><a href="https://youmightnotneedjquery.com/">You Might Not Need jQuery</a> - Zack Bloom &amp; Adam Schwartz</li>
<li><a href="https://github.com/lukehoban/es6features">ES6 Features</a> - Luke Hoban</li>
<li><a href="https://github.com/bendc/frontend-guidelines">Frontend Guidelines</a> - Benjamin De Cock</li>
</ul>
<p><strong>Books</strong></p>
<ul>
<li><a href="https://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742">JavaScript: The Good Parts</a> - Douglas Crockford</li>
<li><a href="https://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752">JavaScript Patterns</a> - Stoyan Stefanov</li>
<li><a href="https://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X">Pro JavaScript Design Patterns</a> - Ross Harmes and Dustin Diaz</li>
<li><a href="https://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309">High Performance Web Sites: Essential Knowledge for Front-End Engineers</a> - Steve Souders</li>
<li><a href="https://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680">Maintainable JavaScript</a> - Nicholas C. Zakas</li>
<li><a href="https://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X">JavaScript Web Applications</a> - Alex MacCaw</li>
<li><a href="https://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273">Pro JavaScript Techniques</a> - John Resig</li>
<li><a href="https://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595">Smashing Node.js: JavaScript Everywhere</a> - Guillermo Rauch</li>
<li><a href="https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X">Secrets of the JavaScript Ninja</a> - John Resig and Bear Bibeault</li>
<li><a href="http://humanjavascript.com/">Human JavaScript</a> - Henrik Joreteg</li>
<li><a href="http://superherojs.com/">Superhero.js</a> - Kim Joar Bekkelund, Mads Mobæk, &amp; Olav Bjorkoy</li>
<li><a href="https://jsbooks.revolunet.com/">JSBooks</a> - Julien Bouquillon</li>
<li><a href="https://www.manning.com/books/third-party-javascript">Third Party JavaScript</a> - Ben Vinegar and Anton Kovalyov</li>
<li><a href="https://amzn.com/dp/0321812182">Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript</a> - David Herman</li>
<li><a href="https://eloquentjavascript.net/">Eloquent JavaScript</a> - Marijn Haverbeke</li>
<li><a href="https://shop.oreilly.com/product/0636920033769.do">You Don’t Know JS: ES6 &amp; Beyond</a> - Kyle Simpson</li>
</ul>
<p><strong>Blogs</strong></p>
<ul>
<li><a href="https://javascriptweekly.com/">JavaScript Weekly</a></li>
<li><a href="https://javascriptweblog.wordpress.com/">JavaScript, JavaScript...</a></li>
<li><a href="https://bocoup.com/weblog">Bocoup Weblog</a></li>
<li><a href="https://www.adequatelygood.com/">Adequately Good</a></li>
<li><a href="https://www.nczonline.net/">NCZOnline</a></li>
<li><a href="http://perfectionkills.com/">Perfection Kills</a></li>
<li><a href="https://benalman.com/">Ben Alman</a></li>
<li><a href="http://dmitry.baranovskiy.com/">Dmitry Baranovskiy</a></li>
<li><a href="https://code.tutsplus.com/?s=javascript">nettuts</a></li>
</ul>
<p><strong>Podcasts</strong></p>
<ul>
<li><a href="https://javascriptair.com/">JavaScript Air</a></li>
<li><a href="https://devchat.tv/js-jabber/">JavaScript Jabber</a></li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="in-the-wild">In the Wild</h2>
<p>  This is a list of organizations that are using this style guide. Send us a pull request and we&#39;ll add you to the list.</p>
<ul>
<li><strong>123erfasst</strong>: <a href="https://github.com/123erfasst/javascript">123erfasst/javascript</a></li>
<li><strong>4Catalyzer</strong>: <a href="https://github.com/4Catalyzer/javascript">4Catalyzer/javascript</a></li>
<li><strong>Aan Zee</strong>: <a href="https://github.com/AanZee/javascript">AanZee/javascript</a></li>
<li><strong>Airbnb</strong>: <a href="https://github.com/airbnb/javascript">airbnb/javascript</a></li>
<li><strong>AloPeyk</strong>: <a href="https://github.com/AloPeyk">AloPeyk</a></li>
<li><strong>AltSchool</strong>: <a href="https://github.com/AltSchool/javascript">AltSchool/javascript</a></li>
<li><strong>Apartmint</strong>: <a href="https://github.com/apartmint/javascript">apartmint/javascript</a></li>
<li><strong>Ascribe</strong>: <a href="https://github.com/ascribe/javascript">ascribe/javascript</a></li>
<li><strong>Avant</strong>: <a href="https://github.com/avantcredit/javascript">avantcredit/javascript</a></li>
<li><strong>Axept</strong>: <a href="https://github.com/axept/javascript">axept/javascript</a></li>
<li><strong>Billabong</strong>: <a href="https://github.com/billabong/javascript">billabong/javascript</a></li>
<li><strong>Bisk</strong>: <a href="https://github.com/Bisk/">bisk</a></li>
<li><strong>Brainshark</strong>: <a href="https://github.com/brainshark/javascript">brainshark/javascript</a></li>
<li><strong>CaseNine</strong>: <a href="https://github.com/CaseNine/javascript">CaseNine/javascript</a></li>
<li><strong>Cerner</strong>: <a href="https://github.com/cerner/">Cerner</a></li>
<li><strong>Chartboost</strong>: <a href="https://github.com/ChartBoost/javascript-style-guide">ChartBoost/javascript-style-guide</a></li>
<li><strong>Coeur d&#39;Alene Tribe</strong>: <a href="https://www.cdatribe-nsn.gov">www.cdatribe-nsn.gov</a></li>
<li><strong>ComparaOnline</strong>: <a href="https://github.com/comparaonline/javascript-style-guide">comparaonline/javascript</a></li>
<li><strong>Compass Learning</strong>: <a href="https://github.com/compasslearning/javascript-style-guide">compasslearning/javascript-style-guide</a></li>
<li><strong>DailyMotion</strong>: <a href="https://github.com/dailymotion/javascript">dailymotion/javascript</a></li>
<li><strong>DoSomething</strong>: <a href="https://github.com/DoSomething/eslint-config">DoSomething/eslint-config</a></li>
<li><strong>Digitpaint</strong> <a href="https://github.com/digitpaint/javascript">digitpaint/javascript</a></li>
<li><strong>Drupal</strong>: <a href="https://git.drupalcode.org/project/drupal/blob/8.6.x/core/.eslintrc.json">www.drupal.org</a></li>
<li><strong>Ecosia</strong>: <a href="https://github.com/ecosia/javascript">ecosia/javascript</a></li>
<li><strong>Evolution Gaming</strong>: <a href="https://github.com/evolution-gaming/javascript">evolution-gaming/javascript</a></li>
<li><strong>EvozonJs</strong>: <a href="https://github.com/evozonjs/javascript">evozonjs/javascript</a></li>
<li><strong>ExactTarget</strong>: <a href="https://github.com/ExactTarget/javascript">ExactTarget/javascript</a></li>
<li><strong>Flexberry</strong>: <a href="https://github.com/Flexberry/javascript-style-guide">Flexberry/javascript-style-guide</a></li>
<li><strong>Gawker Media</strong>: <a href="https://github.com/gawkermedia/">gawkermedia</a></li>
<li><strong>General Electric</strong>: <a href="https://github.com/GeneralElectric/javascript">GeneralElectric/javascript</a></li>
<li><strong>Generation Tux</strong>: <a href="https://github.com/generationtux/styleguide">GenerationTux/javascript</a></li>
<li><strong>GoodData</strong>: <a href="https://github.com/gooddata/gdc-js-style">gooddata/gdc-js-style</a></li>
<li><strong>GreenChef</strong>: <a href="https://github.com/greenchef/javascript">greenchef/javascript</a></li>
<li><strong>Grooveshark</strong>: <a href="https://github.com/grooveshark/javascript">grooveshark/javascript</a></li>
<li><strong>Grupo-Abraxas</strong>: <a href="https://github.com/Grupo-Abraxas/javascript">Grupo-Abraxas/javascript</a></li>
<li><strong>Happeo</strong>: <a href="https://github.com/happeo/javascript">happeo/javascript</a></li>
<li><strong>How About We</strong>: <a href="https://github.com/howaboutwe/javascript-style-guide">howaboutwe/javascript</a></li>
<li><strong>HubSpot</strong>: <a href="https://github.com/HubSpot/javascript">HubSpot/javascript</a></li>
<li><strong>Hyper</strong>: <a href="https://github.com/hyperoslo/javascript-playbook/blob/master/style.md">hyperoslo/javascript-playbook</a></li>
<li><strong>ILIAS</strong>: <a href="https://github.com/ILIAS-eLearning/ILIAS">ILIAS</a></li>
<li><strong>InterCity Group</strong>: <a href="https://github.com/intercitygroup/javascript-style-guide">intercitygroup/javascript-style-guide</a></li>
<li><strong>Jam3</strong>: <a href="https://github.com/Jam3/Javascript-Code-Conventions">Jam3/Javascript-Code-Conventions</a></li>
<li><strong>JSSolutions</strong>: <a href="https://github.com/JSSolutions/javascript">JSSolutions/javascript</a></li>
<li><strong>Kaplan Komputing</strong>: <a href="https://github.com/kaplankomputing/javascript">kaplankomputing/javascript</a></li>
<li><strong>KickorStick</strong>: <a href="https://github.com/kickorstick/">kickorstick</a></li>
<li><strong>Kinetica Solutions</strong>: <a href="https://github.com/kinetica/Javascript-style-guide">kinetica/javascript</a></li>
<li><strong>LEINWAND</strong>: <a href="https://github.com/LEINWAND/javascript">LEINWAND/javascript</a></li>
<li><strong>Lonely Planet</strong>: <a href="https://github.com/lonelyplanet/javascript">lonelyplanet/javascript</a></li>
<li><strong>M2GEN</strong>: <a href="https://github.com/M2GEN/javascript">M2GEN/javascript</a></li>
<li><strong>Mighty Spring</strong>: <a href="https://github.com/mightyspring/javascript">mightyspring/javascript</a></li>
<li><strong>MinnPost</strong>: <a href="https://github.com/MinnPost/javascript">MinnPost/javascript</a></li>
<li><strong>MitocGroup</strong>: <a href="https://github.com/MitocGroup/javascript">MitocGroup/javascript</a></li>
<li><strong>Muber</strong>: <a href="https://github.com/muber/">muber</a></li>
<li><strong>National Geographic Society</strong>: <a href="https://github.com/natgeosociety/">natgeosociety</a></li>
<li><strong>NullDev</strong>: <a href="https://github.com/NullDevCo/JavaScript-Styleguide">NullDevCo/JavaScript-Styleguide</a></li>
<li><strong>Nulogy</strong>: <a href="https://github.com/nulogy/javascript">nulogy/javascript</a></li>
<li><strong>Orange Hill Development</strong>: <a href="https://github.com/orangehill/javascript">orangehill/javascript</a></li>
<li><strong>Orion Health</strong>: <a href="https://github.com/orionhealth/javascript">orionhealth/javascript</a></li>
<li><strong>Peerby</strong>: <a href="https://github.com/Peerby/javascript">Peerby/javascript</a></li>
<li><strong>Pier 1</strong>: <a href="https://github.com/pier1/javascript">Pier1/javascript</a></li>
<li><strong>Qotto</strong>: <a href="https://github.com/Qotto/javascript-style-guide">Qotto/javascript-style-guide</a></li>
<li><strong>React</strong>: <a href="https://reactjs.org/docs/how-to-contribute.html#style-guide">reactjs.org/docs/how-to-contribute.html#style-guide</a></li>
<li><strong>Ripple</strong>: <a href="https://github.com/ripple/javascript-style-guide">ripple/javascript-style-guide</a></li>
<li><strong>Sainsbury’s Supermarkets</strong>: <a href="https://github.com/jsainsburyplc">jsainsburyplc</a></li>
<li><strong>Shutterfly</strong>: <a href="https://github.com/shutterfly/javascript">shutterfly/javascript</a></li>
<li><strong>Sourcetoad</strong>: <a href="https://github.com/sourcetoad/javascript">sourcetoad/javascript</a></li>
<li><strong>Springload</strong>: <a href="https://github.com/springload/">springload</a></li>
<li><strong>StratoDem Analytics</strong>: <a href="https://github.com/stratodem/javascript">stratodem/javascript</a></li>
<li><strong>SteelKiwi Development</strong>: <a href="https://github.com/steelkiwi/javascript">steelkiwi/javascript</a></li>
<li><strong>StudentSphere</strong>: <a href="https://github.com/studentsphere/guide-javascript">studentsphere/javascript</a></li>
<li><strong>SwoopApp</strong>: <a href="https://github.com/swoopapp/javascript">swoopapp/javascript</a></li>
<li><strong>SysGarage</strong>: <a href="https://github.com/sysgarage/javascript-style-guide">sysgarage/javascript-style-guide</a></li>
<li><strong>Syzygy Warsaw</strong>: <a href="https://github.com/syzygypl/javascript">syzygypl/javascript</a></li>
<li><strong>Target</strong>: <a href="https://github.com/target/javascript">target/javascript</a></li>
<li><strong>Terra</strong>: <a href="https://github.com/cerner?utf8=%E2%9C%93&amp;q=terra&amp;type=&amp;language=">terra</a></li>
<li><strong>TheLadders</strong>: <a href="https://github.com/TheLadders/javascript">TheLadders/javascript</a></li>
<li><strong>The Nerdery</strong>: <a href="https://github.com/thenerdery/javascript-standards">thenerdery/javascript-standards</a></li>
<li><strong>Tomify</strong>: <a href="https://github.com/tomprats">tomprats</a></li>
<li><strong>Traitify</strong>: <a href="https://github.com/traitify/eslint-config-traitify">traitify/eslint-config-traitify</a></li>
<li><strong>T4R Technology</strong>: <a href="https://github.com/T4R-Technology/javascript">T4R-Technology/javascript</a></li>
<li><strong>UrbanSim</strong>: <a href="https://github.com/urbansim/">urbansim</a></li>
<li><strong>VoxFeed</strong>: <a href="https://github.com/VoxFeed/javascript-style-guide">VoxFeed/javascript-style-guide</a></li>
<li><strong>WeBox Studio</strong>: <a href="https://github.com/weboxstudio/javascript">weboxstudio/javascript</a></li>
<li><strong>Weggo</strong>: <a href="https://github.com/Weggo/javascript">Weggo/javascript</a></li>
<li><strong>Zillow</strong>: <a href="https://github.com/zillow/javascript">zillow/javascript</a></li>
<li><strong>Zit Software</strong>: <a href="https://github.com/zit-software/javascript">zit-software/javascript</a></li>
<li><strong>ZocDoc</strong>: <a href="https://github.com/ZocDoc/javascript">ZocDoc/javascript</a></li>
</ul>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="translation">Translation</h2>
<p>  This style guide is also available in other languages:</p>
<ul>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png" alt="br"> <strong>Brazilian Portuguese</strong>: <a href="https://github.com/armoucar/javascript-style-guide">armoucar/javascript-style-guide</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png" alt="bg"> <strong>Bulgarian</strong>: <a href="https://github.com/borislavvv/javascript">borislavvv/javascript</a></li>
<li><img src="https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png" alt="ca"> <strong>Catalan</strong>: <a href="https://github.com/fpmweb/javascript-style-guide">fpmweb/javascript-style-guide</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png" alt="cn"> <strong>Chinese (Simplified)</strong>: <a href="https://github.com/lin-123/javascript">lin-123/javascript</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png" alt="tw"> <strong>Chinese (Traditional)</strong>: <a href="https://github.com/jigsawye/javascript">jigsawye/javascript</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png" alt="fr"> <strong>French</strong>: <a href="https://github.com/nmussy/javascript-style-guide">nmussy/javascript-style-guide</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png" alt="de"> <strong>German</strong>: <a href="https://github.com/timofurrer/javascript-style-guide">timofurrer/javascript-style-guide</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png" alt="it"> <strong>Italian</strong>: <a href="https://github.com/sinkswim/javascript-style-guide">sinkswim/javascript-style-guide</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png" alt="jp"> <strong>Japanese</strong>: <a href="https://github.com/mitsuruog/javascript-style-guide">mitsuruog/javascript-style-guide</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png" alt="kr"> <strong>Korean</strong>: <a href="https://github.com/ParkSB/javascript-style-guide">ParkSB/javascript-style-guide</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png" alt="ru"> <strong>Russian</strong>: <a href="https://github.com/leonidlebedev/javascript-airbnb">leonidlebedev/javascript-airbnb</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png" alt="es"> <strong>Spanish</strong>: <a href="https://github.com/paolocarrasco/javascript-style-guide">paolocarrasco/javascript-style-guide</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png" alt="th"> <strong>Thai</strong>: <a href="https://github.com/lvarayut/javascript-style-guide">lvarayut/javascript-style-guide</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Turkey.png" alt="tr"> <strong>Turkish</strong>: <a href="https://github.com/eraycetinay/javascript">eraycetinay/javascript</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Ukraine.png" alt="ua"> <strong>Ukrainian</strong>: <a href="https://github.com/ivanzusko/javascript">ivanzusko/javascript</a></li>
<li><img src="https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png" alt="vn"> <strong>Vietnam</strong>: <a href="https://github.com/dangkyokhoang/javascript-style-guide">dangkyokhoang/javascript-style-guide</a></li>
</ul>
<h2 id="the-javascript-style-guide-guide">The JavaScript Style Guide Guide</h2>
<ul>
<li><a href="https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide">Reference</a></li>
</ul>
<h2 id="chat-with-us-about-javascript">Chat With Us About JavaScript</h2>
<ul>
<li>Find us on <a href="https://gitter.im/airbnb/javascript">gitter</a>.</li>
</ul>
<h2 id="contributors">Contributors</h2>
<ul>
<li><a href="https://github.com/airbnb/javascript/graphs/contributors">View Contributors</a></li>
</ul>
<h2 id="license">License</h2>
<p>(The MIT License)</p>
<p>Copyright (c) 2012 Airbnb</p>
<p>Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
&#39;Software&#39;), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:</p>
<p>The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.</p>
<p>THE SOFTWARE IS PROVIDED &#39;AS IS&#39;, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>
<p><strong><a href="#%EB%AA%A9%EC%B0%A8">⬆ 목차</a></strong></p>
<h2 id="amendments">Amendments</h2>
<p>We encourage you to fork this guide and change the rules to fit your team’s style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts.</p>
<h3 id="코딩가이드-참고-사이트">코딩가이드 참고 사이트</h3>
<ul>
<li><a href="https://google.github.io/styleguide/jsguide.html">구글 자바스크립트 가이드</a></li>
<li><a href="https://github.com/airbnb/javascript">Airbnb 스타일 가이드</a></li>
<li><a href="https://github.com/tipjs/javascript-style-guide">Airbnb 스타일 가이드 한글</a></li>
<li><a href="https://ko.javascript.info/coding-style">자바스크립트 코딩 스타일</a></li>
<li><a href="https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html">jsdoc</a></li>
<li><a href="https://dev.to/documatic/a-guide-to-coding-standards-to-improve-code-quality-68n">A Guide to Coding Standards to Improve Code Quality</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[AJAX]]></title>
            <link>https://velog.io/@yedam_it/AJAX</link>
            <guid>https://velog.io/@yedam_it/AJAX</guid>
            <pubDate>Mon, 18 Nov 2024 23:37:54 GMT</pubDate>
            <description><![CDATA[<h2 id="ajax-란">AJAX 란</h2>
<ul>
<li>XMLHttpRequest 기술을 사용하여 동적인 웹페이지 구성하는 프로그래밍 방식</li>
<li>전체 페이지를 다시 로드하지 않고 페이지 일부 DOM만 업데이트</li>
<li>페이지 일부가 로드되는 동안에도 코드가 계속 실행되어 비동기식으로 작업 가능</li>
<li>(mdn)[<a href="https://developer.mozilla.org/ko/docs/Glossary/AJAX%5D">https://developer.mozilla.org/ko/docs/Glossary/AJAX]</a></li>
</ul>
<h2 id="json-라이브러리">JSON 라이브러리</h2>
<ul>
<li>JavaScript : <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a></li>
<li>Java : <a href="https://github.com/FasterXML/jackson">Jackson</a>, google-gson</li>
</ul>
<h3 id="json">JSON</h3>
<pre><code class="language-javascript">let obj = { name:&#39;scott&#39;, age:20 }

// Object -&gt; String
let str = JSON.stringfy(obj);

//String -&gt; Object
let emp = JSON.parse(str); 
</code></pre>
<h3 id="jackson">Jackson</h3>
<h4 id="objectmapper">ObjectMapper</h4>
<pre><code class="language-java">ObjectMapper objectMapper = new ObjectMapper();

// Object -&gt; String
String empAsString objectMapper.writeValueAsString(empVO);

//String -&gt; Object
EmpVO vo = objectMapper.readValue(str, EmpVO.class);</code></pre>
<h4 id="jackson-annotation">Jackson annotation</h4>
<ul>
<li>@RequestBody, @ResponseBody<pre><code class="language-java">public @ResponseBody List&lt;EmpVO&gt; findEmp( @RequestBody EmpVO empVO) {}</code></pre>
</li>
<li>@JsonProperty, @JsonFormat, @JsonIgnore, @JsonIgnoreProperties, @JsonPropertyOrder<pre><code class="language-java">import java.util.Date;
import com.fasterxml.jackson.annotation.*;
import lombok.*;
</code></pre>
</li>
</ul>
<p>@Data @Builder @AllArgsConstructor @NoArgsConstructor
@JsonPropertyOrder({ &quot;lastName&quot;, &quot;firstName&quot;, &quot;salary&quot; })
@JsonIgnoreProperties({&quot;salary&quot;,&quot;dept&quot;})
public class EmpVO {
    private String firstName;</p>
<pre><code>@JsonProperty(&quot;lname&quot;)
private String lastName;

private String dept;
private int salary;

 @JsonFormat(
  shape = JsonFormat.Shape.STRING,
  pattern = &quot;dd-MM-yyyy hh:mm:ss&quot;)
private Date hireDate;

@JsonIgnore 
private int commission; </code></pre><p>}</p>
<p>//
public class JacksonTest {</p>
<pre><code>@Test
public void test() throws JsonProcessingException {
    EmpVO vo = EmpVO.builder().firstName(&quot;scott&quot;)
                   .lastName(&quot;king&quot;)
                   .dept(&quot;개발&quot;)
                   .salary(2000)
                   .hireDate(new Date())
                   .commission(100)
                   .build();
    String str = new ObjectMapper().writeValueAsString(vo);
    System.out.println(str);
}</code></pre><p>}</p>
<pre><code></code></pre><p>{&quot;lname&quot;:&quot;king&quot;,&quot;firstName&quot;:&quot;scott&quot;,&quot;hireDate&quot;:&quot;18-11-2024 11:13:46&quot;}</p>
<pre><code>
## AJAX 라이브러리
- XMLHttpRequest 객체
- Javascript(web api) fetch() 함수
- jQuery $.ajax() 함수
- axios() 함수

### fetch()  VS  $.ajax() 

1. get 방식
```javascript
 fetch(url + &quot;?var=value&quot;).then();

 $.ajax(url + &quot;?var=value&quot;).done();
 $.ajax(url, {data: &quot;var=value&quot;}).done();
 $.ajax(url, {data: {var:&quot;value&quot;}).done();</code></pre><ol start="2">
<li>post(queryString)<pre><code class="language-javascript">//fetch
fetch(url, {method:&#39;post&#39;, body: &quot;fv=val&amp;sv=val&quot; }).then()    
</code></pre>
</li>
</ol>
<p>//jQuery ajax함수
 $.ajax(url, {method:&#39;post&#39;, data: &quot;fv=val&amp;sv=val&quot; }).done()
 $.ajax(url, {method:&#39;post&#39;, data: {&quot;fv&quot;:&quot;val&quot;, &quot;sv&quot;:&quot;val&quot; }  }).done()</p>
<pre><code>3. post(jsonString)
```javascript
 let data = {&quot;fv&quot;:&quot;val&quot;, &quot;sv&quot;:&quot;val&quot; }

 //fetch 함수
 fetch(url, {method: &#39;post&#39;, 
             headers: { &quot;Content-Type&quot;: &quot;application/json&quot;, },
             body: JSON.stringify(data)
       }).then()    

//jQuery ajax함수
 $.ajax(url, {method: &#39;post&#39;, 
              contentType : &quot;application/json&quot;,
              data: JSON.stringify(data)
        }).done()</code></pre><h3 id="ajax-와-spring-연동">ajax 와 spring 연동</h3>
<pre><code class="language-javascript">queryStr = &quot;firstName=scott&amp;lastName=king&quot;
queryStr = &quot;emps[0].firstName=scott&amp;emps[0].lastName=king&amp;emps[1].firstName=scott&amp;emps[1].lastName=king&quot;

jsonStr = {firstName: &#39;scott&#39;, lastName: &#39;king&#39;}
jsonArr = [{firstName:&quot;scott&quot;, lastName:&quot;king&quot;},{firstName:&quot;james&quot;, lastName:&quot;park&quot;}]
</code></pre>
<pre><code class="language-java">public String handler(EmpVO vo) {}                    // query string (Object)
public String handler(ListEmpVO list) {}              // query string (Array) 
public String handler(@RequestBody EmpVO vo) {}       // JSON String (Object)
public String handler(@RequestBody List&lt;EmpVO&gt; vo) {} // JSON String (Array)

</code></pre>
<pre><code class="language-javascript">class ListEmpVO {
  List&lt;EmpVO&gt; emps;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[타자게임]]></title>
            <link>https://velog.io/@yedam_it/%ED%83%80%EC%9E%90%EA%B2%8C%EC%9E%84</link>
            <guid>https://velog.io/@yedam_it/%ED%83%80%EC%9E%90%EA%B2%8C%EC%9E%84</guid>
            <pubDate>Tue, 12 Nov 2024 07:46:35 GMT</pubDate>
            <description><![CDATA[<p>IT용어로 구성된 타자게임 페이지로 이동하려면 [ <a href="https://thinbluebucket.s3.ap-northeast-2.amazonaws.com/tajagame.html?level=1">타자게임</a>  ]클릭하세요</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[jar 배포]]></title>
            <link>https://velog.io/@yedam_it/jar-%EB%B0%B0%ED%8F%AC</link>
            <guid>https://velog.io/@yedam_it/jar-%EB%B0%B0%ED%8F%AC</guid>
            <pubDate>Mon, 11 Nov 2024 19:59:02 GMT</pubDate>
            <description><![CDATA[<h3 id="프로퍼티-파일-지정">프로퍼티 파일 지정</h3>
<ul>
<li><p>application.properties</p>
<pre><code>server.port=8080
server.servlet.context-path=/test</code></pre></li>
<li><p>application-dev.properties</p>
<pre><code>server.port=80
server.servlet.context-path=/</code></pre><h3 id="로컬에서-빌드하기">로컬에서 빌드하기</h3>
<ul>
<li><p>이클립스에서 실행하는 경우 </p>
<ol>
<li>프로젝트 컨텍스트메뉴  =&gt;  run as  =&gt;  maven install  </li>
<li>target폴더에 jar파일 생성됨 (war)</li>
</ol>
</li>
<li><p>cmd 창에서 실행</p>
<pre>
c:\dev\프로젝트경로> mvn install
                   mvn clean package
                   mvn install -DskipTests   
</pre>
<h3 id="서버에-jdk-설치ec2">서버에 jdk 설치(EC2)</h3>
</li>
</ul>
</li>
</ul>
<ol>
<li><p>자바 설치 가능 리스트 검색</p>
<pre><code class="language-bash">$ sudo yum list java*</code></pre>
</li>
<li><p>jdk(Amazon Corretto OpenJDK) 설치</p>
<pre><code class="language-bash">$ sudo yum install -y java-17-amazon-corretto.x86_64
$ java -version
$ echo $JAVA_HOME</code></pre>
</li>
<li><p>자바 설치 경로 확인 (선택)</p>
<pre><code class="language-bash">$ whhich java
$ readlink -f /usr/bin/java               </code></pre>
</li>
<li><p>환경변수 설정 (선택)</p>
<pre><code class="language-bash">$ sudo vi /etc/profile  </code></pre>
<p>Shift+g(마지막줄로 이동) =&gt; o(입력모드) =&gt; 아래의 export정보 입력 =&gt; esc =&gt; :wq</p>
</li>
</ol>
<pre><code>export JAVA_HOME=/usr/lib/jvm/java-17-amazon-corretto.x86_64
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar   &lt;== 확인</code></pre><pre><code class="language-bash">  $ sudo source /etc/profile</code></pre>
<h3 id="실행">실행</h3>
<ul>
<li><p>default 프로퍼티 실행</p>
<pre><code>$ java -jar project.jar</code></pre><pre>
http://ip주소:8080/test/custList
</pre>
</li>
<li><p>dev 프로퍼티 실행</p>
<pre><code>$ sudo java -jar project.jar --spring.profiles.active=dev
                &lt;== 80포트는 관리자 권한으로 실행해야 함.</code></pre><pre>
http://ip주소/custList
</pre>
</li>
<li><p>백그라운드 실행</p>
<pre><code class="language-bash">java -jar project.jar --spring.profiles.active=dev  &amp;
</code></pre>
</li>
</ul>
<pre><code>
-- 프로세스 확인하고 중지
```bash
$ ps -ef | grep java
$ sudo kill -9 pid</code></pre><ul>
<li>로그파일 지정<pre><code class="language-bash">java -jar project.jar --spring.profiles.active=dev &gt;&gt; /home/ec2-user/logs/tomcat.log 2&gt;&amp;1 &amp;
</code></pre>
</li>
</ul>
<pre><code>
- 실시간 로그 보기
```bash
$ tail -f tomcat.log</code></pre><ul>
<li>무중단 실행(로그아웃하고 세션이 끊어져도 계속 실행)<pre><code class="language-bash">$ nohup  java -jar project.jar --spring.profiles.active=dev &gt;&gt; /home/ec2-user/logs/tomcat.log 2&gt;&amp;1 &amp;</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[로깅 라이브러리(Logging Library)]]></title>
            <link>https://velog.io/@yedam_it/%EB%A1%9C%EA%B9%85-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%ACLogging-Library</link>
            <guid>https://velog.io/@yedam_it/%EB%A1%9C%EA%B9%85-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%ACLogging-Library</guid>
            <pubDate>Mon, 11 Nov 2024 18:00:40 GMT</pubDate>
            <description><![CDATA[<h2 id="로깅-라이브러리">로깅 라이브러리</h2>
<ul>
<li><p>로깅(logging)이란 시스템 동작시 시스템의 상태와 작동 정보를 시간의 경과에 따라 기록하는 것</p>
</li>
<li><p>System.out.println()을 사용하지 말고 log.XXX() 이용할 것</p>
<ol>
<li>로그 출력위치(클래스, 메서드, 라인번호)를 알수 있고</li>
<li>출력 형식을 지정할 수 있으며</li>
<li>성능면에서 훨씬 뛰어남.</li>
</ol>
</li>
<li><p>등장 순서</p>
<pre>
java.util.logging  ==>  Log4j  ==>  Logback   ==>  Log4j2
                       spring      springboot       최신
</pre>
</li>
<li><p><a href="https://logback.qos.ch">Logback</a></p>
</li>
</ul>
<h2 id="로그-설정-위치">로그 설정 위치</h2>
<p>Spring이나 일반 java 프로그램의 경우 logback.xml 파일을 resources 디렉터리에 만들어서 참조하지만 Spring Boot의 경우에는 아래 3가지 중 한 가지 방법을 선택합니다.</p>
<ol>
<li>application.properties에 설정</li>
</ol>
<pre><code>logging.pattern=[%thread] %highlight(%-5level) %cyan(%logger{15}) -%kvp -%msg %n
logging.level.com.yedam.app=debug
logging.level.root=info</code></pre><ol start="2">
<li><p>resources/logback-spring.xml에 설정</p>
</li>
<li><p>resources/logback.xml에 설정</p>
</li>
</ol>
<pre><code class="language-xml">  &lt;appender name=&quot;STDOUT&quot; class=&quot;ch.qos.logback.core.ConsoleAppender&quot;&gt;
    &lt;withJansi&gt;true&lt;/withJansi&gt;
    &lt;encoder&gt;
      &lt;pattern&gt;[%thread] %highlight(%-5level) %cyan(%logger{15}) -%kvp -%msg %n&lt;/pattern&gt;
    &lt;/encoder&gt;
  &lt;/appender&gt;
  &lt;logger name=&quot;com.yedam.app&quot; level=&quot;DEBUG&quot; /&gt;
  &lt;root level=&quot;DEBUG&quot;&gt;
    &lt;appender-ref ref=&quot;STDOUT&quot; /&gt;
  &lt;/root&gt;</code></pre>
<p>log에 대한 세부적인 설정을 하려면 logback.xml 파일을 통한 설정이 필요하고, 간단하게 콘솔 로그만 확인하기 위해서는 application.properties (또는 .yml) 파일에 로그 레벨을 설정하는 것만으로 로그를 확인할 수 있습니다.</p>
<h3 id="로그레벨">로그레벨</h3>
<pre>
     TRACE   >   DEBUG   >   INFO   >   WARN   >   ERROR   >   FATAL   >   OFF
</pre>

<ul>
<li>trace : 아주 자세한 로그 출력</li>
<li>debug : DEV 환경에서 디버깅 하기 위해 사용</li>
<li>warn : PROD 환경에서 사용. 향후에 에러가 될 수 있는 경고성 로그 표시</li>
<li>error : 요청을 처리하는 중 오류 발생한 경우 표시</li>
<li>fatal : 심각한 오류 로그 출력</li>
<li>off : 로그 출력 안함</li>
</ul>
<h3 id="logback-로그-패턴">Logback 로그 패턴</h3>
<p>%d: 날짜와 시간(yyyy-MM-dd HH:mm:ss.SSS.)
%p: 로그 레벨
%-5level: 로그 레벨, -5는 출력의 고정폭 값(5글자)
%logger{36}: 로그네임(className)를 나타냅니다.(36글자)
%c: 로그를 출력하는 클래스의 이름을 나타냅니다.
%C: 로그를 출력하는 클래스의 간결한 이름(패키지명 없이)을 나타냅니다.
%M: 로그를 출력하는 메서드의 이름을 나타냅니다.
%L: 로그를 출력하는 코드 라인 번호를 나타냅니다.
%m: 로그 메시지 자체를 나타냅니다.
%n: 개행 문자를 나타냅니다.</p>
<h3 id="로깅">로깅</h3>
<p>💡 Spring Boot Logging</p>
<ul>
<li>spring-boot-start-web 안에 spring-boot-starter-logging에 구현체가 있습니다.</li>
<li>Spring Boot에는 내장으로 ‘jul(java.util.logging)’ 로깅 프레임워크가 내장되어 있어서 이를 즉시 사용할 수 있습니다.</li>
</ul>
<p>💡 Lombok</p>
<ul>
<li>Lombok 내에 Slf4j가 포함되어 있어서 기존의 Logger를 선언해서 사용하는 방식외에 @Slf4J Annotaion을 이용하여서 간편하게 사용이 가능합니다.</li>
</ul>
<pre><code class="language-java">@Slf4J         //Logger static log 필드가 추가됨
public class XXXX { }</code></pre>
<h2 id="logback을-log4j2로-변경">Logback을 Log4j2로 변경</h2>
<p>spring boot에서 log4j2를 사용하기 위해서는 dependency에서 logback을 제거해주는 작업이 필요합니다.
스프링 부트는 기본 설정으로 logback을 사용하기 때문에 log4j2 의존성을 추가하더라도 기본 설정으로 잡힌 logback이 동작하게 됩니다.</p>
<h2 id="스프링-로깅-동작과정">스프링 로깅 동작과정</h2>
<h3 id="spring-frameworklog4j">spring framework(Log4j)</h3>
<ul>
<li><p>Log4j 구현체 사용
JCL(Jakarta Common Logging 인터페이스)
==&gt; Log4j(JCL 구현체)</p>
</li>
<li><p>log4j2 구현체 사용
JCL(Jakarta Common Logging 인터페이스)
==&gt; jcl-over-slf4j(어댑터)
==&gt; SLF4J(인터페이스)
==&gt; slf4j-log4j(브릿지)
==&gt; log4j2 (slf4j 구현체)</p>
</li>
</ul>
<h3 id="spring-boot-logback">spring boot (Logback)</h3>
<p>-&gt; log4j-to-slf4j(어댑터)
-&gt; SLF4J(인터페이스)
-&gt; Logback(slf4j 구현체)</p>
<p>spring-boot starter-logging
logback-classic
log4j-to-slf4j
jul-to-slf4j(브릿지)</p>
<h3 id="slf4j-simple-logging-facade-for-java">slf4j (Simple Logging Facade For Java)</h3>
<p>slf4j는 자바 로깅 시스템을 쉽게 사용할 수 있도록 해주는 라이브러리이며, 다양한 자바 로깅 시스템을 사용할 수 있도록 파사드 패턴(facade pattern) 및 추상화를 통해 로깅 기능을 제공합니다.
slf4j를 사용함으로서 얻을 수 있는 이점은 기존에 사용하는 로깅 시스템을 교체하고 싶을 때, 소스 코드를 수정하지 않고도 maven이나 gradle의 의존성 설정만 바꾸면 손쉽게 적용할 수 있습니다.</p>
<h3 id="파사드facade-pattern">파사드(Facade pattern)</h3>
<p>복잡한 서브 시스템을 단순한 인터페이스를 제공하여 제어하는 방식.
클라이언트는 복잡한 서브 시스템에 대해 알 필요가 없으며, Facade를 통해 일괄적으로 제어가능하다.
단순한고 일관된 통합 인터페이스르 제공</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 키워드]]></title>
            <link>https://velog.io/@yedam_it/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%82%A4%EC%9B%8C%EB%93%9C</link>
            <guid>https://velog.io/@yedam_it/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%82%A4%EC%9B%8C%EB%93%9C</guid>
            <pubDate>Mon, 11 Nov 2024 15:41:21 GMT</pubDate>
            <description><![CDATA[<ol>
<li><p>arguments</p>
</li>
<li><p>await</p>
</li>
<li><p>break</p>
</li>
<li><p>case</p>
</li>
<li><p>catch</p>
</li>
<li><p>const</p>
</li>
<li><p>debugger</p>
</li>
<li><p>default</p>
</li>
<li><p>delete</p>
</li>
<li><p>do</p>
</li>
<li><p>else</p>
</li>
<li><p>enum</p>
</li>
<li><p>eval</p>
</li>
<li><p>export</p>
</li>
<li><p>false</p>
</li>
<li><p>finally</p>
</li>
<li><p>for</p>
</li>
<li><p>function</p>
</li>
<li><p>if</p>
</li>
<li><p>import</p>
</li>
<li><p>in</p>
</li>
<li><p>Infinity</p>
</li>
<li><p>instanceof</p>
</li>
<li><p>let</p>
</li>
<li><p>NaN</p>
</li>
<li><p>null</p>
</li>
<li><p>return</p>
</li>
<li><p>switch</p>
</li>
<li><p>this</p>
</li>
<li><p>throw</p>
</li>
<li><p>true</p>
</li>
<li><p>typeof</p>
</li>
<li><p>undefined</p>
</li>
<li><p>var</p>
</li>
<li><p>void</p>
</li>
<li><p>while</p>
</li>
<li><p>yield</p>
</li>
<li><p>class</p>
</li>
<li><p>extends</p>
</li>
<li><p>implements</p>
</li>
<li><p>interface</p>
</li>
<li><p>package</p>
</li>
<li><p>public</p>
</li>
<li><p>private</p>
</li>
<li><p>protected</p>
</li>
<li><p>static</p>
</li>
<li><p>super</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 event]]></title>
            <link>https://velog.io/@yedam_it/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-event</link>
            <guid>https://velog.io/@yedam_it/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-event</guid>
            <pubDate>Mon, 11 Nov 2024 15:26:33 GMT</pubDate>
            <description><![CDATA[<h2 id="이벤트-핸들러-등록">이벤트 핸들러 등록</h2>
<p>참고사이트 : <a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Building_blocks/Events">MDN Web Docs 이벤트 입문</a></p>
<h3 id="1-html-태그에-인라인-이벤트-핸들러-등록">1. HTML 태그에 인라인 이벤트 핸들러 등록</h3>
<pre><code class="language-javascript">&lt;input type=&quot;button&quot; onclick=&quot;doProcess()&quot;/&gt;

&lt;script&gt;
function doProcess() {   }
&lt;/script&gt;
</code></pre>
<ul>
<li>html과 javascript 코드 분리해야함. 이 방식은 사용을 자제해야 함</li>
<li>function(){ doProcess(); } 와 같은 구조임. 함수호출이므로 ( )가 필요함</li>
<li>react, vue에서는 인라인 이벤트 핸들러 사용해야 함.</li>
</ul>
<h3 id="2-자바스크립트에서-이벤트-핸들러-프로퍼티-지정">2. 자바스크립트에서 이벤트 핸들러 프로퍼티 지정</h3>
<pre><code class="language-javascript">&lt;input type=&quot;button&quot; id=&quot;btn1&quot;/&gt;

&lt;script&gt;
function doProcess() {  }
var btn1 = document.getElementById(&quot;btn1&quot;);

btn.onclick = doProcess;          //함수참조: ()를 붙히지 않음
btn.onclick = function(){   }     //익명함수
btn.onclick = () =&gt; {  }          //화살표함수
&lt;/script&gt;</code></pre>
<ul>
<li>이벤트 핸들러를 하나만 지정할 수 있음</li>
</ul>
<h3 id="3-이벤트-리스너-방식-처리">3. 이벤트 리스너 방식 처리</h3>
<pre><code class="language-javascript">&lt;script&gt;
function doProcess() { }
function doClickOnBtn1() { }

var btn1 = document.getElementById(&quot;btn1&quot;);

btn1.addEventListener(&quot;click&quot;, doProcess, false);
btn1.addEventListener(&quot;click&quot;, doClickOnBtn1,false);</code></pre>
<h2 id="이벤트-흐름">이벤트 흐름</h2>
<ul>
<li>이벤트흐름 3단계 : 캡쳐링 -&gt; 대상 -&gt; 버블링</li>
</ul>
<pre><code class="language-javascript">&lt;div id=&quot;grand&quot; style=&quot;border:1px solid #333&quot;&gt;grand의 상단
    &lt;div id=&quot;parent&quot; style=&quot;border:1px solid red&quot;&gt;parent의 상단
        &lt;div id=&quot;child&quot; style=&quot;border:1px solid blue&quot;&gt;child
        &lt;/div&gt; 
         parent의 하단
    &lt;/div&gt;
     grand의 하단
&lt;/div&gt;
&lt;script&gt;
window.onload = function() {
var grand = document.getElementById(&quot;grand&quot;);
var parent = document.getElementById(&quot;parent&quot;);
var child = document.getElementById(&quot;child&quot;);

ajax.Event.addListener(grand, &quot;mousedown&quot;, grandHandler, false);
ajax.Event.addListener(parent, &quot;mousedown&quot;, parentHandlerCapture, true);
ajax.Event.addListener(parent, &quot;mousedown&quot;, parentHandler, false);
ajax.Event.addListener(child, &quot;mousedown&quot;, childHandler, false);
}
&lt;/script&gt;</code></pre>
<ul>
<li>이벤트 전파(propagation)  / 중지</li>
</ul>
<pre><code class="language-javascript">event.stopPropagation();</code></pre>
<ul>
<li>기본 이벤트 전파 중지</li>
</ul>
<pre><code class="language-javascript">event.preventDefault();</code></pre>
<h2 id="이벤트-개요">이벤트 개요</h2>
<ul>
<li><p>event 종류</p>
</li>
<li><p>event 객체</p>
<ul>
<li>이벤트 발생시킨 대상이 누구인지, 또는  이벤트의 발생 위치가 어떻게 되는지 정보를 구하기 위해서는 이벤트 객체를 먼저 구해야한다.</li>
<li>KeyboardEvent(keyCode), MouseEvent(clientX, clientY)</li>
</ul>
</li>
</ul>
<pre><code class="language-javascript">function doClickOnBtn1(e) {
   var e = window.event || e;
   var target = e.target;       //이벤트타캣
   log(&quot;이벤트 대상: &quot; + target.nodeName);
   log(&quot;대상의 ID: &quot; + target.id);

   log(&quot;이벤트 타입: &quot; + e.event.type);
}</code></pre>
<ul>
<li><p>event 타겟</p>
</li>
<li><p>리스너(핸들러)</p>
</li>
<li><p>그룹이벤트(이벤트위임)</p>
</li>
<li><p>이벤트핸들러에서 this</p>
<ul>
<li>apply, call, bind : 함수를 직접 호출하지 않고 apply(), call() 함수를 사용해서 호출하면 첫 번째 인자가 함수 내에서 this 객체로 매핑</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터베이스 모델링]]></title>
            <link>https://velog.io/@yedam_it/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EB%AA%A8%EB%8D%B8%EB%A7%81</link>
            <guid>https://velog.io/@yedam_it/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EB%AA%A8%EB%8D%B8%EB%A7%81</guid>
            <pubDate>Mon, 11 Nov 2024 07:15:48 GMT</pubDate>
            <description><![CDATA[<h2 id="논리명-추출">논리명 추출</h2>
<ol>
<li>Tools 메뉴 -&gt; Data Brower 메뉴</li>
<li>File 메뉴 -&gt; New Report 메뉴<ul>
<li>Name :  report (레포트이름 입력)</li>
<li>Category : Logical 선택하고 드랍다운 메뉴에서 Attribute 선택</li>
<li>Options 탭 : Name 체크<pre><code>        Table -&gt; Name 체크</code></pre></li>
<li>OK 버튼              </li>
</ul>
</li>
<li>생성된 레포트를 더블클릭하여 execute 하면 하위 실행 레포트가 생성</li>
<li>실행된 레포트에 마우스오른쪽 버튼 클릭하고 Export Result set 메뉴 선택</li>
<li>Export 형식은 CSV 선택하고 Export... 버튼 클릭</li>
<li>저장위치 지정</li>
</ol>
<h2 id="속성분리">속성분리</h2>
<h2 id="물리명-지정">물리명 지정</h2>
<h2 id="용어사전-만들기">용어사전 만들기</h2>
<h2 id="물리명-적용">물리명 적용</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[springboot 프로젝트]]></title>
            <link>https://velog.io/@yedam_it/springboot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@yedam_it/springboot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Sun, 10 Nov 2024 16:48:31 GMT</pubDate>
            <description><![CDATA[<h3 id="로컬-개발-운영-환경에-맞게-프로파일-분리">로컬, 개발, 운영 환경에 맞게 프로파일 분리</h3>
<ol>
<li>개발환경</li>
</ol>
<ul>
<li>local(로컬 개발환경) : 각 개발자 PC에서 개발 및 테스트 환경 설정</li>
<li>dev(서버 개발환경) : 개발자들이 만든 코드를 통합하여 테스트 할 수 있는 서버 환경</li>
<li>production(운영 환경) : 실제 서비스를 운영하는 환경</li>
</ul>
<ol start="2">
<li><p>개발환경에 맞게 프로퍼티 파일 준비
application.properties
application-dev.properties
application-prod.properties</p>
</li>
<li><p>적용할 프로퍼티 지정</p>
</li>
</ol>
<ul>
<li><p>application.properties 파일에 활성 프로파일을 dev로 지정</p>
<pre><code>spring.profiles.active=dev</code></pre></li>
<li><p>실행할 때 active 프로퍼티 지정</p>
<pre><code class="language-java">java -jar  XXX.jar                              // application.properties 적용됨
java -jar -Dspring.profiles.active=dev XXX.jar  // application-dev.properties 적용됨</code></pre>
</li>
<li><p>.gitignore에 *.properties 추가</p>
</li>
</ul>
<h3 id="외부-경로의-리소스업로드폴더-접근">외부 경로의 리소스(업로드폴더) 접근</h3>
<pre><code class="language-java">import java.util.concurrent.TimeUnit;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class ResourceConfiguration implements WebMvcConfigurer {

    @Value(&quot;${file.uploadpath}&quot;)
    String uploadpath;

    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {

        registry.addResourceHandler(&quot;/img/**&quot;)
        .addResourceLocations(&quot;file://&quot; + uploadpath + &quot;/&quot;)      

        // 접근 파일 캐싱 시간 
    .setCacheControl(CacheControl.maxAge(1, TimeUnit.MINUTES));
    }
}</code></pre>
<h3 id="log4jdbc-설정">log4jdbc 설정</h3>
<ol>
<li><p>log4jdbc 의존성 추가</p>
<pre><code class="language-xml"> &lt;!-- log4jdbc --&gt;
&lt;dependency&gt;
     &lt;groupId&gt;org.bgee.log4jdbc-log4j2&lt;/groupId&gt;
     &lt;artifactId&gt;log4jdbc-log4j2-jdbc4.1&lt;/artifactId&gt;
     &lt;version&gt;1.16&lt;/version&gt;
 &lt;/dependency&gt;</code></pre>
</li>
<li><p>데이터소스 driver-class-name과 url 수정
application.properties 파일 수정</p>
</li>
</ol>
<ul>
<li>변경전<pre><code>spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe</code></pre></li>
<li>변경후<pre><code class="language-peoperties">spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521:xe</code></pre>
</li>
</ul>
<ol start="3">
<li>log4jdbc.log4j2.properties 파일 생성<ul>
<li>src/main/resources 폴더에 파일 생성하고 아래의 내용 작성<pre><code>log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator</code></pre></li>
</ul>
</li>
</ol>
<ol start="4">
<li>log레벨 설정
application.properties 파일 수정<pre><code>logging.level.jdbc.sqlonly=OFF
logging.level.jdbc.sqltiming=DEBUG
logging.level.jdbc.audit=OFF
logging.level.jdbc.resultset=OFF
logging.level.jdbc.resultsettable=DEBUG
logging.level.jdbc.connection=OFF
</code></pre></li>
</ol>
<pre><code>
5. 테스트 매퍼 
```java
import java.util.Map;
import org.apache.ibatis.annotations.Select;

public interface TestMapper {
    @Select(&quot;select ${col1}, #{col2} as col2 from dual&quot;)
    public Map&lt;String,Object&gt; test(String col1, String col2);
}</code></pre><ol start="6">
<li>junit 테스트<pre><code class="language-java">import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
</code></pre>
</li>
</ol>
<p>import com.yedam.app.emp.mapper.TestMapper;</p>
<p>@SpringBootTest
public class TestMapperClient {</p>
<pre><code>@Autowired TestMapper testMapper;
@Test
public void tes() {
    String col = &quot;scott&quot;;
    Map&lt;String, Object&gt; map = testMapper.test(&quot;sysdate&quot;, col);
    assertEquals(col, (String)map.get(&quot;col&quot;));
}</code></pre><p>}</p>
<pre><code>
7. 적용전과 후를 비교
![](https://velog.velcdn.com/images/yedam_it/post/34fd9f27-d012-4ff9-a678-c4d5549f08d0/image.png)


### security 설정
```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public PasswordEncoder bcryptPassword() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((requests) -&gt; requests.antMatchers(&quot;/home&quot;, &quot;/&quot;).permitAll().antMatchers(&quot;/admin/**&quot;)
                .hasAuthority(&quot;ROLE_ADMIN&quot;)
                //.anyRequest().authenticated()
                .anyRequest().permitAll()
                )
                .formLogin(login -&gt; login.defaultSuccessUrl(&quot;/home&quot;).loginPage(&quot;/login&quot;).usernameParameter(&quot;userid&quot;)
                        .permitAll())
                .logout().logoutUrl(&quot;/logout&quot;).logoutSuccessUrl(&quot;/home&quot;).permitAll()
        // .and()
        // .csrf().disable();
        ;
        return http.build();
    }


    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -&gt; web.ignoring().antMatchers(&quot;/images/**&quot;, &quot;/js/**&quot;, &quot;/css/**&quot;);
    }
}</code></pre><h3 id="프로퍼티-파일-암호화">프로퍼티 파일 암호화</h3>
<h4 id="1-라이브러리-추가">1. 라이브러리 추가</h4>
<pre><code class="language-xml">&lt;dependency&gt;
        &lt;groupId&gt;com.github.ulisesbocchio&lt;/groupId&gt;
        &lt;artifactId&gt;jasypt-spring-boot-starter&lt;/artifactId&gt;
        &lt;version&gt;3.0.5&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<h4 id="2-빈등록">2. 빈등록</h4>
<pre><code class="language-java">@Configuration
public class JasyptConfig {

    @Bean(name = &quot;jasyptStringEncryptor&quot;)   //    복호화할 때 사용할 빈
    public StringEncryptor stringEncryptor() {
    String jasyptkey = System.getenv(&quot;jasyptkey&quot;);
        final String key = jasyptkey;
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(key);
        config.setAlgorithm(&quot;PBEWithMD5AndDES&quot;);
        config.setPoolSize(&quot;1&quot;);
        encryptor.setConfig(config);
        return encryptor;
    }
}</code></pre>
<h4 id="3-암호화">3. 암호화</h4>
<pre><code class="language-java">public class JasyptTest {

  @Test
  public void testpass(){
    String encodedPass = encPass(&quot;db&quot;);   
    System.out.println(encodedPass);
  }

  public String encPass(String rawPass){
    String jasyptkey = System.getenv(&quot;jasyptkey&quot;);     //암호화할 때 사용할 키는 실행할 때 외부에서 주입
    StandardPBEStringEncryptor standardPBEStringEncryptor = new StandardPBEStringEncryptor();
    standardPBEStringEncryptor.setAlgorithm(&quot;PBEWithMD5AndDES&quot;);
    standardPBEStringEncryptor.setPassword(jasyptkey);             
    String encodedPass = standardPBEStringEncryptor.encrypt(rawPass); 
    return encodedPass;
  }
}</code></pre>
<h4 id="4-properties-파일에-패스워드-암호화된-값으로-변경">4. properties 파일에 패스워드 암호화된 값으로 변경</h4>
<pre><code class="language-java">jasypt.encryptor.bean=jasyptStringEncryptor
  db.username=ENC(X3XXXX==)
  db.password=ENC(eGXXXX==)</code></pre>
<h4 id="5-run-configuration에서-enviroment-추가">5. run configuration에서 enviroment 추가</h4>
<pre><code>name: jasyptkey  value: 사용할 키</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[springboot 어노테이션]]></title>
            <link>https://velog.io/@yedam_it/springboot</link>
            <guid>https://velog.io/@yedam_it/springboot</guid>
            <pubDate>Sun, 10 Nov 2024 16:47:22 GMT</pubDate>
            <description><![CDATA[<h2 id="springboot-버전">springboot 버전</h2>
<pre>
springboot    3.2.9   <==   3.2.0  <==  2.7.18
    spring    6.1.12  <==   5      <==  5
   mybatis    3.5.14  <==   3.0.3  <==  2.3.2
      java    21      <==   17     <==  11
</pre>

<h2 id="springboot-annotation">springboot annotation</h2>
<ul>
<li>@EnableAutoConfiguration</li>
<li>@EnableWebMvc</li>
<li>@SpringBootApplication</li>
<li>@Configuration</li>
<li>@PropertySource, @ConfigurationProperties, @Value</li>
<li>@ComponentScan, @Component</li>
<li>@Bean, @Required, @Singletone, @Lazy</li>
<li>@Autowired, @Inject, @Qualifier, @Resource</li>
<li>@PostConstruct, @PreConstruct, @PreDestory</li>
<li>@RestController, @Controller, @Service, @Repository</li>
<li>@CrossOrign</li>
<li>@ExceptionHandler</li>
<li>@ControllerAdvice, @RestControllerAdvice</li>
<li>@RequestMapping, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping</li>
<li>@CookieValue</li>
<li>@Valid, @InitBinder</li>
<li>@PathVariable</li>
<li>@RequestAttribute, @RequestHeader, @RequestParam, @RequestPart, @RequestBody</li>
<li>@ModelAttribute, @SessionAttributes</li>
<li>@ResponseBody, @ResponseStatus</li>
<li>@Transactional</li>
<li>@Cacheable, @CachePut, @CacheEvent, @CacheConfig</li>
</ul>
<h3 id="aop-anotation">AOP Anotation</h3>
<ul>
<li>@Aspect</li>
<li>@Pointcut</li>
<li>@Before, @After, @Around, @AfterRetruning, @AfterThrowing</li>
</ul>
<h3 id="jpa-annotation">JPA Annotation</h3>
<ul>
<li>@Entity</li>
<li>@Table</li>
<li>@Id, @GeneratedValue</li>
<li>@column</li>
<li>@OneToMany</li>
<li>@ManyToOne</li>
</ul>
<h3 id="java-bean-validation-annotation">Java Bean Validation Annotation</h3>
<ul>
<li>@NotBlank, @Null, @NotNull</li>
<li>@NotEmpty</li>
<li>@Email</li>
<li>@Min, @Max</li>
<li>@Digits, @Positive, @PositiveOrZero, @Negative, @NegativeOrZero</li>
<li>@Future, @futureOrPresent, @Past, @PastOrPresent</li>
</ul>
<h3 id="swagger-annotation">Swagger Annotation</h3>
<ul>
<li>@Tag</li>
<li>@Operation</li>
<li>@Parameter</li>
<li>@ApiResponse</li>
<li>@Schema</li>
<li>@ApiModelProperty</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MyBatis 프로시저와 TypeHandler]]></title>
            <link>https://velog.io/@yedam_it/MyBatis-procedure</link>
            <guid>https://velog.io/@yedam_it/MyBatis-procedure</guid>
            <pubDate>Sun, 10 Nov 2024 16:35:07 GMT</pubDate>
            <description><![CDATA[<h3 id="1-filevo">1. FileVO</h3>
<pre><code class="language-java">@Data
public class FileVO {
    private String userid;
    private String filename;
    private String filetype;
}</code></pre>
<h3 id="2-uservo">2. UserVO</h3>
<pre><code class="language-java">@Data
public class UserVO{
    private String userid;
    private String name;
    private String[] hobby;
    private List&lt;FileVO&gt; files;
}</code></pre>
<p>String[] 타입과 List&lt;VO&gt; 타입의 파라미터 전달</p>
<h3 id="3-oraclearrayhandler">3. OracleArrayHandler</h3>
<pre><code class="language-java">public class OracleArrayHandler implements TypeHandler&lt;Object&gt; {
  @Override
  public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
    OracleConnection conn = ps.getConnection().unwrap(OracleConnection.class);         
    Array reportsArray = (Array)conn.createOracleArray(&quot;STRINGARRAY&quot;, (String[])parameter);        
    ps.setArray(i, reportsArray);
  }</code></pre>
<h3 id="4-mapper-xml과-인터페이스">4. mapper xml과 인터페이스</h3>
<pre><code class="language-xml">    &lt;insert id=&quot;insertUser&quot; statementType=&quot;CALLABLE&quot;&gt;
    call insert_user(
          #{userid},
          #{name},
          #{hobby, typeHandler=com.yedam.app.OracleArrayHandler},
          #{files, typeHandler=com.yedam.app.OracleArrayStructHandler}
        )
    &lt;/insert&gt;    

    public void insertUser(UserVO vo);</code></pre>
<h3 id="5-테스트파일">5. 테스트파일</h3>
<pre><code class="language-java">@SpringBootTest
public class UserMapperTest {

    @Autowired 
    UserMapper userMapper;

    @Test
    public void testStruct() {
        UserVO vo = new UserVO();
        vo.setUserid(&quot;9999&quot;);
        vo.setName(&quot;test&quot;);
        vo.setHobby(new String[] {&quot;read&quot;,&quot;ski&quot;});
        vo.setFiles(List.of(new FileVO(&quot;test1&quot;,&quot;jpg&quot;),
                            new FileVO(&quot;test2&quot;,&quot;pdf&quot;)));
        userMapper.insertUser(vo);    
    }
}</code></pre>
<h3 id="6-오라클-타입-생성">6. 오라클 타입 생성</h3>
<pre><code class="language-sql">create or replace type STRINGARRAY as table of varchar2(30);


create or replace TYPE FILETYPE AS OBJECT 
(   USERID VARCHAR2(20),
    FILENAME    VARCHAR2(20),
    TYPE    VARCHAR2(20)
);

create or replace type fileArray as table of FILETYPE;</code></pre>
<h3 id="7-procedure">7. procedure</h3>
<pre><code class="language-sql">create or replace PROCEDURE INSERT_USER 
(
    p_userid VARCHAR,
    p_name VARCHAR,
    p_hobby STRINGARRAY,
    p_files FILEARRAY 
) AS 
BEGIN
    --profile 등록

    --hobby (String[]) 등록
    for i in 1..p_hobby.count loop
        insert into hobbys values (p_userid, p_hobby(i));
    end loop;

    --file (List&lt;FileVO&gt;) 등록
     for i in 1..p_files.count loop
        insert into files values (p_userid, p_files(i).filename, p_files(i).filetype);
    end loop;

END INSERT_USER;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript VS jQuery]]></title>
            <link>https://velog.io/@yedam_it/JavaScript-VS-jQuery</link>
            <guid>https://velog.io/@yedam_it/JavaScript-VS-jQuery</guid>
            <pubDate>Sun, 10 Nov 2024 15:54:30 GMT</pubDate>
            <description><![CDATA[<h2 id="자바스크립트-기능">자바스크립트 기능</h2>
<ol>
<li>DOM api</li>
<li>AJAX</li>
<li>validation</li>
</ol>
<h2 id="dom-api">DOM api</h2>
<table>
<thead>
<tr>
<th align="left">분류</th>
<th align="left">자바스크립트</th>
<th align="left">jquery</th>
</tr>
</thead>
<tbody><tr>
<td align="left">요소선택</td>
<td align="left">document.getElementById(&quot;div&quot;)</td>
<td align="left">$(&quot;#div&quot;)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.getElementsByTagName(&quot;div&quot;)</td>
<td align="left">$(&quot;div&quot;)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.getElementsByName(&quot;div&quot;)</td>
<td align="left">$(&quot;[name=&#39;div&#39;]&quot;)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.getElementsByClassName(&quot;div&quot;)</td>
<td align="left">$(&quot;.div&quot;)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.querySelector(&quot;css slector&quot;)</td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.querySelectorAll(&quot;css slector&quot;)</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">html 요소 생성</td>
<td align="left">변수 = document.createElement(&quot;option&quot;)</td>
<td align="left">$newTag = $(&quot;&lt;option&gt;&quot;)</td>
</tr>
<tr>
<td align="left">html 요소 추가</td>
<td align="left">부모태그.append( node)</td>
<td align="left">$(부모)append($newTag)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.prepend(), .appendChild()</td>
<td align="left">.prepend($newTag)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.insertAdjacentElement(position, element)</td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.insertAdjacentHTML(position, text)</td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.insertAdjacentText(position, text)</td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">형제.after(), before()</td>
<td align="left">$형제.after(), before()</td>
</tr>
<tr>
<td align="left">html 내용 변경</td>
<td align="left">태그.innerHTML = &#39;수정할내용&#39;</td>
<td align="left">$태그.html(&quot;수정할내용&quot;)</td>
</tr>
<tr>
<td align="left">html 요소 삭제</td>
<td align="left">부모태그.removeChild(태그)</td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">태그.remove()</td>
<td align="left">$태그.remove()</td>
</tr>
<tr>
<td align="left">html 속성 변경</td>
<td align="left">태그.setAttribute(&#39;속성&#39;, &#39;값&#39;)</td>
<td align="left">$태그.attr(&#39;속성&#39;,&#39;값&#39;)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">태그.속성명 =&#39;값&#39;</td>
<td align="left">.prop(&#39;속성&#39;,&#39;값&#39;)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">태그.removeAttribute(&#39;속성&#39;)</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">input 값</td>
<td align="left">태그.value</td>
<td align="left">$태그.val()</td>
</tr>
<tr>
<td align="left">css 변경</td>
<td align="left">태그.style.속성 = &#39;xxx&#39;</td>
<td align="left">$태그.css(&#39;속성&#39;,&#39;값&#39;)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">태그.style.display = &#39;none&#39;   또는 &#39;block&#39;</td>
<td align="left">.hide(),  show()</td>
</tr>
<tr>
<td align="left">class 변경</td>
<td align="left">태그.classList.add() / remove() / togger()</td>
<td align="left">$태그.addClass()/removeClass()/toggleClass()</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.contains(&quot;클래스명&quot;)</td>
<td align="left">.hasClass(&quot;클래스명&quot;)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">.className = &quot;클래스명&quot;</td>
<td align="left">.attr(&quot;class&quot;, &quot;클래스명&quot;)</td>
</tr>
<tr>
<td align="left">data속성</td>
<td align="left">태그.setAttribute(&quot;data-속성&quot;, &quot;값&quot;)</td>
<td align="left">$태그.data(&quot;속성&quot;, &quot;값&quot;)</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">태그.dataset.속성 = &quot;값&quot;</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">event 추가</td>
<td align="left">태그.addEventListener(&quot;type&quot;, handler)</td>
<td align="left">$태그.bind(),    on(),  one()</td>
</tr>
<tr>
<td align="left">event 삭제</td>
<td align="left">태그.removeEventListener(&quot;type&quot;)</td>
<td align="left">.unbind(),  off()</td>
</tr>
<tr>
<td align="left">traverse-부모</td>
<td align="left">태그.parentElement , closest()</td>
<td align="left">$태그.parent(),   closest()</td>
</tr>
<tr>
<td align="left">자식</td>
<td align="left">childNodes, children,</td>
<td align="left">children(),</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">firstElementChild, lastElementChild</td>
<td align="left">first(),  last()</td>
</tr>
<tr>
<td align="left"></td>
<td align="left"></td>
<td align="left">find(&quot;css선택자&quot;)</td>
</tr>
<tr>
<td align="left">형제</td>
<td align="left">nextElementSibling, previousElementSibling</td>
<td align="left">$태그.prev(),  next()</td>
</tr>
<tr>
<td align="left"></td>
<td align="left"></td>
<td align="left">.prevAll(), nextAll(),  siblings()</td>
</tr>
<tr>
<td align="left">필터</td>
<td align="left"></td>
<td align="left">eq(index), gt(), lt(), odd(), even()</td>
</tr>
<tr>
<td align="left">반복문</td>
<td align="left">forEach()</td>
<td align="left">each()</td>
</tr>
<tr>
<td align="left">ajax</td>
<td align="left">XMLHttpRequest 객체</td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">fetch()</td>
<td align="left">$.ajax(),  $.post(), $.get(), $.getJson()</td>
</tr>
<tr>
<td align="left"></td>
<td align="left"></td>
<td align="left">$(&quot;div&quot;).load(url)</td>
</tr>
</tbody></table>
<h2 id="dom-객체와-jquery-객체-변환">dom 객체와 jQuery 객체 변환</h2>
<pre><code class="language-javascript">//dom 객체
var btn = document.getElementById(&quot;btn1&quot;);
btn.style.backgroundColor = &#39;red&#39;

//jquery 객체
var $btn = $(&quot;#btn1&quot;);
$btn.css(&quot;backgroundColor&quot;,&quot;blue&quot;)

//dom =&gt; jquery   : $()로 감쌈
$(btn).css(&quot;backgroundColor&quot;,&quot;blue&quot;)

//jquery =&gt; dom   : get(0) 함수
$btn[0].style.backgroundColor = &#39;red&#39;
$btn.get(0).style.backgroundColor = &#39;red&#39;

$(&quot;div&quot;).eq(0)    // jquery
$(&quot;div&quot;)[0]       // dom
$(&quot;div&quot;).get(0)   // dom

//each 반복문 안에서 객체 타입
$(&quot;div&quot;).each(function(idx, item){   
  item            // dom 객체
  $(item)         // jQuery 객체
  $(this)         // jQuery 객체
})</code></pre>
<h2 id="fetch--vs--ajax">fetch()  VS  $.ajax()</h2>
<ol>
<li><p>get 방식</p>
<pre><code class="language-javascript">fetch(url + &quot;?var=value&quot;).then();

$.ajax(url + &quot;?var=value&quot;).done();</code></pre>
</li>
<li><p>post(queryString)</p>
<pre><code class="language-javascript">//fetch
fetch(url, {method:&#39;post&#39;, body: &quot;fv=val&amp;sv=val&quot; }).then()    
</code></pre>
</li>
</ol>
<p>//jQuery ajax함수
 $.ajax(url, {method:&#39;post&#39;, data: &quot;fv=val&amp;sv=val&quot; }).done()
 $.ajax(url, {method:&#39;post&#39;, data: {&quot;fv&quot;:&quot;val&quot;, &quot;sv&quot;:&quot;val&quot; }  }).done()</p>
<pre><code>3. post(jsonString)
```javascript
 let data = {&quot;fv&quot;:&quot;val&quot;, &quot;sv&quot;:&quot;val&quot; }

 //fetch 함수
 fetch(url, {method: &#39;post&#39;, 
             headers: { &quot;Content-Type&quot;: &quot;application/json&quot;, },
             body: JSON.stringify(data)
       }).then()    

//jQuery ajax함수
 $.ajax(url, {method: &#39;post&#39;, 
              contentType : &quot;application/json&quot;,
              data: JSON.stringify(data)
        }).done()</code></pre><h2 id="반복문">반복문</h2>
<pre><code class="language-javascript">// javaScript
array1.forEach((element, index) =&gt; console.log(element));

// jQuery
$( &quot;li&quot; ).each((index, element) =&gt; console.log( element ));


//each 반복중단
$.each(arr, function(idx, item){
  return;         // continue
  return false;   // beak
})</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바 키워드]]></title>
            <link>https://velog.io/@yedam_it/%EC%9E%90%EB%B0%94-%ED%82%A4%EC%9B%8C%EB%93%9C</link>
            <guid>https://velog.io/@yedam_it/%EC%9E%90%EB%B0%94-%ED%82%A4%EC%9B%8C%EB%93%9C</guid>
            <pubDate>Sun, 10 Nov 2024 03:36:49 GMT</pubDate>
            <description><![CDATA[<h1 id="자바키워드">자바키워드</h1>
<ol>
<li>abstract </li>
<li>class </li>
<li>interface </li>
<li>instanceof </li>
<li>main </li>
<li>null </li>
<li>package </li>
<li>private </li>
<li>public</li>
<li>protected</li>
<li>return</li>
<li>static</li>
<li>switch</li>
<li>for</li>
<li>while</li>
<li>if~else</li>
<li>this</li>
<li>super</li>
<li>try~catch</li>
<li>finally</li>
<li>throw</li>
<li>throws</li>
<li>void</li>
<li>main</li>
<li>implements</li>
<li>extends</li>
<li>float</li>
<li>double</li>
<li>byte</li>
<li>short</li>
<li>char</li>
<li>boolean</li>
<li>int</li>
<li>long</li>
<li>case</li>
<li>do</li>
<li>continue</li>
<li>break</li>
</ol>
<h1 id="자바개념">자바개념</h1>
<ol>
<li>상속 (inheritence)</li>
<li>객체 (object)</li>
<li>변수 (variable)</li>
<li>상수 (literal)</li>
<li>참조타입 (reference type)</li>
<li>오버라이딩 (overriding) </li>
<li>오버로딩 (overloading)</li>
<li>다형성 (polymorphism)</li>
<li>깊은복제 (deep clone)</li>
<li>생성자 (constructor)</li>
<li>캡슐화 (encapsulation)</li>
<li>박싱/언방싱 (boxing/unboxing)</li>
<li>쓰레기수집기 (Garbage Collector)</li>
<li>게터/세터 (Getter/Setter)</li>
<li>힙 (heap)</li>
<li>스택 (stack)</li>
<li>인스턴스 (instance)</li>
<li>람다식 (Lambda Expressions)</li>
<li>정규표현식 (Regular Expression)</li>
<li>메소드 (method)</li>
<li>매개변수 (parameter)</li>
<li>멀티테스킹 (multi tasking)</li>
<li>캐스팅 (casting)</li>
<li>싱글톤 (singletone)</li>
<li>예외처리 (exception)</li>
<li>스태틱 (static)</li>
</ol>
<h1 id="알아야-할-클래스">알아야 할 클래스</h1>
<ol>
<li>Object </li>
<li>System </li>
<li>String </li>
<li>StringBuffer </li>
<li>StringBuilder </li>
<li>Math </li>
<li>Byte, Short </li>
<li>Boolean </li>
<li>Character</li>
<li>Integer, Long</li>
<li>Float, Double</li>
<li>Random</li>
<li>Calendar</li>
<li>Date</li>
<li>Arrays</li>
<li>StringTokenizer</li>
<li>Class</li>
<li>Pattern</li>
<li>DecimalFormat</li>
<li>SimpleDateFormat</li>
<li>MessageFormat</li>
<li>LocalDate</li>
<li>LocalTime</li>
<li>Period</li>
<li>Duration</li>
<li>Collections</li>
<li>List</li>
<li>Set</li>
<li>Map</li>
<li>Properties</li>
<li>Queue</li>
<li>Stream</li>
<li>File</li>
<li>Path</li>
<li>Iterator</li>
<li>Exception</li>
<li>Connection</li>
<li>Statement</li>
<li>ResultSet</li>
<li>Operator</li>
<li>Optional</li>
<li>Serializable</li>
<li>Scanner</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[IT 용어]]></title>
            <link>https://velog.io/@yedam_it/IT-%EC%9A%A9%EC%96%B4</link>
            <guid>https://velog.io/@yedam_it/IT-%EC%9A%A9%EC%96%B4</guid>
            <pubDate>Sun, 10 Nov 2024 03:16:51 GMT</pubDate>
            <description><![CDATA[<h3 id="linux">linux</h3>
<ul>
<li>ftp</li>
<li>telnet</li>
<li>web server</li>
<li>DNS</li>
<li>DHCP</li>
<li>IP주소(퍼블릭/프라이빗, 고정/유동)</li>
<li>서브넷과 서브넷 마스크</li>
<li>CIDR</li>
<li>라우팅과 라우터</li>
<li>포트</li>
</ul>
<h3 id="database">DATABASE</h3>
<ul>
<li>인덱스</li>
<li>정규화</li>
<li>제약조건(일관성)</li>
<li>트랜잭션</li>
<li>조인</li>
<li>서브쿼리</li>
<li>그룹함수</li>
<li>실행계획</li>
<li>프로시저와 함수의 차이</li>
<li>트리거</li>
</ul>
<h3 id="javascript">JavaScript</h3>
<ul>
<li>var , let, const 차이</li>
<li>attribute와 property 차이</li>
<li>클로저</li>
<li>Event 전파</li>
<li>DOM API</li>
<li>JSON</li>
<li>비동기통신(AJAX)</li>
</ul>
<h3 id="java">Java</h3>
<ul>
<li>Wrapper Class</li>
<li>인터페이스</li>
<li>오버라이딩과 오버로딩 차이</li>
<li>상속과 다형성</li>
<li>JVM</li>
<li>프로그램 패러다임<ul>
<li>선언형 프로그래밍</li>
<li>함수형 프로그래밍</li>
<li>논리형 프로그래밍</li>
<li>절차적 프로그래밍</li>
<li>객체 지향 프로그래밍</li>
<li>명령형 프로그래밍</li>
</ul>
</li>
<li>call by value vs call by reference</li>
<li>제네릭과 람다식</li>
</ul>
<h3 id="웹프로그래밍">웹프로그래밍</h3>
<ul>
<li>세션과 쿠키의 차이</li>
<li>HTTP 프로토콜</li>
<li>get과 post 차이</li>
<li>WAS와 웹서버의 차이</li>
<li>쿼리스트링 vs json 스트링</li>
<li>REST API</li>
<li>포워드와 리다이렉트 페이지 이동의 차이</li>
<li>부트스트랩</li>
<li>제이쿼리</li>
</ul>
<h3 id="node--react--vue">Node / react / vue</h3>
<ul>
<li>SPA</li>
<li>라우터</li>
<li>useRouter()와 useRoute() </li>
<li>redux</li>
<li>next.js</li>
<li>Options API 와 Composition API 스타일 </li>
<li>생명주기 훅(onMounted, onUpdated)</li>
</ul>
<h3 id="spring">Spring</h3>
<ul>
<li>MVC 패턴</li>
<li>스프링 아키텍쳐</li>
<li>서블릿</li>
<li>스프링 디스페처서블릿</li>
<li>레이아웃 템플릿 엔진</li>
<li>DI / IoC</li>
<li>AOP</li>
<li>JPA 와 MyBatis 차이</li>
<li>디자인패턴(싱글톤패턴/팩토리패턴/퍼사드패턴)</li>
<li>was 종류</li>
<li>전자정부프레임워크</li>
<li>넥사크로 / 웹스퀘어</li>
<li>레포트 도구</li>
</ul>
<h3 id="clould--deploy">clould &amp; deploy</h3>
<ul>
<li>CI/CD</li>
<li>VPC</li>
<li>도커</li>
<li>RDS</li>
<li>형상관리도구</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[EC2 인스턴스]]></title>
            <link>https://velog.io/@yedam_it/EC2-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4</link>
            <guid>https://velog.io/@yedam_it/EC2-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4</guid>
            <pubDate>Sun, 10 Nov 2024 02:49:02 GMT</pubDate>
            <description><![CDATA[<h2 id="실습1--ec2-인스턴스-배포">실습1 : EC2 인스턴스 배포</h2>
<h3 id="1-리전-변경">1. 리전 변경</h3>
<p>아시아 태평양(서울)</p>
<h3 id="2-키페어-생성">2. 키페어 생성</h3>
<ul>
<li>사이드메뉴  =&gt; 네트워크 및 보안  =&gt;  키페어</li>
<li>이름 : <strong>awskey</strong></li>
<li>프라이빗 키 파일 형식 : <strong>.pem</strong> 선택</li>
<li>태그 : <strong>myserver</strong></li>
<li>키파일 다운로드</li>
<li>c:\aws 폴더 생성하고 다운받은 pem 키파일 이동<br><strong>파일 분실 시 재발급 안 되고 서버 접속 할 수 없음</strong></li>
</ul>
<h3 id="3-보안그룹-생성">3. 보안그룹 생성</h3>
<ul>
<li>사이드메뉴  =&gt; 네트워크 및 보안  =&gt;  보안그룹</li>
<li>myserver_sg</li>
<li>보안그룹 =&gt; myserver_sg 체크 =&gt; 인바운드 규칙 탭 =&gt; 인바운드 규칙 편집 버튼<pre><code>     =&gt; 규칙 추가 버튼 =&gt; 포트 범위에 80 =&gt; 소스 에 &quot;anywhere-IPv4&quot; =&gt; 규칙 저장 버튼</code></pre></li>
</ul>
<h3 id="4-인스턴스-시작">4. 인스턴스 시작</h3>
<ul>
<li>서비스  =&gt;  컴퓨팅  =&gt;  EC2 선택</li>
<li>이름 및 태그 : <strong>myserver</strong></li>
<li>AMI : <strong>Amazon Linux</strong></li>
<li>인스턴스 유형 : <strong>t2.micro</strong> (프리티어 기본값 )</li>
<li>키페어 : <strong>awskey</strong> 선택</li>
<li>네트워크 설정 : <strong>myserver_sg</strong> 보안그룹 선택</li>
<li>스토리지 구성 :  <strong>30</strong> </li>
<li>인스턴스 시작 버튼</li>
<li>모든 인스턴스 보기 버튼</li>
<li>myserver 인스턴스 선택</li>
<li>public IP 주소 따로 메모해둘 것</li>
</ul>
<h2 id="실습2--ec2-인스턴스-접속">실습2 : EC2 인스턴스 접속</h2>
<h4 id="mobaxterm-다운로드하고-설치">MobaXterm 다운로드하고 설치</h4>
<h4 id="mobaxterm-session-설정">MobaXterm session 설정</h4>
<ul>
<li><p>메인 메뉴 =&gt; session</p>
</li>
<li><p>SSH 탭</p>
</li>
<li><p>Remote host에 인스턴스의 퍼블릭 IP 입력</p>
</li>
<li><p>specify username 체크 하고 ec2-user 입력</p>
</li>
<li><p>Advanced SSH settings 탭</p>
</li>
<li><p>SSH-browswer type 은 None 선택
파일 전송하려면 SFTP protocol 선택</p>
</li>
<li><p>use private key 체크하고 다운받은 pem 키파일을 지정</p>
</li>
<li><p>OK 버튼</p>
</li>
<li><p>서버 정보 확인</p>
<pre><code class="language-bash">$ ifconfig                     # 퍼블릭 IP 확인
$ curl ipinfo.io/ip
$ cat /etc/os-release          # 리눅스 버전
$ lsblk                        # 스토리지 확인
$ df –h                        # 디스크 사용량 확인
$ free –h                      # 메모리 용량 확인</code></pre>
</li>
<li><p>호스트 이름 변경</p>
<pre><code class="language-bash">$ hostname                                     # 호스트 이름 확인
$ sudo hostnamectl set-hostname webserver      # 호스트 이름 변경
$ sudo reboot                                  # 재부팅 </code></pre>
</li>
</ul>
<h2 id="실습3--http-웹서버-구축">실습3 : http 웹서버 구축</h2>
<h4 id="1-웹서버-구축">1. 웹서버 구축</h4>
<pre><code class="language-bash">    sudo su -                                       # 슈퍼 유저로 변경
    yum install httpd –y                            # http 데몬 설치
    systemctl start httpd                           # http 데몬 실행
                                                    # sudo service httpd start
    systemctl status httpd                          # http 서비스 상태
                                                    # sudo service httpd status  
    sudo netstat -nlp | grep 80                     # 80 포트 확인
    cd /var/www/html                                
    echo “AWS web server start~~~” &gt; index.html     # index 파일 생성</code></pre>
<h4 id="2-서버-연결-테스트">2. 서버 연결 테스트</h4>
<p>   브라우저에서 <a href="http://ip%EC%A3%BC%EC%86%8C">http://ip주소</a></p>
<h2 id="실습4--클라우드-자원-삭제하기">실습4 : 클라우드 자원 삭제하기</h2>
<h4 id="1-인스턴스-삭제">1. 인스턴스 삭제</h4>
<p>  인스턴스 상태 =&gt; 인스턴스 종료(삭제)</p>
<h4 id="2-보안그룹-삭제">2. 보안그룹 삭제</h4>
]]></description>
        </item>
    </channel>
</rss>