함수 만들기 - Web 개발 학습하기

함수 만들기
======

* 이전
* Overview: Building blocks
* 다음

지난 문서에서 다뤄진 필수적인 이론의 대부분을 바탕으로, 이 문서에서는 실제적인 경험을 제공합니다. 여기서 사용자 정의(custom) 함수를 만드는 연습을 할 수 있습니다. 그 과정에서 함수를 다루는 데 있어 유용한 세부 사항을 설명할 것입니다.

|  |  |
| --- | --- |
| 필요한 사전 지식: |
 기본적인 컴퓨터 사용 능력, HTML과 CSS에 대한 기본적인 이해,
 JavaScript 첫걸음,
 함수 — 코드 재사용.
  |
| 목표: |
 사용자 정의 함수를 만들어보기, 그리고 그와 관련된 유용한 세부 사항 좀 더
 설명하기.
  |

직접 해보기: 함수를 만들어 봅시다
-------------------

우리가 만들 사용자 정의 함수는 `displayMessage()`라는 이름입니다. 이 함수는 웹 페이지에 사용자 정의 메시지 박스를 표시하고 브라우저의 내장 alert() 함수를 대체하는 역할을 할 것입니다. 우리는 이것을 전에 보긴 했지만, 기억을 되살려 봅시다. 원하는 어떤 페이지에서든지, 다음을 브라우저의 JavaScript 콘솔에 입력해 보세요:

```js
alert("This is a message");
```

`alert` 함수는 하나의 인수(argument)를 취합니다 — alert 박스에 표시될 문자열입니다. 메시지를 바꾸기 위해서 문자열에 변화를 줘 보세요.

`alert` 함수는 제한적입니다: 메시지를 바꿀 수는 있지만, 색상, 아이콘 등 그 밖에 다른 것에는 쉽게 변화를 줄 수 없습니다. 우리는 더 재미있는 것을 만들 것입니다.

**참고:** 이 예제는 모든 현대적인 브라우저에서 잘 동작할 것이지만, 약간 오래된 브라우저에서는 스타일이 조금 이상하게 적용될지도 모릅니다. Firefox, Opera, 또는 Chrome같은 브라우저에서 이 연습을 진행하기를 추천합니다.

기본적인 함수
-------

기본적인 함수를 만들면서 시작해 봅시다.

**참고:** 함수에 이름을 붙일 때 변수 명명 규칙과 같은 규칙을 따라야 합니다. 함수와 변수를 떼어놓고 이야기할 수 있으므로, 이렇게 하는 것은 괜찮습니다 — 함수명은 뒤에 괄호가 나타나지만 변수는 그렇지 않습니다.

1. function-start.html 파일을 다운로드한 후 시작해 봅시다. HTML은 간단합니다 — body는 버튼 하나만을 포함하고 있습니다. 또한 커스텀 메시지 박스를 꾸밀 기본적인 CSS와, JavaScript를 넣을 빈 `<script>` 요소가 제공됩니다.
2. 다음으로, 다음을 `<script>` 요소 내부에 추가해 보세요:

```js
function displayMessage() {}
```

우리는 키워드 `function`으로 시작했는데, 이는 우리가 함수를 정의하고 있다는 것을 의미합니다. 이것 다음에는 우리가 함수에 붙이고 싶은 이름이 오고, 그 다음에는 괄호가 오고, 그 다음에는 중괄호가 옵니다. 함수에 넣고자 하는 매개변수(parameter)는 괄호 안에 들어가고, 함수를 호출했을 때 실행될 코드는 중괄호 안에 들어갑니다.
3. 마지막으로, 다음의 코드를 중괄호 안에 추가해 보세요:

```js
const html = document.querySelector("html");

const panel = document.createElement("div");
panel.setAttribute("class", "msgBox");
html.appendChild(panel);

const msg = document.createElement("p");
msg.textContent = "This is a message box";
panel.appendChild(msg);

const closeBtn = document.createElement("button");
closeBtn.textContent = "x";
panel.appendChild(closeBtn);

closeBtn.onclick = function () {
  panel.parentNode.removeChild(panel);
};
```

코드가 꽤 긴 편이니 조금씩 설명을 이어가겠습니다.

첫 번째 줄은 `<html>` 요소를 선택하고, `html` 상수에 그것에 대한 참조를 저장하기 위해 `document.querySelector()` 라는 DOM API 함수를 사용했습니다. 이를 통해, 우리는 나중에 이 요소에 이런저런 것들을 할 수 있습니다.

```js
const html = document.querySelector("html");
```

다음 섹션은 `<div>` (en-US) 요소를 생성하기 위해 `document.createElement()` 라는 또 다른 DOM API 함수를 사용하고 `panel` 상수에 그것에 대한 참조를 저장합니다. 이 요소는 메시지 박스의 바깥 컨테이너가 될 것입니다.

그 후, 패널에 있는 `class` 어트리뷰트에 `msgBox`라는 값을 설정하기 위해 `Element.setAttribute()` 라는 또 다른 DOM API 함수를 사용합니다. 이렇게 하는 이유는 요소를 스타일하기 쉽게 만들기 위함입니다 — 만약 CSS를 보면, 메시지 박스와 메시지 박스의 컨텐츠를 스타일하기 위해 `.msgBox` 클래스 선택자를 사용하고 있는 것을 볼 수 있을 것입니다.

마지막으로, 우리는 앞에서 저장한 `html` 상수에 `Node.appendChild()` 라는 DOM 함수를 호출하는데, 이는 한 요소를 다른 요소 안에 그것의 자식으로서 중첩합니다. 우리는 `<html>` 요소 안에 덧붙이기를 원하는 자식으로서 패널 `<div>`를 명시했습니다. 우리가 생성한 요소가 페이지에 혼자서 나타나지는 않으므로 우리는 appendChild를 사용할 필요가 있습니다 — panel을 어디 넣을지 명시해야 합니다.

```js
const panel = document.createElement("div");
panel.setAttribute("class", "msgBox");
html.appendChild(panel);
```

다음의 두 섹션은 새로운 요소 두 개 — `<p>` 와 `<button>` — 를 생성하기 위해 이미 살펴본 `createElement()`와 `appendChild()` 함수를 사용하고 이것들을 페이지에 패널 `<div>`의 자식으로서 삽입합니다. 단락 안에 메시지와, 버튼 안에 'x'를 삽입하기 위해 우리는 이 요소들의 `Node.textContent` 프로퍼티를 사용해 요소의 텍스트 콘텐츠를 나타냅니다. 이 버튼은 유저가 메시지 박스를 닫기를 원할 때 클릭될/작동될 필요가 있는 것입니다.

```js
const msg = document.createElement("p");
msg.textContent = "This is a message box";
panel.appendChild(msg);

const closeBtn = document.createElement("button");
closeBtn.textContent = "x";
panel.appendChild(closeBtn);
```

마지막으로, 우리는 버튼이 클릭되었을 때, 전체 패널을 페이지에서 삭제하기 위해 — 메시지 박스를 닫기 위해 — 몇몇 코드가 실행되도록 `GlobalEventHandlers.onclick` (en-US) 이벤트 핸들러를 사용합니다.

간략하게 말하자면, `onclick` 핸들러는 버튼이 클릭되었을 때 어떤 코드를 실행할 지 명시하기 위해 함수에 설정될 수 있는, 버튼에서 (사실은, 페이지에 있는 어떠한 요소들에서든지) 사용 가능한 프로퍼티입니다. 차후의 이벤트 문서에서 이것에 대해 더 많이 배울 것입니다. 우리는 `onclick` 핸들러를 익명 함수로 만들었는데, 이는 버튼이 클릭되었을 때 실행할 코드를 포함합니다. 함수 내부의 코드는 우리가 특정한 자식 요소 — 이 경우 패널 `<div>` — 를 제거하고 싶다는 것을 명시하기 위해 `Node.removeChild()` (en-US) DOM API를 사용합니다.

```js
closeBtn.onclick = function () {
  panel.parentNode.removeChild(panel);
};
```

기본적으로, 이 전체 코드 블록은 아래와 같이 보이는 HTML 블록을 생성하고, 페이지에 삽입합니다:

```html
<div class="msgBox">
  <p>This is a message box</p>
  <button>x</button>
</div>
```

이것은 뚫고 나오기에 많은 코드였습니다 — 지금은 어떻게 코드의 모든 부분이 동작하는지 정확히 기억하지 못해도 너무 걱정하지는 마세요! 이 문서에서 우리가 집중하기를 원하는 주된 부분은 함수의 구조와 사용이지만, 우리는 이 예제에 대해 무언가 흥미로운 것을 보여주고 싶었습니다.

함수 호출하기
-------

이제 여러분은 `<script>` 요소에 아주 잘 작성된 함수 정의를 가지고 있지만, 이것은 현재 상태 그대로는 아무것도 하지 않을 것입니다.

1. 함수를 호출하기 위해, 다음의 코드를 함수 아래에 포함시켜 보세요.

```js
displayMessage();
```

이 코드는 함수를 호출하는데, 즉시 실행되게 합니다. 코드를 저장하고 브라우저에서 새로고침했을 때, 작은 메시지 박스가 단 한 번, 즉시 나타나는 것을 볼 수 있을 것입니다. 어쨌든 우리는 이 함수를 오직 한 번 호출했으니까요.
2. 이제 예제 페이지에서 브라우저 개발자 도구를 열고, JavaScript 콘솔로 가서 이 코드를 다시 입력해 보면, 메시지 박스가 다시 나타나는 것을 볼 수 있을 것입니다! 이것은 재미있습니다 — 이제 우리는 우리가 원할 때 언제든지 호출할 수 있는 재사용 가능한 함수를 가지고 있는 것입니다.
 하지만 우리는 이 함수가 유저와 시스템 작동에 응답하여 나타나기를 원합니다. 실제 어플리케이션에서는, 그러한 메시지 박스는 아마도 이용 가능한 새로운 데이터나, 발생한 에러나, 프로필을 지우려는 유저나 ("정말로 지우시겠습니까?"), 새로운 연락처를 추가한 유저 그리고 성공적으로 완료된 작동 등에 응답하여 호출될 것입니다.
 이 예제에서는, 우리는 유저가 버튼을 클릭했을 때 메시지 박스가 나타나게 할 것입니다.
3. 추가한 마지막 줄을 지우세요.
4. 다음으로, 우리는 버튼을 선택하고 상수에 이것에 대한 참조를 저장할 것입니다. 함수 정의 위에, 다음을 코드에 추가해 보세요:

```js
const btn = document.querySelector("button");
```

5. 마지막으로, 다음을 지난 코드 아래에 추가해 보세요:

```js
btn.onclick = displayMessage;
```

함수 내부의 `closeBtn.onclick...` 코드와 비슷한 방식으로, 여기서 우리는 클릭된 버튼에 응답하여 몇몇 코드를 호출하고 있습니다. 하지만 이 경우, 코드를 포함하는 익명 함수를 호출하는 대신, 우리는 함수명을 직접 호출하고 있습니다.
6. 저장하고 페이지를 새로고침해 보세요 — 이제 여러분이 버튼을 클릭했을 때 메시지 박스가 나타나는 것을 볼 수 있을 것입니다.

왜 함수명 뒤에 괄호를 포함하지 않았는지 궁금할지도 모릅니다. 그 이유는 함수를 즉시 호출하고 싶지 않았기 때문입니다 — 오직 버튼이 클릭된 이후에만 호출되기를 원했습니다. 만약 이 줄을 다음으로 변경하고

```js
btn.onclick = displayMessage();
```

저장한 후 새로고침한다면, 여러분은 메시지 박스가 버튼이 클릭되지도 않았는데 나타나는 것을 보게 될 것입니다. 이 맥락에서의 괄호는 때때로 "함수 호출 연산자(function invocation operator)"라고 불립니다. 이것은 함수를 현재 스코프에서 즉시 실행하고 싶을 때만 사용됩니다. 같은 측면에서, 익명 함수 내부의 코드는 즉시 실행되지 않는데, 이는 그것이 함수 스코프 내에 있기 때문입니다.

만약 마지막 실험을 시도해 봤다면, 앞으로 가기 전에 반드시 이전으로 되돌리세요.

매개변수를 사용해 함수를 더 낫게 만들기
----------------------

현재로써는, 함수는 여전히 유용하지 않습니다 — 우리는 같은 기본 메시지를 매번 보이게 하고 싶지 않습니다. 함수를 다른 옵션으로 호출할 수 있게 해 주는 매개변수를 추가해서 우리의 함수를 더 낫게 만들어 봅시다.

1. 우선, 함수의 첫 번째 줄을

```js
function displayMessage() {
```

이것으로 업데이트하세요:

```js
function displayMessage(msgText, msgType) {
```

이제 함수를 호출할 때, 우리는 메시지 박스에 표시할 메시지와, 메시지의 타입을 나타내기 위해 괄호 안에 두 개의 변수 값을 제공할 수 있습니다.
2. 첫번째 매개변수를 사용하기 위해, 함수 안의 다음의 줄을

```js
msg.textContent = "This is a message box";
```

다음으로 업데이트하세요:

```js
msg.textContent = msgText;
```

3. 마지막으로 또한 중요한 것은, 업데이트된 메시지 텍스트를 포함시키기 위해 이제 함수 호출을 바꿀 필요가 있다는 것입니다. 다음의 줄을

```js
btn.onclick = displayMessage;
```

이 블록으로 바꾸세요:

```js
btn.onclick = function () {
  displayMessage("Woo, this is a different message!");
};
```

만약 호출할 함수의 괄호 내부에 매개변수를 넣기 원한다면, 함수는 직접 호출될 수 없습니다 — 대신, 함수를 익명 함수 안에 넣어 함수가 즉각적인 스코프(immediate scope) 내에 있지 않게 하여 즉시 호출되지 않게 할 수 있습니다. 이제 함수는 버튼이 클릭되기 전까지는 호출되지 않을 것입니다.
4. 새로고침하고 다시 시도해 보면, 여전히 아주 잘 작동할 뿐만 아니라 박스 안에 다른 메시지들이 표시될 수 있게 매개변수에 변화를 줄 수 있다는 것 또한 확인할 수 있을 것입니다.
### 더욱 복잡한 매개변수

다음 매개변수로 가 봅시다. 이것은 약간의 수고를 더 필요로 합니다 — 우리는 이것을 설정하여 `msgType` 매개변수가 무엇으로 설정되어 있는지에 따라, 함수가 다른 아이콘과 다른 배경색을 표시하도록 할 것입니다.

1. 우선, 이 예제를 위해 필요한 아이콘들을 GitHub에서 다운로드하세요 (경고 그리고 채팅). 이것들을 HTML파일과 같은 위치에 있는 `icons` 라는 새로운 폴더에 저장하세요.

**참고:** 경고와 채팅 아이콘은 원래 iconfinder.com에서 찾아졌고, Nazarrudin Ansyari가 디자인했습니다 — 감사합니다! (실제 아이콘 페이지는 이전에 이동되거나 삭제되었습니다.)
2. 다음으로, HTML 파일 내부에서 CSS를 찾으세요. 우리는 아이콘이 들어갈 자리를 만들기 위해 약간의 변경을 가할 것입니다. 우선, `.msgBox` 폭을

```css
width: 200px;
```

다음으로 업데이트하세요:

```css
width: 242px;
```

3. 다음으로, `.msgBox p { ... }` 규칙 내부에 다음을 추가하세요:

```css
padding-left: 82px;
background-position: 25px center;
background-repeat: no-repeat;
```

4. 이제 우리는 아이콘 표시를 처리하기 위해 `displayMessage()` 함수에 코드를 추가해야 합니다. 다음의 블록을 함수의 닫는 중괄호 (`}`) 바로 위에 추가하세요:

```js
if (msgType === "warning") {
  msg.style.backgroundImage = "url(icons/warning.png)";
  panel.style.backgroundColor = "red";
} else if (msgType === "chat") {
  msg.style.backgroundImage = "url(icons/chat.png)";
  panel.style.backgroundColor = "aqua";
} else {
  msg.style.paddingLeft = "20px";
}
```

여기서, 만약 `msgType` 매개변수가 `'warning'`으로 설정되어 있다면, 경고 아이콘이 표시될 것이고 패널의 배경색이 빨강으로 설정될 것입니다. 만약 이것이 `'chat'`으로 설정되어 있다면, 채팅 아이콘이 표시되고 패널의 배경색이 연한 파랑으로 설정될 것입니다. 만약 `msgType` 매개변수가 전혀 설정되어 있지 않다면 (혹은 무언가 다른 것으로 설정되어 있다면), 코드의 `else { ... }` 부분이 작동하고, 문단은 단순히 기본 패딩이 적용되고 아이콘과 패널 배경색 없이 보여질 것입니다. 즉 `msgType` 매개변수가 제공되지 않으면 기본 상태가 표시되는데, 이는 이 매개변수가 선택적인 매개변수라는 것을 의미합니다!
5. 업데이트된 함수를 시험해 봅시다. `displayMessage()` 호출을

```js
displayMessage("Woo, this is a different message!");
```

이것들 중 하나로 업데이트해 봅시다:

```js
displayMessage("Your inbox is almost full — delete some mails", "warning");
displayMessage("Brian: Hi there, how are you today?", "chat");
```

우리의 작은 (이제 그렇게 작지는 않은) 함수가 얼마나 유용해졌는지 볼 수 있습니다.

**참고:** 만약 이 예제를 작업하는 데 어려움이 있다면, 자유롭게 GitHub에 있는 완성된 버전과 비교해 보거나 (실제로 작동하는 모습도 보세요), 우리에게 도움을 요청해 보세요.

실력을 평가해 보세요!
------------

이 문서를 끝까지 읽으셨지만, 중요한 것들을 여전히 기억하고 계신가요? 다음 문서를 읽기 전에 이 문서의 내용을 잘 학습하고 이해하셨는지 확인하실 수 있습니다 — 실력을 평가해 보세요: 함수. 이 평가들은 다음 문서에서 다뤄지는 기술들을 요구하므로, 평가를 시도해보기 전에 다음 문서를 먼저 읽을 수도 있습니다.

결론
--

끝에 도달하신 것을 축하드립니다! 이 문서는 여러분이 실용적인 사용자 정의 함수를 만들어보는 전체 과정을 익히도록 했는데, 이는 조금의 추가적인 작업과 함께 실제 프로젝트로 이식될 수도 있습니다. 다음 문서에서 우리는 또 다른 관련된 필수적인 개념 — 반환 값을 설명함으로써 함수를 마무리지을 것입니다.

* 이전
* Overview: Building blocks
* 다음


이벤트 입문 - Web 개발 학습하기

이벤트 입문
======

* 이전
* Overview: Building blocks
* 다음

이벤트(event)란 여러분이 프로그래밍하고 있는 시스템에서 일어나는 사건(action) 혹은 발생(occurrence)인데, 이는 여러분이 원한다면 그것들에 어떠한 방식으로 응답할 수 있도록 시스템이 말해주는 것입니다. 예를 들자면, 만약 유저가 웹페이지에 있는 버튼을 고른다면, 여러분은 그 사건에 인포메이션 박스를 표시함으로써 응답하기를 원할지도 모릅니다. 이 문서에서는, 우리는 이벤트에 대한 몇몇 중요한 개념을 논하고, 그것들이 브라우저에서 어떻게 작동하는지 살펴봅니다. 이것은 완전한 공부가 되지 않을 것입니다; 단지 지금 단계에서 여러분이 알아야 할 필요가 있는 것입니다.

|  |  |
| --- | --- |
| 필요한 사전 지식: |
 기본적인 컴퓨터 활용 능력, HTML, CSS,
 JavaScript 첫걸음에 대한 기본적인 이해
  |
| 목표: |
 이벤트에 대한 필수적인 이론, 브라우저에서 이벤트가 어떻게 작동하는지,
 그리고 어떻게 다른 프로그래밍 환경에서 다를 지도 모르는지를 이해하기
  |

일련의 운 좋은 사건들
------------

위에서 언급했다시피, **이벤트**란 여러분이 프로그래밍하고 있는 시스템에서 일어나는 사건이나 발생입니다 — 시스템은 이벤트가 발생될 때 몇몇 종류의 신호를 생산(produce) (또는 "발생(fire)"시키고, 이벤트가 발생되었을 때 사건이 자동적으로 취해질 수 있는 메커니즘 (즉, 코드의 실행)을 제공합니다. 예를 들자면, 공항에서, 활주로가 이륙을 위해 막혀 있지 않을 때, 신호가 파일럿에게 전달됩니다. 결과적으로, 비행기는 안전하게 이륙할 수 있습니다.

![](/ko/docs/Learn/JavaScript/Building_blocks/Events/mdn-mozilla-events-runway.png)

웹의 경우에, 이벤트는 브라우저 윈도우 내에서 발생되고, 그것이 거주하는 특정한 요소에 부착되는 경향이 있습니다 — 이것은 하나의 요소, 요소들의 집합, 현재 탭에 로드된 HTML 문서, 혹은 전체 브라우저 윈도우일지도 모릅니다. 발생될 수 있는 많은 각양각색의 이벤트 타입이 있습니다. 예를 들자면:

* 유저가 어떤 요소를 선택하거나 어떤 요소 위에 커서를 올려둡니다(hover).
* 유저가 키보드에서 키를 선택합니다.
* 유저가 브라우저 창의 크기를 재조정하거나 닫습니다.
* 웹 페이지가 로딩을 완료했습니다.
* 양식(form)이 제출되었습니다.
* 비디오가 재생되거나, 멈추거나, 혹은 끝났습니다.
* 오류가 발생했습니다.

여러분은 이것으로부터 (그리고 MDN 이벤트 레퍼런스 (en-US)를 흘낏 보는 것으로부터) 응답되어질 수 있는 **많은** 이벤트들이 있다는 것을 알 수 있습니다.

각각의 이용가능한 이벤트들은 **이벤트 핸들러**(event handler)를 가지고 있는데, 이는 이벤트가 발생되면 실행되는 코드 블럭 (보통 여러분과 같은 프로그래머가 만드는 JavaScript 함수)입니다. 그러한 코드 블럭이 이벤트에 응답해서 실행되기 위해 정의되었을 때, 우리는 **이벤트 핸들러를 등록**(register)했다고 말합니다. 알림: 이벤트 핸들러는 때때로 **이벤트 리스너**(event listener)라고 불립니다 — 이것들은 우리의 목적을 위해 꽤 교체할수 있지만, 그러나 엄밀히 말하자면, 그들은 같이 동작합니다. 리스너는 발생되는 이벤트에 대해 듣고, 핸들러는 발생되는 이벤트에 응답해서 실행되는 코드입니다.

**참고:** #### 참고웹 이벤트는 코어 JavaScript 언어의 일부가 아닙니다 — 이것들은 브라우저에 내장된 API의 일부로서 정의됩니다.

### 간단한 예제

우리가 여기서 의미한 것의 간단한 예제를 봅시다. 여러분은 이미 많은 예제들에서 사용된 이벤트와 이벤트 핸들러를 보았지만, 단지 우리의 지식을 견고하게 하기 위해 요약해 봅시다. 다음의 예제에서, 우리는 하나의 `<button>`을 가지고 있는데, 눌러졌을 때, 이는 배경이 무작위의 색으로 바뀌게 만듭니다:

```html
<button>Change color</button>
```

```
button {
  margin: 10px;
}
```

JavaScript는 다음과 같습니다:

```js
const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() \* (number + 1));
}

btn.onclick = function () {
  const rndCol =
    "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")";
  document.body.style.backgroundColor = rndCol;
};
```

이 코드에서, `Document.querySelector()` 함수를 사용하여, 우리는 `btn` 상수 내부에 버튼에 대한 참조를 저장했습니다. 우리는 또한 무작위의 숫자를 반환하는 함수를 정의했습니다. 코드의 세번째 부분은 이벤트 핸들러입니다. `btn` 상수는 `<button>` 요소를 가리키고, 이 타입의 객체는 발생시킬 수 있는 얼마간의 이벤트를 가지고 있으므로, 이벤트 핸들러를 사용 가능합니다. `onclick` (en-US) 이벤트 핸들러 프로퍼티를 무작위의 RGB 색상을 생성하고 그것과 같은 `<body>` `background-color`를 설정하는 코드를 포함하는 익명함수에 설정함으로써, 우리는 `click` 이벤트 발생에 귀를 기울이고 있습니다.

이 코드는 언제든지 `<button>` 요소에서 click 이벤트가 발생될 때, 즉 언제든지 유저가 그것을 선택했을 때, 실행됩니다.

예제 출력은 다음과 같습니다:

### 이것은 단지 웹 페이지가 아닙니다

이 지점에서 언급할 가치가 있는 다른 것은 이벤트는 JavaScript 특유의 것이 아니라는 것입니다 — 대부분의 프로그래밍 언어는 몇몇 종류의 이벤트 모델을 가지고 있고, 그 모델이 작동하는 방식은 종종 JavaScript의 방법과는 다릅니다. 사실, 웹 페이지를 위한 JavaScript에서의 이벤트 모델은 다른 환경에서 쓰이는 JavaScript에 대한 이벤트 모델과는 다릅니다.

예를 들자면, 개발자들이 JavaScript를 네트워크와 서버사이드 어플리케이션을 제작하기 위해 사용하는 것을 가능하게 하는 Node.js는 매우 인기있는 JavaScript 런타임입니다. Node.js 이벤트 모델은 이벤트를 듣는 리스너와 이벤트를 주기적으로 발산하는 이미터(emitter)에 의존하고 있습니다 — 이것은 그렇게 다른 것처럼 들리지 않지만, 코드는 상당히 다른데, 이벤트 리스너를 등록하기 위해 `on()`, 이벤트 리스너를 등록하고 한 번 실행된 이후에 등록을 해제하는 `once()`같은 함수를 사용합니다. HTTP connect 이벤트 문서는 좋은 예시를 제공합니다.

WebExtensions이라 불리는 기술을 사용하여, 여러분은 또한 크로스 브라우저 애드온(cross-browser add-on) — 브라우저 기능성 강화 — 을 개발하기 위해 JavaScript를 사용할 수 있습니다. 이 이벤트 모델은 웹 이벤트 모델과 유사하나, 조금 다릅니다 — 이벤트 리스너 프로퍼티들은 (`onmessage`가 아니라 `onMessage`와 같이) 카멜케이스(camel-case)화 되어있고, `addListener` 함수와 연결될 필요가 있습니다. 예시를 위해 `runtime.onMessage` 페이지 (en-US)를 봐 보세요.

지금 배우는 단계에서는 그러한 다른 환경들에 대해서 아무것도 이해할 필요가 없습니다; 우리는 단지 이벤트가 다른 프로그래밍 환경에서 다를 수 있다는 것을 확실히 하고 싶었습니다.

웹 이벤트를 사용하는 방법들
---------------

이벤트 리스너 코드가 관련된 이벤트가 발생되었을 때 실행되도록 웹 페이지에 이것을 더하는 얼마간의 방법들이 있습니다. 이 섹션에서, 우리는 다양한 메커니즘을 관찰하고 어떤 것을 여러분이 사용해야만 하는지 논할 것입니다.

### 이벤트 핸들러 프로퍼티

이것들은 이 코스 동안에 우리가 가장 자주 봤던 이벤트 핸들러 코드를 포함하기 위해 존재하는 프로퍼티입니다. 위의 예제로 돌아가 봅시다.

```js
const btn = document.querySelector("button");

btn.onclick = function () {
  const rndCol =
    "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")";
  document.body.style.backgroundColor = rndCol;
};
```

`onclick` (en-US) 프로퍼티는 이 상황에서 쓰이고 있는 이벤트 핸들러 프로퍼티입니다. 이것은 본질적으로 버튼에서 사용 가능한 다른 것들과 같은 프로퍼티지만 (예: `btn.textContent`, 또는 `btn.style` (en-US)), 이것은 특별한 타입입니다 — 어떤 코드와 동일한 것을 설정했을 때, 그 코드는 버튼에서 이벤트가 발생되었을 때 실행됩니다.

여러분은 또한 기명 함수 이름과 같은 핸들러 프로퍼티를 설정할 수 있습니다 (자신만의 함수 만들기에서 본 것처럼요). 다음은 아주 똑같이 동작합니다:

```js
const btn = document.querySelector("button");

function bgChange() {
  const rndCol =
    "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")";
  document.body.style.backgroundColor = rndCol;
}

btn.onclick = bgChange;
```

사용 가능한 많은 가지각색의 이벤트 핸들러 프로퍼티가 있습니다. 실험해 봅시다.

우선, random-color-eventhandlerproperty.html를 다운받으시고, 여러분의 브라우저에서 열어보세요. 이것은 우리가 이미 해본 단순한 무작위 색상 예제의 복사본입니다. 이제 `btn.onclick`를 다음의 다른 값들로 차례대로 바꿔 보시고, 예제에서 그 결과를 관찰해 보세요.

* `btn.onfocus` (en-US)와 `btn.onblur` (en-US) — 색상은 버튼이 포커스되고 포커스가 해제되었을 때 바뀝니다; 버튼을 포커스하기 위해 탭 키를 눌러 보시고 다시 탭 키를 눌러서 버튼으로부터 포커스를 해제해 보세요. 이것들은 종종 양식 필드(form field)가 포커스되었을 때 그것에 채움(filling)에 대한 정보를 표시하기 위해 사용되거나, 만약 양식 필드가 올바르지 않은 값으로 채워진다면 에러 메시지를 표시하기 위해 사용됩니다.
* `btn.ondblclick` — 오직 버튼이 더블 클릭되었을 때만 색상이 바뀝니다.
* `window.onkeydown` (en-US), `window.onkeyup` (en-US) — 키보드에서 키가 눌렸을 때 색상이 바뀝니다. `keydown` 과 `keyup`은 단지 각각 키 누름(keystroke)의 누름(key down)과 뗌(key up) 부분을 지칭합니다. 알림: 만약 여러분이 이 이벤트 핸들러를 버튼 그 자체에 등록한다면 이것은 작동하지 않습니다 — 우리는, 전체 브라우저를 나타내는, window에 이것을 등록해야만 합니다.
* `btn.onmouseover` (en-US) 와 `btn.onmouseout` (en-US) — 각각 마우스 포인터가 버튼 위에 올라가 있을 때, 혹은 포인터가 버튼에서 벗어났을 때 색상이 바뀝니다.

몇몇 이벤트들은 일반적이고 거의 어디서나 사용 가능한 반면 (예: `onclick` 핸들러는 거의 어떠한 요소에서도 등록될 수 있습니다), 몇몇은 더욱 특수하고 오직 어떤 상황들에서만 유용합니다 (예: onplay (en-US)를 오직 `<video>`와 같은, 특정한 요소에서만 사용하는 것은 타당합니다).

### 인라인 이벤트 핸들러 — 사용하지 마세요

여러분은 또한 코드에서 이것과 같은 패턴을 봤을 지도 모릅니다:

```html
<button onclick="bgChange()">Press me</button>
```

```js
function bgChange() {
  const rndCol =
    "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")";
  document.body.style.backgroundColor = rndCol;
}
```

**참고:** #### 참고여러분은 이 예제에 대한 전체 소스 코드를 Github에서 찾을 수 있습니다 (또한 실제로 작동하는 모습도 보세요).

웹에서 찾아지는 가장 이른 이벤트 핸들러의 등록 방법은 위에서 보이는 것처럼 **이벤트 핸들러 HTML 어트리뷰트** (또는 **인라인 이벤트 핸들러**)을 포함합니다. — 어트리뷰트 값은 말 그대로 이벤트가 발생되었을 때 여러분이 실행하기를 원하는 JavaScript 코드입니다. 위의 예시는 같은 페이지의 `<script>` 요소 안에서 정의된 함수를 호출하지만, 여러분은 또한 어트리뷰트 안에 직접적으로 JavaScript을 삽입할 수 있습니다. 예를 들자면:

```html
<button onclick="alert('Hello, this is my old-fashioned event handler!');">
  Press me
</button>
```

여러분은 HTML 어트리뷰트를 많은 이벤트 핸들러 프로퍼티와 동등한 것이라고 생각할 수도 있습니다; 그러나, 여러분은 이 방법을 사용해서는 안 됩니다 — 이 방법은 나쁜 습관이라고 여겨집니다. 만약 여러분이 뭔가를 정말 빨리 한다면 이벤트 핸들러 어트리뷰트를 사용하는 것이 쉬워 보일지도 모르나, 이것은 빠르게 다루기 힘들어지고 비효율적이 됩니다.

우선, HTML과 JavaScript를 뒤죽박죽으로 만드는 것은 좋은 생각이 아닙니다. 왜냐하면 분석하기(parse)가 어려워지기 때문입니다 — JavaScript를 분리한 채로 놔두는 것이 좋은 습관입니다; 만약 이것이 분리된 파일 안에 있다면 여러분은 이것을 다수의 HTML 문서에 적용할 수 있습니다.

하나의 파일이더라도, 인라인 이벤트 핸들러는 좋은 생각이 아닙니다. 하나의 버튼은 괜찮지만, 100개의 버튼이라면 어떡할 건가요? 여러분은 파일에 100개의 어트리뷰트를 더해야만 합니다; 이것은 빠르게 유지보수의 악몽으로 변할 것입니다. JavaScript와 함께, 다음과 같은 것을 통해서, 여러분은 버튼이 얼마나 있든 간에 페이지에 있는 모든 버튼에 쉽게 이벤트 핸들러를 추가할 수 있습니다.

```js
const buttons = document.querySelectorAll("button");

for (let i = 0; i < buttons.length; i++) {
  buttons[i].onclick = bgChange;
}
```

여기서의 또 다른 옵션은 `NodeList` 객체에서 사용 가능한 `forEach()` 내장 메서드를 사용하는 것이라는 데 주목해 주세요.

```js
buttons.forEach(function (button) {
  button.onclick = bgChange;
});
```

**참고:** #### 참고프로그래밍 로직을 콘텐츠로부터 분리하는 것은 또한 여러분의 사이트를 검색 엔진에 더욱 친화적으로 만듭니다.

### 이벤트 핸들러를 추가하고 제거하기

이벤트 핸들러를 더하는 현대적인 메커니즘은 `addEventListener()` 메서드입니다. 이것을 사용해서, 우리는 무작위 색상 예제를 다음과 같이 재작성할 수 있습니다.

```js
const btn = document.querySelector("button");

function bgChange() {
  const rndCol =
    "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")";
  document.body.style.backgroundColor = rndCol;
}

btn.addEventListener("click", bgChange);
```

**참고:** 여러분은 이 예제에 대한 전체 소스 코드를 Github에서 찾을 수 있습니다 (또한 실제로 작동하는 모습도 보세요).

`addEventListener()` 함수 안에, 우리는 두 매개변수(parameter)를 명시합니다: 우리가 이 핸들러에 등록하고자 하는 이벤트의 이름과, 그것에 응답하여 우리가 실행하기를 원하는 핸들러 함수를 구성하는 코드입니다. 알림: `addEventListener()` 내부에, 다음과 같이, 익명 함수 안에 모든 코드를 넣는 것은 완벽히 괜찮습니다:

```js
btn.addEventListener("click", function () {
  var rndCol =
    "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")";
  document.body.style.backgroundColor = rndCol;
});
```

이 메커니즘은 앞에서 논한 낡은 메커니즘들에 비해 몇몇 이점을 가지고 있습니다. 첫째로, 이전에 추가한 이벤트 핸들러를 제거하는, `removeEventListener()`라는 대응 관계에 있는 함수가 있습니다. 예를 들어, 이것은 이 섹션의 첫번째 코드 블록 안에 있는 이벤트 핸들러를 제거할 것입니다.

```js
btn.removeEventListener("click", bgChange);
```

이벤트 핸들러는 또한 `AbortSignal`을 `addEventListener()`에 전달하고, 그리고서 나중에, `AbortSignal`을 소유하고 있는 컨트롤러에서 `abort()`를 호출함으로써 제거할 수도 있습니다. 예를 들자면, 우리가 `AbortSignal`로 제거할 수 있는 이벤트 핸들러를 추가하기 위해서는:

```js
const controller = new AbortController();
btn.addEventListener(
  "click",
  function () {
    var rndCol =
      "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")";
    document.body.style.backgroundColor = rndCol;
  },
  { signal: controller.signal },
); // 이 핸들러에 AbortSignal을 전달
```

그리고서 위의 코드로 생성된 이벤트 핸들러는 다음과 같이 제거될 수 있습니다:

```js
controller.abort(); // 이 컨트롤러와 연관된 어떠한/모든 이벤트 핸들러를 제거
```

간단하고, 작은 프로그램에 대해서는, 낡고, 사용되지 않는 이벤트 핸들러를 청소하는 것은 필수적이지 않습니다 — 하지만 더 크고, 더욱 복잡한 프로그램에 대해서는, 이것은 효율성을 향상시킬 수 있습니다. 더해서, 이벤트 핸들러를 제거할 수 있는 능력은 같은 버튼이 다른 상황에서 다른 작동을 수행하도록 하는 것을 가능케 합니다.

앞서 논한 낡은 메커니즘에 대해 `addEventListener()` 가 가지고 있는 두 번째 이점은 같은 리스너에 대해 다수의 핸들러를 등록하는 것을 가능하게 한다는 것입니다. 다음의 두 핸들러는 둘 다 적용되지 않을 것입니다:

```js
myElement.onclick = functionA;
myElement.onclick = functionB;
```

두 번째 줄이 첫 번째 줄에 의해 설정된 `onclick`의 값을 덮어씁니다. 그러나, 다음은 작동할 것입니다.

```js
myElement.addEventListener("click", functionA);
myElement.addEventListener("click", functionB);
```

두 함수 모두는 이제 요소가 선택되었을 때 실행될 것입니다.

추가적으로, 이 이벤트 메커니즘과 함께 이용 가능한 옵션과 강력한 다른 기능들이 있습니다. 이것들은 이 문서의 범위를 조금 벗어나지만, 만약 그것들을 읽고 싶으시다면, `addEventListener()` 와 `removeEventListener()` 참조 페이지를 방문해 보세요.

### 어떤 메커니즘을 사용해야만 하는가?

이 세 가지 메커니즘 중에서, 여러분은 HTML 이벤트 핸들러 어트리뷰트를 사용해서는 안 됩니다 — 이것은 위에서 언급되었다시피, 구식이고, 나쁜 습관입니다.

다른 두 가지는, 적어도 간단한 사용에 대해서는, 비교적 서로 바꿀 수 있습니다.

* 이벤트 핸들러 프로퍼티는 더 적은 능력과 옵션을 가지고 있지만, 더 나은 크로스 브라우저 호환성을 가지고 있습니다 (Internet Explorer 8만큼 옛날 브라우저에서도 지원됨). 여러분은 아마도 학습을 시작하면서 이것들과 함께 시작해야 합니다.
* DOM Level 2 이벤트 (`addEventListener()` 등)은 더욱 강력하지만, 또한 복잡하며 덜 지원됩니다 (Internet Explorer 9만큼 옛날 브라우저에서 지원됨). 여러분은 또한 이것들로 실험해봐야 하고, 가능한 곳에서 사용해봐야 합니다.

세 번째 메커니즘의 주된 이점은, 필요하다면 `removeEventListener()`을 사용하여 이벤트 핸들러 코드를 삭제할 수 있고, 만약 요구된다면 같은 타입의 다수의 리스너를 요소들에 추가할 수 있다는 것입니다. 예를 들어, 여러분은 요소에 `addEventListener('click', function() { ... })`를, 두 번째 인자(argument)에 다른 함수를 명시한 채로, 여러 번 호출할 수 있습니다. 이것은 이벤트 핸들러 프로퍼티로는 불가능합니다. 왜냐하면 프로퍼티를 설정하려는 어떠한 연이은 시도도 앞선 것들을 덮어쓸 것이기 때문입니다. 예를 들자면:

```js
element.onclick = function1;
element.onclick = function2;
등등.
```

**참고:** #### 참고만약 여러분이 Internet Explorer 8보다 오래된 브라우저를 지원하라고 요청받았다면, 그러한 아주 오래된 브라우저들은 새로운 브라우저들과는 다른 이벤트 모델을 사용하므로, 여러분은 어려움을 만날 지도 모릅니다. 하지만 걱정하지 마세요, 대부분의 JavaScript 라이브러리들은 (예를 들자면 `jQuery`) 크로스 브라우저 차이를 분리하는 내장 함수들을 가지고 있습니다. 이 배움의 단계에서 이것을 너무 많이는 걱정하지 마세요.

다른 이벤트 개념들
----------

이 섹션에서는, 우리는 간략하게 이벤트에 관련된 몇몇 고급 개념들을 다룹니다. 이 개념들을 이 지점에서 완전히 이해하는 것은 중요하지 않지만, 여러분이 마주칠 가능성이 있는 몇몇 코드 패턴의 설명을 제공할지도 모릅니다.

### 이벤트 객체

때때로 이벤트 핸들러 함수 내부에서, 여러분은 `event`, `evt`, 혹은 `e`와 같은 이름으로 명명된 매개변수(parameter)를 봤을 것입니다. 이것들은 **이벤트 객체**라고 불리고, 추가적인 기능과 정보를 제공하기 위해 이벤트 핸들러에 자동으로 전달됩니다. 예시로, 무작위 색상 예제를 다시 약간 재작성해 봅시다.

```js
function bgChange(e) {
  const rndCol =
    "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")";
  e.target.style.backgroundColor = rndCol;
  console.log(e);
}

btn.addEventListener("click", bgChange);
```

**참고:** #### 참고여러분은 이 예제에 대한 전체 소스 코드를 Github에서 찾을 수 있습니다 (또한 실제로 작동하는 모습도 보세요).

여기서 여러분은 우리가 이벤트 객체, **e**를, 함수에 포함하고, 함수에서 배경 색상 스타일을 — 버튼 그 자체인 — `e.target`에서 설정한 것을 볼 수 있습니다. 이벤트 객체의 `target` 프로퍼티는 항상 이벤트가 발생된 요소에 대한 참조입니다. 그래서, 이 예제에서, 우리는 무작위의 배경색을 페이지가 아니라, 버튼에 설정했습니다.

**참고:** #### 참고여러분은 이벤트 객체에 대해 여러분이 좋아하는 어떠한 이름이든 사용할 수 있습니다 — 여러분은 단지 이벤트 핸들러 함수 내에서 그것을 참조하기 위해 사용할 수 있는 이름을 선택할 필요가 있습니다. `e`/`evt`/`event`가 가장 일반적으로 개발자들에 의해 사용됩니다. 왜냐하면 짧고 기억하기 쉽기 때문입니다. 일관적인 것은 항상 좋습니다 — 여러분 자신과, 그리고 만약 가능하다면 타인과.

여러분이 같은 이벤트 핸들러를 다수의 요소에 설정하고 그것들에 이벤트가 발생되었을 때 그것들 모두에 뭔가를 하기를 원할 때 `e.target`은 엄청나게 유용합니다. 예를 들자면, 여러분에게 선택되었을 때 사라지는 16개의 타일 세트가 있다고 합시다. 타일을 몇몇 더욱 어려운 방법으로 선택해야만 하는 것 대신에, `e.target`으로서 단지 타일을 사라지게 항상 설정할 수 있는 것은 유용합니다. 다음의 예제에서 (전체 소스 코드는 useful-eventtarget.html에서 찾을 수 있습니다; 또한 실제로 작동하는 모습도 보세요), 우리는 16개의 `<div>` (en-US) 요소를 JavaScript를 통해 생성했습니다. 우리는 그리고서 `document.querySelectorAll()`을 사용해 그것들 모두를 선택했고, 그리고서 선택되었을 때 무작위 색상이 적용되도록 만드는 `onclick` 핸들러를 각각에 추가하며 요소들을 순회했습니다:

```js
const divs = document.querySelectorAll("div");

for (let i = 0; i < divs.length; i++) {
  divs[i].onclick = function (e) {
    e.target.style.backgroundColor = bgChange();
  };
}
```

출력은 다음과 같습니다 (타일들을 클릭해 보세요 — 즐겨 보세요):
```

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Useful event target example</title>
    <style>
 div {
 height: 100px;
 width: 25%;
 float: left;
 }
 </style>
  </head>
  <body>
    <script>
 for (let i = 1; i <= 16; i++) {
 const myDiv = document.createElement("div");
 myDiv.style.backgroundColor = "red";
 document.body.appendChild(myDiv);
 }

 function random(number) {
 return Math.floor(Math.random() \* number);
 }

 function bgChange() {
 var rndCol =
 "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")";
 return rndCol;
 }

 const divs = document.querySelectorAll("div");

 for (let i = 0; i < divs.length; i++) {
 divs[i].onclick = function (e) {
 e.target.style.backgroundColor = bgChange();
 };
 }
 </script>
  </body>
</html>
```

여러분이 만날 대부분의 이벤트 핸들러들은 이벤트 객체에서 사용 가능한 표준 프로퍼티와 함수 (메서드) 집합을 가지고 있습니다; 전체 리스트를 위해 `Event` 객체 레퍼런스를 참조해 보세요. 그러나 몇몇의 더욱 고급 핸들러들은 그들이 기능하기를 필요로 하는 추가적인 데이터를 포함하는 전문적인 프로퍼티들을 추가합니다. 예를 들어, Media Recorder API (en-US)는 `dataavailable` 이벤트를 가지고 있는데, 이는 몇몇 오디오나 비디오가 기록되고 뭔가를 할 수 있을 때 (예를 들자면 저장하거나, 다시 재생하거나) 발생됩니다. 해당하는 ondataavailable (en-US) 핸들러의 이벤트 객체는 여러분이 그것에 접근하거나 그것으로 무언가를 할 수 있게 하는 녹화된 오디오나 비디오 데이터를 포함하는 이용 가능한 `data` 프로퍼티를 가지고 있습니다.

### 기본 행동 방지하기

때때로, 이벤트가 기본으로 하는 것을 방지하고 싶은 상황에 마주칠 수 있습니다. 가장 일반적인 예제는 웹 양식에 관한 것인데, 예를 들자면, 커스텀 등록 양식입니다. 세부 사항을 채우고 제출 버튼을 선택했을 때, 자연적인 행동은 데이터가 처리를 위해 서버에 있는 명시된 페이지로 제출되는 것이고, 브라우저는 몇몇 종류의 "성공 메시지" 페이지로 리다이렉트되는 것입니다 (혹은 만약 다른 것이 명시되지 않았다면, 같은 페이지로).

문제는 유저가 데이터를 옳게 제출하지 않았을 때 발생합니다 — 개발자로서, 여러분은 서버로의 제출을 방지하고 무엇이 잘못되었고 옳게 되기 위해 무엇이 완료되어야 하는지를 말하는 에러 메시지를 주기를 원합니다. 몇몇 브라우저는 자동 양식 데이터 확인 기능을 제공하지만, 많은 브라우저들은 그렇지 않으므로, 그것들에 의존하지 않고 여러분만의 점검 기능을 구현하는 것이 낫습니다. 간단한 예제를 살펴봅시다.

우선, 이름과 성을 입력하기를 요구하는 간단한 HTML 양식입니다.

```html
<form>
  <div>
    <label for="fname">First name: </label>
    <input id="fname" type="text" />
  </div>
  <div>
    <label for="lname">Last name: </label>
    <input id="lname" type="text" />
  </div>
  <div>
    <input id="submit" type="submit" />
  </div>
</form>
<p></p>
```

```
div {
  margin-bottom: 10px;
}
```

이제 JavaScript입니다 — 여기 우리는 텍스트 필드가 비었는지를 검사하는 `onsubmit` 이벤트 핸들러 (제출 이벤트는 양식이 제출되었을 때 발생됩니다) 내부에 아주 간단한 점검을 구현했습니다. 만약 텍스트 필드가 비었다면, 우리는 이벤트 객체에 있는 — 양식 제출을 멈추는 — `preventDefault()` 함수를 호출하고 그리고서 유저에게 무엇이 잘못되었는지를 말하기 위해 양식 아래에 있는 단락에 에러 메시지를 표시합니다.

```js
const form = document.querySelector("form");
const fname = document.getElementById("fname");
const lname = document.getElementById("lname");
const para = document.querySelector("p");

form.onsubmit = function (e) {
  if (fname.value === "" || lname.value === "") {
    e.preventDefault();
    para.textContent = "You need to fill in both names!";
  }
};
```

명백히, 이것은 아주 약한 양식 확인입니다 — 예를 들자면, 필드에 공백이나 숫자가 입력된 채의 양식을 확인하는 유저를 멈추지 못할 것입니다 — 하지만 예제의 목적으로라면 괜찮습니다. 결과는 다음과 같습니다.

**참고:** #### 참고전체 코드 소스는 preventdefault-validation.html에서 확인하실 수 있습니다 (또한 여기서 실제로 작동하는 모습도 보세요).

### 이벤트 버블링과 캡처

여기서 다룰 마지막 주제는 여러분이 종종 마주치지 못할 무언가이지만, 만약 여러분이 이것을 이해하지 못한다면 진짜 고통일 것입니다. 이벤트 버블링과 캡처는 같은 이벤트 타입의 두 이벤트 핸들러가 한 요소에서 작동되었을 때 무슨 일이 일어나는지를 기술하는 두 메커니즘입니다. 이것을 쉽게 만드는 예시를 봅시다. show-video-box.html 예시와 (소스 코드를 다른 탭에서) 여세요. 이것은 또한 아래에서 바로 이용 가능합니다.
```

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Show video box example</title>
    <style>
 div {
 position: absolute;
 top: 50%;
 transform: translate(-50%, -50%);
 width: 480px;
 height: 380px;
 border-radius: 10px;
 background-color: #eee;
 background-image: linear-gradient(
 to bottom,
 rgba(0, 0, 0, 0),
 rgba(0, 0, 0, 0.1)
 );
 }

 .hidden {
 left: -50%;
 }

 .showing {
 left: 50%;
 }

 div video {
 display: block;
 width: 400px;
 margin: 40px auto;
 }
 </style>
  </head>
  <body>
    <button>Display video</button>

    <div class="hidden">
      <video>
        <source
 src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.mp4"
 type="video/mp4" />
        <source
 src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.webm"
 type="video/webm" />
        <p>
          Your browser doesn't support HTML5 video. Here is a
          <a href="rabbit320.mp4">link to the video</a> instead.
        </p>
      </video>
    </div>

    <script>
 const btn = document.querySelector("button");
 const videoBox = document.querySelector("div");
 const video = document.querySelector("video");

 btn.onclick = function () {
 displayVideo();
 };

 function displayVideo() {
 if (videoBox.getAttribute("class") === "hidden") {
 videoBox.setAttribute("class", "showing");
 }
 }

 videoBox.addEventListener("click", function () {
 videoBox.setAttribute("class", "hidden");
 });

 video.addEventListener("click", function () {
 video.play();
 });
 </script>
  </body>
</html>
```

이것은 `<video>`를 내부에 가지고 있는 `<div>` (en-US)를 보이고 감추는 아주 간단한 예제입니다.

```html
<button>Display video</button>

<div class="hidden">
  <video>
    <source src="rabbit320.mp4" type="video/mp4" />
    <source src="rabbit320.webm" type="video/webm" />
    <p>
      Your browser doesn't support HTML5 video. Here is a
      <a href="rabbit320.mp4">link to the video</a> instead.
    </p>
  </video>
</div>
```

`<button>`이 선택되었을 때, `<div>`의 클래스 어트리뷰트를 `hidden`에서 `showing`으로 바꿈으로써, 비디오는 표시됩니다. (예제의 CSS는 이 두 클래스를 포함하고 있는데, 각각 박스를 화면에서 벗어나게 만들고 들어오게 위치시킵니다):

```js
btn.onclick = function () {
  videoBox.setAttribute("class", "showing");
};
```

우리는 그리고서 두 개의 `onclick` 이벤트 핸들러를 추가합니다 — 첫번째는 `<div>`에 대한 것이고 두번째는 `<video>`에 대한 것입니다. 이제, 비디오 외부의 `<div>` 영역이 선택되었을 때, 박스는 다시 숨겨져야만 하고 비디오 그 자체가 선택되었을 때, 비디오는 재생을 시작해야만 합니다.

```js
videoBox.onclick = function () {
  videoBox.setAttribute("class", "hidden");
};

video.onclick = function () {
  video.play();
};
```

하지만 문제가 있습니다 — 현재, 비디오를 클릭했을 때 이것은 재생을 시작하나, 동시에 `<div>`가 숨겨지는 것을 유발합니다. 이것은 왜냐하면 비디오가 `<div>` 내부에 있기 때문입니다 — 비디오는 div의 부분입니다 — 그래서 비디오를 선택하는 것은 실제로는 위의 *두 이벤트 핸들러를 다* 실행합니다.

#### 버블링과 캡처링 설명

부모 요소를 가지고 있는 요소에서 이벤트가 발생되었을 때 (이 경우, `<video>`는 부모로서의 `<div>` (en-US)를 가지고 있습니다), 현대의 브라우저들은 두 가지 다른 단계(phase)를 실행합니다 — **캡처링**(capturing) 단계와 **버블링**(bubbling) 단계입니다.

**캡처링** 단계에서는:

* 브라우저는 요소의 가장 바깥쪽의 조상 (`<html>`)이 캡처링 단계에 대해 그것에 등록된 `onclick` 이벤트 핸들러가 있는지를 확인하기 위해 검사하고, 만약 그렇다면 실행합니다.
* 그리고서 `<html>` 내부에 있는 다음 요소로 이동하고 같은 것을 하고, 그리고서 그 다음 요소로 이동하고, 실제로 선택된 요소에 닿을 때까지 계속합니다.

**버블링** 단계에서는, 정확히 반대의 일이 일어납니다:

* 브라우저는 선택된 요소가 버블링 단계에 대해 그것에 등록된 `onclick` 이벤트 핸들러를 가지고 있는지 확인하기 위해 검사하고, 만약 그렇다면 실행합니다.
* 그리고서 그것은 바로 다음의 조상 요소로 이동하고 같은 일을 하고, 그리고서 그 다음 요소로 이동하고, `<html>` 요소에 닿을 때까지 계속합니다.

![](/ko/docs/Learn/JavaScript/Building_blocks/Events/bubbling-capturing.png)

(더 큰 도표를 보려면 이미지를 클릭하세요)

현대의 브라우저들은, 기본으로, 모든 이벤트 핸들러들은 버블링 단계에 대해 등록되어 있습니다. 그래서 우리의 현재 예제에서는, 비디오를 선택했을 때, 이벤트는 `<video>` 요소로부터 밖으로 나가 `<html>` 요소까지 올라갑니다(bubble). 그 동안 다음이 일어납니다:

* `video.onclick...` 핸들러를 발견하고 실행하므로, 비디오가 먼저 재생을 시작합니다.
* 그리고서 `videoBox.onclick...` 핸들러를 발견하고 실행하므로, 비디오는 또한 숨겨집니다.

**참고:** #### 참고버블링과 캡처링, 두 타입의 이벤트 핸들러가 모두 존재하는 경우에, 캡처링 단계가 먼저 실행되고, 이어서 버블링 단계가 실행됩니다.

#### stopPropagation()으로 문제 고치기

이것은 몹시 짜증나는 움직임이지만, 고칠 방법이 있습니다! 표준 `Event` 객체는 `stopPropagation()`라 불리는 사용 가능한 함수를 가지고 있는데, 핸들러의 이벤트 객체가 호출되었을 때, 이는 첫번째 핸들러가 실행되지만 이벤트가 더 이상 위로 전파되지 않도록 만들어, 더 이상의 핸들러가 실행되지 않도록 합니다.

그러므로, 이전 코드 블럭에 있는 두 번째 핸들러 함수를 다음으로 변경함으로써 우리는 현재의 문제를 고칠 수 있습니다:

```js
video.onclick = function (e) {
  e.stopPropagation();
  video.play();
};
```

show-video-box.html 소스 코드를 다운받아 직접 고쳐볼 수도 있고, show-video-box-fixed.html에서 고쳐진 결과를 볼 수도 있습니다 (또한 여기서 소스 코드를 보세요).

**참고:** #### 참고왜 캡처링과 버블링으로 애를 쓰냐구요? 글쎄요, 브라우저들이 지금보다 훨씬 덜 호환되던 옛날의 좋지 못하던 시절에, Netscape는 오직 이벤트 캡처링만을 사용했고, Internet Explorer는 오직 이벤트 버블링만을 사용했습니다. W3C가 이 움직임을 표준화하고 합의에 이르기를 시도하기로 결정했을 때, 그들은 양 쪽을 다 포함하는 이 시스템을 채용하게 되었는데, 이것이 현대 브라우저들이 구현한 것입니다.

**참고:** #### 참고위에서 언급했다시피, 기본적으로 모든 이벤트 핸들러는 버블링 단계에 등록되어 있고, 이것은 대부분의 경우 더 타당합니다. 만약 정말로 이벤트를 캡처링 단계에 대신 등록하기를 원한다면, `addEventListener()`를 사용하고, 옵션인 세 번째 프로퍼티를 `true`로 설정하여 핸들러를 등록함으로써 그렇게 할 수 있습니다.

#### 이벤트 위임(Event delegation)

버블링은 또한 **이벤트 위임**의 이점을 취할 수 있게 합니다 — 이 개념은 만약 다수의 자식 요소 중 하나를 선택했을 때 코드를 실행하기를 원한다면, 모든 자식에 개별적으로 이벤트 리스너를 설정해야만 하는 것 대신 이벤트 리스너를 그들의 부모에 설정하고 그들에게서 일어난 이벤트가 그들의 부모에게까지 올라오게 할 수 있다는 사실에 의존합니다. 기억하세요, 버블링은 이벤트 핸들러에 대해 이벤트가 발생된 요소를 먼저 검사하고서, 요소의 부모 등등으로 올라가는 것을 포함합니다.

하나의 좋은 예시는 일련의 리스트 아이템들입니다 — 만약 각각이 선택되었을 때 메시지를 띄우기(pop up)를 원한다면, 여러분은 `click` 이벤트 리스너를 부모 `<ul>`에 설정할 수 있고, 이벤트들은 리스트 아이템들에서 `<ul>`까지 올라갈 것입니다.

이 개념은 David Walsh의 블로그에서, 다수의 예제와 함께 더 설명됩니다. 어떻게 JavaScript 이벤트 위임은 작동하는가를 보세요..

실력을 평가해 보세요!
------------

이 문서를 끝까지 읽으셨지만, 중요한 것들을 여전히 기억하고 계신가요? 다음 문서를 읽기 전에 이 문서의 내용을 잘 학습하고 이해하셨는지 확인하실 수 있습니다 — 실력을 평가해 보세요: 이벤트.

결론
--

여러분은 이제 이 이른 단계에서의 웹 이벤트에 대해 알아야 할 모든 것들을 알고 계실 것입니다. 언급했듯이, 이벤트는 코어 JavaScript의 일부가 정말 아닙니다 — 이것들은 브라우저 웹 API에 정의되어 있습니다.

또한, JavaScript가 쓰이는 다른 맥락들은 다른 이벤트 모델들을 가지고 있다는 것을 이해하는 것은 중요합니다 — 웹 API에서 브라우저 WebExtensions과 Node.js (서버사이드 JavaScript)와 같은 다른 영역들까지. 우리는 이 모든 영역을 지금 여러분이 이해하기를 기대하지는 않지만, 이것은 여러분이 웹 개발을 배우며 나아가는 동안 이벤트의 기본을 이해하는 것을 분명히 돕습니다.

만약 뭐든지 이해하지 못한 게 있다면, 자유롭게 이 문서를 다시 읽거나, 문의하기에서 도움을 요청해 보세요.

같이 보기
-----

* domevents.dev — 탐험을 통해 DOM 이벤트 시스템의 움직임에 대한 배울 수 있는 매우 유용한 인터랙티브 놀이터 앱
* 이벤트 참고서 (en-US)
* 이벤트 순서 (캡처링과 버블링에 대한 논의) — Peter-Paul Koch가 작성한 뛰어나게 상세한 글
* 이벤트 접근 (이벤트 객체에 대한 논의) — Peter-Paul Koch가 작성한 또 다른 뛰어나게 상세한 글
* 이전
* Overview: Building blocks
* 다음


실력을 평가해 보세요: 반복문 - Web 개발 학습하기

실력을 평가해 보세요: 반복문
================

이 실력 테스트의 목적은 여러분이 우리의 반복문 문서를 이해했는지를 평가하기 위함입니다.

**참고:** 여러분은 코드를 다운로드하고, CodePen, jsFiddle, 또는 Glitch와 같은 온라인 툴(tool)에 넣고, 그리고서 과제에 도전해 봄으로써 아래의 과제들에 대한 해답을 시도해볼 수 있습니다. 무한 루프를 만들고 평가 페이지를 멈추게 하는 위험 때문에 우리는 이 과제들에 대해 실시간으로 수정 가능한 에디터를 제공하지 않았습니다!

만약 막히면, 도움을 요청하세요 — 이 페이지 아래의 Assessment or further help 섹션을 보세요.

DOM 조작: 유용하다고 생각됨
-----------------

아래의 몇몇 문제들은 여러분에게 문제 해결을 위해서 몇몇 DOM 조작 코드를 작성하기를 요구합니다 — 새로운 HTML 요소 생성하기, 특정한 문자열 값과 동일한 텍스트 콘텐츠 설정하기, 그리고 페이지에 존재하는 요소 내부에 중첩하기와 같은 — 모두 JavaScript를 통해서.

우리는 이것을 아직 이 코스에서 분명하게 가르치지 않았지만, 여러분은 이것을 사용하는 몇몇 예제를 보았고, 우리는 여러분이 문제에 성공적으로 답하기 위해 어떤 DOM API들이 필요한지에 대해 검색하기를 원합니다. 좋은 시작점은 우리의 문서 조작하기 (en-US)(Manipulating documents) 튜토리얼입니다.

반복문 1
-----

우리의 첫 반복문 과제에서 우리는 여러분이 제공된 `myArray` 내의 모든 요소를 순회하고, 제공된 `list`에 추가될 리스트 아이템 (예: `<li>` 요소) 내에서 화면에 그것들을 출력하는 간단한 반복문을 만듦으로써 시작하기를 원합니다.

**참고:** 여러분의 에디터나 온라인 에디터에서 작업하기 위해서 이 과제의 시작점을 다운로드하세요.

반복문 2
-----

이 다음 과제에서, 우리는 여러분이, 이름이 주어지면 이름과 전화번호 (`phonebook`)를 포함하고 있는 객체 배열을 탐색하고, 만약 그 이름을 찾으면, 이름과 전화번호를 단락 (`para`)에 출력하고 그리고서 반복문이 다 실행되기 전에 반복문을 빠져나오는 간단한 프로그램을 작성하기를 원합니다.

3개의 변수가 주어집니다:

* `i` — 0의 값에서 시작합니다; 반복자(iterator)로써 쓰이게 의도되었습니다.
* `name` — 검색할 이름을 포함하고 있습니다.
* `para` — 단락에 대한 참조를 포함하고 있는데, 결과를 보이기 위해 사용될 것입니다.

여러분은 전 과제에서 사용하지 않은 유형의 반복문을 사용해야 합니다.

**참고:**

여러분의 에디터나 온라인 에디터에서 작업하기 위해서 이 과제의 시작점을 다운로드하세요.

반복문 3
-----

이 마지막 과제에서는, 다음의 것들이 제공됩니다:

* `i` — 500의 값으로 시작합니다; 반복자로써 쓰이게 의도되었습니다.
* `para` — 단락에 대한 참조를 포함하고 있는데, 결과를 보이기 위해 사용될 것입니다.
* `isPrime()` — 숫자가 전달되었을 때, 만약 숫자가 소수(prime number)면, `true`를 반환하고, 아니면 `false`를 반환하는 함수.

여러분은 숫자 2에서 500까지 뒤로 가는 반복문을 사용하고 (1은 소수에 포함되지 않습니다), 제공된 `isPrime()` 함수를 그 숫자들에서 실행할 필요가 있습니다. 소수가 아닌 각 숫자에 대해서는, 다음 반복으로 계속하세요. 소수인 각 숫자에 대해서는, 그것을 단락의 `textContent`에 몇몇 종류의 분리자(separator)에 덧붙여 추가하세요.

여러분은 이전의 두 과제에서 사용하지 않은 유형의 반복문을 사용해야 합니다.

**참고:** 여러분의 에디터나 온라인 에디터에서 작업하기 위해서 이 과제의 시작점을 다운로드하세요.

평가 혹은 추가적인 도움
-------------

만약 여러분의 작업을 평가받고 싶으시거나 막혀서 도움을 요청하기를 원하신다면:

1. 여러분의 작업을 CodePen, jsFiddle, 또는 Glitch와 같은 온라인에서 공유 가능한 에디터에 올리세요. 여러분은 코드를 직접 작성할 수도 있고, 혹은 위 섹션에 링크된 시작 파일을 사용할 수도 있습니다.
2. MDN Discourse forum Learning category 에 평가 및/또는 도움을 요청하는 글을 작성하세요. 여러분의 글은 다음을 포함해야만 합니다:
    * "반복문 1 실력 테스트에 대한 평가 원함"과 같은 서술적인 제목.
    * 여러분이 이미 무엇을 시도해 봤는지, 그리고 우리가 무엇을 하기를 원하는지에 대한 설명. 예를 들자면, 막혀서 도움이 필요하다거나, 평가를 원한다거나 하는 설명을 포함해야 합니다.
    * (위의 단계 1에서 언급된) 온라인에서 공유 가능한 에디터에 있는, 여러분이 평가를 원하거나 도움이 필요한 예제의 링크. 이것은 익숙해지기에 좋은 습관입니다. 코딩 문제가 있는 누군가를 도울 때, 그들의 코드를 보지 못한다면 그들을 돕는 것은 몹시 힘듭니다.
    * 우리가 여러분이 도움을 원하는 문제를 찾을 수 있도록, 실제 과제나 평가 페이지의 링크.


함수 반환 값 - Web 개발 학습하기

함수 반환 값
=======

* 이전
* Overview: Building blocks
* 다음

함수에 대해 우리가 이야기해야 할 마지막 한 가지 필수적인 개념이 있습니다 — 반환 값(return value)입니다. 몇몇 함수들은 중요한 값을 반환(return)하지 않지만, 다른 함수들은 반환합니다. 그 값들이 무엇인지, 그것들을 어떻게 사용하는지, 그리고 어떻게 함수가 유용한 값을 반환하게 만드는지를 이해하는 것은 중요합니다. 우리는 이 모든 것을 아래에서 다룰 것입니다.

|  |  |
| --- | --- |
| 필요한 사전 지식: |
 기본적인 컴퓨터 사용 능력, HTML과 CSS에 대한 기본적인 이해,
 JavaScript 첫걸음,
 함수 — 코드 재사용.
  |
| 목표: | 함수 반환 값과, 어떻게 그것을 사용하는지 이해하기. |

반환 값이 무엇인가요?
------------

**반환 값**(return value)이란 그냥 들리는 그대로입니다 — 함수가 완료되었을 때 함수가 반환하는 값입니다. 여러분은 이미 수 차례 반환 값을 마주쳤습니다. 비록 그것들에 대해 분명하게 생각하지는 않았을지도 모르지만요.

(이 시리즈의 지난 문서에서 본) 익숙한 예제로 돌아가 봅시다.

```js
let myText = "The weather is cold";
let newString = myText.replace("cold", "warm");
console.log(newString); // Should print "The weather is warm"
// replace() 문자열 함수는 문자열을 취해서,
// 부분열(substring)을 다른 것으로 바꾸고,
// 새로운 문자열을 반환합니다.
```

`replace()` (en-US) 함수는 `myText` 문자열에서 호출되었고, 두 매개변수(parameter)를 전달받았습니다:

1. 찾을 부분열 ('cold').
2. 바꿀 문자열 ('warm').

이 함수가 완료되었을 (실행을 끝냈을) 때, 값을 반환하는데, 그것은 교체된 문자열입니다. 위의 코드에서, 이 반환 값의 결과는 `newString`에 저장됩니다.

`replace()` (en-US) 함수 MDN 레퍼런스 페이지를 본다면, return value (en-US) 라는 섹션을 보게 될 것입니다. 어떤 값이 함수에 의해 반환되는지 이해하고 아는 것은 몹시 유용합니다. 어디든지 가능한 곳에 이 정보를 사용해 볼 수 있도록 말입니다.

어떤 함수들은 어떠한 값도 반환하지 않습니다. (이 경우, 우리의 레퍼런스 페이지는 반환 값을 `void` 나 `undefined`로 보여줍니다.) 예를 들면, 지난 문서에서 우리가 만든 `displayMessage()` 함수에서, 어떤 특정한 값도 함수가 호출되었을 때 반환되지 않습니다. 이 함수는 단지 화면 어딘가에 박스가 나타나게 만들 뿐입니다 — 그게 전부입니다!

일반적으로, 반환 값은 함수가 어떤 종류의 계산에서의 중간 단계인 곳에서 사용됩니다. 최종 결과를 얻기 위해, 몇몇 값들은 함수에 의해 계산될 필요가 있을 수 있습니다. 함수가 값을 계산한 이후에, 결과가 변수에 저장될 수 있도록 함수는 계산 결과를 반환합니다; 그리고 다음 단계의 계산에서 그 변수를 사용할 수 있습니다.

### 사용자 정의 함수에서 반환 값 사용하기

사용자 정의(custom) 함수에서 값을 반환하기 위해서는, return 키워드를 사용할 필요가 있습니다. 우리는 최근에 이것을 random-canvas-circles.html 예제에서 보았습니다. `draw()` 함수는 무작위의 원 100개를 HTML `<canvas>`에 그립니다:

```js
function draw() {
  ctx.clearRect(0, 0, WIDTH, HEIGHT);
  for (let i = 0; i < 100; i++) {
    ctx.beginPath();
    ctx.fillStyle = "rgba(255,0,0,0.5)";
    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 \* Math.PI);
    ctx.fill();
  }
}
```

각 반복 내에서, 현재 원의 *x-coordinate*, *y-coordinate*, 그리고 *radius*에 대한 무작위 값을 생성하기 위해, `random()` 함수가 세 번 호출되었습니다. `random()` 함수는 한 개의 매개변수 — 정수 — 를 취하고 `0`과 그 숫자 사이의 무작위 정수를 반환합니다. 이 함수는 다음과 같습니다:

```js
function random(number) {
  return Math.floor(Math.random() \* number);
}
```

이것은 다음과 같이 쓰여질 수도 있습니다:

```js
function random(number) {
  const result = Math.floor(Math.random() \* number);
  return result;
}
```

하지만 첫번째 코드가 더 작성이 빠르고, 더 콤팩트합니다.

함수가 호출될 때마다 `Math.floor(Math.random() * number)` 계산의 결과가 반환되고 있습니다. 이 반환 값은 함수가 호출된 시점에서 나타나고, 코드는 계속됩니다.

그래서 다음을 실행했을 때:

```js
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 \* Math.PI);
```

만약 세 개의 `random()` 호출이 각각 값 `500`, `200`, 그리고 `35`를 반환했다면, 이 줄은 실제로는 다음처럼 실행될 것입니다:

```js
ctx.arc(500, 200, 35, 0, 2 \* Math.PI);
```

함수 호출들이 먼저 실행되고, 줄 자체가 그리고서 실행되기 전에 함수의 반환 값이 함수 호출을 대신합니다.

직접 해보기: 우리만의 반환 값 함수
--------------------

반환 값을 포함하는 우리만의 함수를 작성해 봅시다.

1. 우선, GitHub에서 function-library.html 파일을 다운받으세요. 이것은 텍스트 `<input>` (en-US) 필드와 단락을 포함하고 있는 단순한 HTML 페이지입니다. 또한 `<script>` 요소가 있는데, 두 HTML 요소에 대한 참조를 두 변수에 저장해 놓았습니다. 이 작은 페이지는 숫자를 텍스트 박스에 입력할 수 있게 하고, 그것에 관련된 다른 숫자들을 아래의 단락에 표시할 것입니다.
2. 몇몇 유용한 함수들을 이 `<script>` 요소에 추가합시다. 두 줄의 JavaScript 아래에, 다음의 함수 정의를 추가하세요.

```js
function squared(num) {
  return num \* num;
}

function cubed(num) {
  return num \* num \* num;
}

function factorial(num) {
  if (num < 0) return undefined;
  if (num == 0) return 1;
  let x = num - 1;
  while (x > 1) {
    num \*= x;
    x--;
  }
  return num;
}
```

`squared()` 와 `cubed()` 함수는 분명합니다 — 이 함수들은 매개변수로 주어진 숫자의 제곱과 세제곱을 반환합니다. `factorial()` 함수는 주어진 숫자의 팩토리얼을 반환합니다.
3. 다음으로, 우리는 텍스트 인풋에 입력된 숫자에 대한 정보를 출력할 방법을 포함할 것입니다. 다음의 이벤트 핸들러를 존재하는 함수들 아래에 입력해 보세요:

```js
input.onchange = function () {
  const num = parseFloat(input.value);
  if (isNaN(num)) {
    para.textContent = "You need to enter a number!";
  } else {
    para.textContent =
      num +
      " squared is " +
      squared(num) +
      ". " +
      num +
      " cubed is " +
      cubed(num) +
      ". " +
      num +
      " factorial is " +
      factorial(num) +
      ".";
  }
};
```

여기서 우리는 `onchange` 이벤트 핸들러를 만들었습니다. 이것은 `change` 이벤트가 언제든지 텍스트 인풋에서 발생(fire)되었을 때 실행됩니다 — 즉, 새로운 값이 텍스트 `input`에 입력되고, 제출되었을 때 (예: 값을 입력하고, `Tab`이나 `Return`을 눌러 그리고서 인풋에서 포커스를 옮겼을 때). 익명 함수가 실행되었을 때, `input` 내의 값은 `num` 상수에 저장됩니다.
 다음으로, 우리는 조건문 테스트를 합니다. 만약 입력된 값이 숫자가 아니라면, 오류 메시지가 단락에 출력됩니다. 이 테스트는 표현식(expression) `isNaN(num)`이 `true`를 반환하는지를 살핍니다. `isNaN()` 함수는 `num` 값이 숫자가 아닌지를 검사합니다 — 만약 그렇다면, 이것은 `true`를 반환하고, 아니라면, `false`를 반환합니다.
 만약 검사가 `false`를 반환했다면, `num` 값은 숫자입니다. 그러므로, 문장이 그 숫자의 제곱, 세제곱, 그리고 팩토리얼을 서술하는 단락 요소 내부에 출력됩니다. 문장은 `squared()`, `cubed()`, 그리고 `factorial()` 함수를 요구된 값을 계산하기 위해 호출합니다.
4. 코드를 저장하고, 브라우저에서 로드한 후, 시도해 보세요.

**참고:** 만약 이 예제를 작업하는 데 어려움이 있다면, 자유롭게 GitHub에 있는 완성된 버전과 비교해 보거나 (실제로 작동하는 모습도 보세요), 우리에게 도움을 요청해 보세요.

이제 여러분의 차례입니다!
--------------

이 시점에서, 우리는 여러분이 두 개의 함수를 작성해 보고 라이브러리에 추가하기를 원합니다. 숫자의 제곱근이나 세제곱근은 어떠세요? 혹은 주어진 반지름의 원의 둘레는 어떠세요?

몇몇 추가적인 함수에 관계된 팁들:

* 함수 내부에 *오류 처리*(error handling)를 작성하는 다른 예제를 보세요. 필수적인 매개변수가 확인되는 것과, 선택적인 매개변수가 몇몇 종류의 주어진 기본 값을 가지고 있는 것을 검사하는 것은 일반적으로 좋은 생각입니다. 이 방법으로, 여러분의 프로그램이 오류를 발생시킬 가능성은 더 적어질 것입니다.
* *함수 라이브러리*(function library)를 만드는 것에 대해 생각해 보세요. 프로그래밍 경력이 더 오래 갈수록, 여러분은 똑같은 종류의 것들을 계속 그리고 계속 하게 될 것입니다. 이런 종류의 것들을 하기 위한 여러분만의 유틸리티 함수 라이브러리를 만드는 것은 좋은 생각입니다. 여러분은 이것들을 새로운 코드에 복사해 넣거나, 심지어는 단순히 필요한 곳 어디든 HTML 페이지에 적용할 수도 있습니다.
실력을 평가해 보세요!
------------

이 문서를 끝까지 읽으셨지만, 중요한 것들을 여전히 기억하고 계신가요? 다음 문서를 읽기 전에 이 문서의 내용을 잘 학습하고 이해하셨는지 확인하실 수 있습니다 — 실력을 평가해 보세요: 함수.

결론
--

이제 끝났습니다 — 함수는 즐겁고, 아주 유용하고, 그리고 비록 함수의 문법과 기능성에 대해 이야기할 것들이 많지만, 그것들은 꽤 이해하기 쉽습니다.

만약 뭐든지 이해하지 못한 게 있다면, 자유롭게 이 문서를 다시 읽거나, 문의하기에서 도움을 요청해 보세요.

같이 보기
-----

* 함수 고급 — 더욱 고급의 함수에 관련된 정보를 다루는 자세한 가이드
* JavaScript에서의 콜백(callback) 함수 — 일반적인 JavaScript 패턴은 함수를 다른 함수 내부에 *인자(argument)로서* 전달하는 것입니다. 이것은 그리고서 첫번째 함수 내부에서 호출됩니다. 이것은 이 코스의 범위를 조금 넘어서지만, 머지않아 공부할 가치는 있습니다.
* 이전
* Overview: Building blocks
* 다음


판단 내리기 — 조건문 - Web 개발 학습하기

판단 내리기 — 조건문
============

* Overview: Building blocks
* 다음

어떤 프로그래밍 언어든 코드는 의사 결정을 내리고 입력 내용에 따라 작업을 수행해야 합니다. 예를 들어 게임에서 플레이어의 생명 수치가 0이면 게임이 종료됩니다. 날씨 앱에서는 아침에 해가 뜬 그림을 보여주고 밤에는 달과 별을 보여줍니다. 이 문서에서는 JavaScript에서 조건문이 작동하는 방법을 살펴 보겠습니다.

|  |  |
| --- | --- |
| 필요한 사전 지식: |
 기본적인 컴퓨터 활용 능력, HTML, CSS,
 Javascript 첫걸음 |
| 목표: | JavaScript에서 조건문의 사용법을 이해합니다. |

여러분은 한 조건보다 우위에 있을 수 있습니다..!
----------------------------

사람(과 동물)은 항상 그들의 삶에 영향을 미치는 결정을, 작은 것(과자를 하나 먹을까? 두개 먹을까?)부터 큰 것(고향에 머물면서 아버지의 농장에서 일해야 할까? 아니면 천체물리학을 공부하러 미국으로 유학을 갈까?)까지 내립니다.

조건문은 우리가, 반드시 내려져야 하는 선택에서부터 (예를 들자면, "쿠키 한 개 또는 두 개"), 그 선택들의 결과까지 (아마도 "쿠키 한 개를 먹는다" 의 결과는 "여전히 배가 고프다" 일지도 모르고, "쿠키 두 개를 먹는다" 의 결과는 "배부르다, 그러나 엄마가 쿠키를 다 먹었다고 나를 야단칠 것이다" 일지도 모릅니다), 그러한 의사 결정을 JavaScript에서 표현할 수 있게 합니다.

![](/ko/docs/Learn/JavaScript/Building_blocks/conditionals/cookie-choice-small.png)

if ... else 문
-------------

여러분이 JavaScript에서 쓸 단연코 가장 일반적인 형태의 조건문을 살펴봅시다 — 변변찮은 `if ... else` 문입니다.

### 기본 if ... else 문법

기본 `if...else` 문법은 의사 코드(pseudocode)로 다음과 같이 보입니다:
```

if (조건) {
  만약 조건(condition)이 참일 경우 실행할 코드
} else {
  대신 실행할 다른 코드
}
```

위를 살펴보면:

1. 키워드 `if` 뒤에 괄호가 옵니다.
2. 시험할 조건은 괄호 안에 위치합니다 (전형적으로 "이 값은 다른 값보다 큰가?", 또는 "이 값은 존재하는가?"). 이 조건은 마지막 모듈에서 논의했던 비교 연산자(comparison operators)를 사용할 것이고 `true`나 `false`를 리턴합니다.
3. 내부의 중괄호 안에 코드가 있습니다. — 이것은 우리가 좋아하는 어떤 코드든 될 수 있고, 오직 조건이 `true`를 반환하는 경우에만 실행됩니다.
4. 키워드 `else`.
5. 또 다른 중괄호 안에 더 많은 코드가 있습니다. — 이것은 우리가 좋아하는 어떤 코드든 될 수 있고, 오직 조건이 `true`가 아닌 경우에만 실행됩니다. — 또는 다른 말로 하자면, 조건이 `false`인 경우에만 실행됩니다.

이 코드는 사람이 읽을 수 있습니다. — 이것은 "**만약** **조건**이 `true`면, 코드 A를 실행하고, **아니면** 코드 B를 실행한다." 라고 말합니다.

반드시 `else`와 두 번째 중괄호를 포함하지 않아도 된다는 것을 주목해야 합니다. — 다음은 또한 완벽한 코드입니다:
```

if (조건) {
  만약 조건(condition)이 참일 경우 실행할 코드
}

실행할 다른 코드
```

하지만, 여기서 조심해야 할 점 — 위의 경우, 코드의 두 번째 블록은 조건문에 의해서 제어되지 않아서, 조건이 `true`나 `false`를 리턴하는 것에 관계없이 **항상** 동작합니다. 이것이 반드시 나쁜 것은 아니지만, 여러분이 원하는 것이 아닐 지도 모릅니다. — 종종 여러분은 둘 다가 아니라, 코드의 한 블럭 또는 다른 블럭을 실행하기를 원합니다.

마지막으로, 여러분은 때때로 다음과 같이 짧은 스타일로 중괄호 없이 쓰여진 `if...else`를 보았을 지도 모릅니다:
```

if (조건) 만약 조건(condition)이 참일 경우 실행할 코드
else 대신 실행할 다른 코드
```

이것은 완벽하게 유효한 코드이지만, 사용하는 것을 추천하지 않습니다 — 만약 코드 블록의 범위를 정하기 위해 중괄호를 사용하고, 다수의 줄과 들여쓰기를 사용한다면 코드를 읽고 무엇이 진행되는지 알아내는 것이 훨씬 쉽습니다.

### 실제 예시

문법을 잘 이해하기 위해서 실제 예시를 알아봅시다. 어머니나 아버지가 아이에게 집안일을 도와달라고 요청한다고 상상해 봅시다. 부모님께서 "우리 애기, 만약에 쇼핑 가는 걸 도와주면, 네가 원하는 장난감을 살 여유가 되도록 용돈을 더 줄게." 라고 말씀하실지도 모릅니다. JavaScript에서, 우리는 이것을 다음과 같이 표현할 수 있습니다:

```js
let shoppingDone = false;
let childsAllowance;

if (shoppingDone === true) {
  childsAllowance = 10;
} else {
  childsAllowance = 5;
}
```

위 코드는 항상 `false`를 리턴하는 `shoppingDone`변수를 결과로 낳는데, 이는 우리의 불쌍한 아이에게 실망을 안겨주겠죠. 아이가 부모님과 함께 쇼핑을 간다면 부모님이 `shoppingDone`변수를 `true`로 설정하는 메커니즘을 제공하는 것은 우리에게 달렸습니다.

**참고:** GitHub에서 예시를 더 볼 수 있습니다. 이 예제의 완성 버전 on GitHub (also see it running live.)

### else if

지난 예시에서는 두 가지 선택, 또는 결과가 있었죠 — 하지만 우리가 두 가지보다 더 많은 것을 원한다면?

추가로 선택/결과를 `if...else`에 연결하는 방법이 있습니다. — `else if`를 사용해서 말입니다. 각 추가 선택은 `if() { ... }`와 `else { ... }`사이에 넣을 추가적인 블록을 필요로 합니다. 간단한 날씨 예보 어플리케이션의 일부가 될 수 있는 다음의 좀 더 관련된 예시를 확인하세요:

```html
<label for="weather">Select the weather type today: </label>
<select id="weather">
  <option value="">--Make a choice--</option>
  <option value="sunny">Sunny</option>
  <option value="rainy">Rainy</option>
  <option value="snowing">Snowing</option>
  <option value="overcast">Overcast</option>
</select>

<p></p>
```

```js
const select = document.querySelector("select");
const para = document.querySelector("p");

select.addEventListener("change", setWeather);

function setWeather() {
  const choice = select.value;

  if (choice === "sunny") {
    para.textContent =
      "It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.";
  } else if (choice === "rainy") {
    para.textContent =
      "Rain is falling outside; take a rain coat and a brolly, and don't stay out for too long.";
  } else if (choice === "snowing") {
    para.textContent =
      "The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.";
  } else if (choice === "overcast") {
    para.textContent =
      "It isn't raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.";
  } else {
    para.textContent = "";
  }
}
```

1. 여기서 우리는 HTML `<select>` (en-US) 엘리먼트를 사용하여 다른 날씨 선택과 간단한 문단을 만들 수 있습니다.
2. JavaScript 코드에서 `<select>` (en-US) 와 `<p>` 요소를 모두 저장하고 있고, 값이 변할 때 `setWeather()`함수가 동작하도록 `<select>` 요소에 이벤트 리스너를 추가했습니다.
3. 함수가 동작했을 때, 현재 `<select>` 요소에서 선택된 현재 값을 `choice`라는 변수에 먼저 설정합니다. 그런 다음 `choice`값에 따라 문단 안에 다른 텍스트를 표시하기 위해 조건문을 사용합니다. `if() {...} block`에서 테스트된 첫 번째를 제외하고, `else if() {...}`에서 모든 조건들이 어떻게 테스트되는지에 유의하세요.
4. `else {...}`안의, 가장 마지막 선택은 기본적으로 "최후의 수단" 옵션입니다 — `true`인 조건이 없으면 그 안의 코드가 실행됩니다. 이 경우 아무것도 선택되지 않으면, 예를 들어, 사용자가 처음에 표시한 "--Make a choice--" 플레이스홀더(placeholder) 옵션을 다시 선택하기로 한다면, 문단의 텍스트를 비우는 역할을 합니다.

**참고:** 또한 이 예제를 GitHub에서 찾을 수 있습니다. (see it running live on there also.)

### 비교 연산자에 대한 메모

비교 연산자는 우리의 조건문 안의 조건을 테스트하는데 사용됩니다. 우리는 먼저 이전의 JavaScript의 기본적인 연산 - 숫자와 연산자 문서에서 비교 연산자를 봤습니다. 우리의 선택들은 다음과 같습니다:

* `===`와 `!==` — 한 값이 다른 값과 같거나 다른지 테스트한다.
* `<` 와 `>` — 한 값이 다른 값보다 작은지 큰지 테스트한다.
* `<=` 와 `>=` — 한 값이 다른 값보다 작거나 같은지, 크거나 같은지 테스트한다

**참고:** 이것들에 대한 기억을 되살리기를 원하신다면 저 링크에 있는 것들을 다시 보세요.

몇 번이고 다시 만날 boolean(`true`/`false`)값을 테스트하는 것과 일반적인 패턴에 대한 특별한 언급을 하고 싶었습니다. 어떠한 값들이든 `false`, `undefined`, `null`, `0`, `NaN`이나 빈 문자열(`''`)이 아닌 값은 조건문으로 테스트되었을 때, 실제로는 `true`를 리턴하므로, 변수가 참인지 혹은 값이 존재하는지를 테스트하기 위해 변수 이름 그 자체를 사용할 수 있습니다. 예를 들어:

```js
let cheese = "Cheddar";

if (cheese) {
  console.log("Yay! Cheese available for making cheese on toast.");
} else {
  console.log("No cheese on toast for you today.");
}
```

그리고, 부모님을 위해 집안일을 하는 아이에 대한 이전 예시로 돌아가자면, 다음과 같이 작성할 수 있습니다.

```js
let shoppingDone = false;
let childsAllowance;

if (shoppingDone) {
  // 명시적으로 '=== true'를 명시할 필요가 없습니다
  childsAllowance = 10;
} else {
  childsAllowance = 5;
}
```

### if ... else 중첩

`if...else`문을 또 다른 문 앞에 (중첩하기 위하여) 넣는 것은 완벽하게 가능합니다. 예를 들어, 온도가 무엇인지에 따라 추가적인 선택의 옵션을 보여주기 위해 우리의 날씨 예보 어플리케이션을 업데이트 할 수 있습니다.

```js
if (choice === "sunny") {
  if (temperature < 86) {
    para.textContent =
      "It is " +
      temperature +
      " degrees outside — nice and sunny. Let's go out to the beach, or the park, and get an ice cream.";
  } else if (temperature >= 86) {
    para.textContent =
      "It is " +
      temperature +
      " degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.";
  }
}
```

비록 코드가 모두 동작하더라도, 각 `if...else`문은 다른 문과 완전히 독립적으로 동작합니다.

### 논리 연산자: AND, OR 그리고 NOT

만약 중첩된 `if...else`문을 작성 없이 다양한 조건을 테스트하길 원한다면 논리 연산자가 여러분을 도와줄 수 있습니다. 조건 내에서 사용될 때, 처음의 두 가지는 다음을 합니다:

* `&&` — AND; 전체 표현식(expression)이 `true`를 리턴하기 위해 두 개 혹은 그 이상의 표현식이 개별적으로 `true`로 평가되도록 그 식들을 같이 연결할 수 있게 합니다.
* `||` — OR; 전체 표현식이 `true`를 리턴하기 위해 하나 혹은 그 이상의 표현식이 개별적으로 `true`로 평가되도록 두 개 혹은 그 이상의 식들을 같이 연결할 수 있게 합니다.

AND 예시를 위해서 앞의 예제 코드를 다음과 같이 재작성할 수 있습니다.

```js
if (choice === "sunny" && temperature < 86) {
  para.textContent =
    "It is " +
    temperature +
    " degrees outside — nice and sunny. Let's go out to the beach, or the park, and get an ice cream.";
} else if (choice === "sunny" && temperature >= 86) {
  para.textContent =
    "It is " +
    temperature +
    " degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.";
}
```

위 예시에서, 첫 번째 코드 블록은 `choice === 'sunny'`*와* `temperature < 86`가 오직 `true`를 리턴해야만 실행될 것입니다.

빠르게 OR 예시를 봅시다.

```js
if (iceCreamVanOutside || houseStatus === "on fire") {
  console.log("You should leave the house quickly.");
} else {
  console.log("Probably should just stay in then.");
}
```

논리 연산자의 마지막 유형인 `!` 연산자로 표현되는 NOT은 표현식을 부정(negate)하기 위해 사용될 수 있습니다. 위 OR 예시와 함께 봅시다.

```js
if (!(iceCreamVanOutside || houseStatus === "on fire")) {
  console.log("Probably should just stay in then.");
} else {
  console.log("You should leave the house quickly.");
}
```

위 예시에서, OR 문이 `true`를 리턴한다면, NOT 연산자는 전체 표현식이 `false`를 리턴하도록 부정할 것입니다.

어떤 구조든지, 여러분이 원하는 만큼 많은 논리 문(statement)을 결합할 수 있습니다. 다음 예시는 오직 두 OR 문 모두가 true를 리턴하면 내부의 코드를 실행하는데, 이는 전체의 AND 문이 true를 리턴할 것임을 의미합니다.

```js
if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === "Steve")) {
  // run the code
}
```

조건문에서 논리적 OR 연산자를 사용할 때의 일반적인 실수는 여러분이 검사하는 값의 변수를 한 번 명시하기(state)를 시도하고, 그리고 true를 리턴할 수 있는 값들의 목록을, `||` (OR) 연산자에 의해 분리하며 제공하는 것입니다. 예를 들자면:

```js
if (x === 5 || 7 || 10 || 20) {
  // run my code
}
```

이 경우에 `if(...)` 내부 조건은 7(또는 다른 0이 아닌 값)이 항상 true로 평가되므로, 항상 true로 평가될 것입니다. 이 조건은 실제로는 "만약 x가 5와 같거나, 7이 true면 — 이것은 항상 true다"라고 분명하게 말하고 있습니다. 이것은 논리적으로 우리가 원하는 것이 아닙니다! 이를 동작하게 하기 위해 우리는 각 OR 연산자의 양 측에서 완전한 테스트를 명시해야 합니다.

```js
if (x === 5 || x === 7 || x === 10 || x === 20) {
  // run my code
}
```

switch 문
--------

`if...else` 문은 조건문 코드가 잘 가능하게 하는 일을 하지만, 단점이 없지는 않습니다. 그 문은 두 가지 선택을 가지고 있고, 각각은 실행될 합리적인 양의 코드가 필요하고, 및/또는 그 조건이 복잡한 (예를 들자면, 다수의 논리 연산자) 경우에 주로 유용합니다. 여러분이 단지 어떤 값의 선택에 변수를 설정하거나 조건에 달린 특정한 문(statement)을 출력하기를 원하는 경우에, 그 구문(syntax)은 다소 번거로울 수 있는데, 특히 여러분이 다수의 선택을 가지고 있는 경우에 그렇습니다.

그러한 경우에 `switch`문 (en-US)은 여러분의 친구입니다. 이는 입력으로 하나의 표현식/값을 받고, 값과 일치하는 하나를 찾을 때까지 여러 항목을 살펴보고 그에 맞는 코드를 실행합니다. 여러분에게 아이디어를 주기 위해, 여기 몇몇 많은 의사 코드가 있습니다:
```

switch (expression) {
  case choice1:
    run this code
    break;

  case choice2:
    run this code instead
    break;

  // 원하는 만큼 많은 case를 포함하십시오

  default:
    actually, just run this code
}
```

여기에서:

1. 뒤에 괄호가 오는 키워드 `switch`.
2. 괄호 내부에는 표현식이나 값을 입력합니다.
3. 표현식이나 값이 될 수 있는 선택이 따라오는, 키워드 `case`는 콜론이 뒤에 옵니다.
4. 만약 선택이 표현식과 일치하면 실행할 코드.
5. `break`문은 뒤에 세미콜론이 옵니다. 이전의 선택이 표현식이나 값과 일치한다면 브라우저는 해당 코드 블록에서 실행을 멉추고, switch 문 아래에 있는 코드로 이동합니다.
6. 원하는 만큼 다른 케이스를 (3번–5번) 입력할 수 있습니다.
7. 키워드 `default`는 그 뒤에 선택이 없다는 것을 제외하고 케이스들 중 하나와 완전히 같은 코드 패턴인데 (3번–5번), 이 블록 이후에는 실행할 어떤 코드도 없으므로 `break` 문이 필요하지 않습니다. 일치하는 항목이 없으면 실행되는 기본 옵션입니다.

**참고:** `default`를 반드시 포함하지 않아도 됩니다 — 만약 표현식이 미지의 값과 같게 되어버릴 수 있는 경우가 없다면 여러분은 안전하게 이것을 생략할 수 있습니다. 그러나, 그 경우가 있다면, 여러분은 미지의 경우를 다루기 위해 이것을 포함할 필요가 있습니다.

### A switch example

실전 예제를 해 봅시다. switch문을 대신 사용해 일기예보 애플리케이션을 재작성할 것입니다.

```html
<label for="weather">Select the weather type today: </label>
<select id="weather">
  <option value="">--Make a choice--</option>
  <option value="sunny">Sunny</option>
  <option value="rainy">Rainy</option>
  <option value="snowing">Snowing</option>
  <option value="overcast">Overcast</option>
</select>

<p></p>
```

```js
const select = document.querySelector("select");
const para = document.querySelector("p");

select.addEventListener("change", setWeather);

function setWeather() {
  const choice = select.value;

  switch (choice) {
    case "sunny":
      para.textContent =
        "It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.";
      break;
    case "rainy":
      para.textContent =
        "Rain is falling outside; take a rain coat and a brolly, and don't stay out for too long.";
      break;
    case "snowing":
      para.textContent =
        "The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.";
      break;
    case "overcast":
      para.textContent =
        "It isn't raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.";
      break;
    default:
      para.textContent = "";
  }
}
```

**참고:** 또한 이 예제를 GitHub에서 찾을 수 있습니다. (see it running live on there also.)

삼항연산자
-----

다른 예제로 들어가기 전에 소개하고 싶은 마지막 구문이 있습니다. 삼항(조건)연산자(ternary or conditional operator)는 조건을 테스트하고 만약 조건이 `true`라면 하나의 값/표현식을 리턴하고, 만약 `false`라면 다른 값/표현식을 리턴하는 구문입니다 — 이것은 어떤 상황에 유용할 수 있으며, 만약 `true`/`false`조건 사이를 통해 선택되는 두 선택을 가지고 있다면 `if...else` 블록보다 코드를 훨씬 적게 사용할 수 있습니다. 이 의사 코드는 아래와 같습니다:
```

( condition ) ? run this code : run this code instead
```

그러면 간단한 예를 봅시다:

```js
let greeting = isBirthday
  ? "Happy birthday Mrs. Smith — we hope you have a great day!"
  : "Good morning Mrs. Smith.";
```

`isBirthday` 라는 변수명이 여기 있습니다 — 만약 이것이 `true`라면, 우리는 게스트에게 생일 축하 메시지를 보냅니다; 만약 아니라면, 우리는 그녀에게 일반적인 인사를 보냅니다.

### 삼항 연산자 예제

삼항연산자로 단지 변수 값만을 정할 필요가 없습니다; 무엇이든지 좋아하는 함수나 코드를 실행할 수 있습니다. 이 예제는 삼항연산자를 사용하여 사이트의 스타일링이 적용되는 간단한 테마 선택기를 보여줍니다.

```html
<label for="theme">Select theme: </label>
<select id="theme">
  <option value="white">White</option>
  <option value="black">Black</option>
</select>

<h1>This is my website</h1>
```

```js
const select = document.querySelector("select");
const html = document.querySelector("html");
document.body.style.padding = "10px";

function update(bgColor, textColor) {
  html.style.backgroundColor = bgColor;
  html.style.color = textColor;
}

select.onchange = function () {
  select.value === "black"
    ? update("black", "white")
    : update("white", "black");
};
```

여기에는 테마(검정 또는 하양)를 고르기 위한 '`<select>` (en-US)' 요소가 있고, 여기에 더하여 웹사이트 제목을 보여주는 간단한 '`<h1>`" 요소가 있습니다. 우리는 또한 `update()`라는 함수를 가지고 있는데, 이 함수는 두 색상을 매개변수(parameter)(입력)로 취합니다. 웹사이트의 배경색이 첫 번째 제공된 색상으로 지정되고, 텍스트 색상이 두 번째 제공된 색상으로 정해집니다.

끝으로, 우리는 또한 삼항연산자를 포함하고 있는 함수의 실행을 제공하는 'onchange' 이벤트 리스너를 가지고 있습니다. 이것은 테스트 조건으로 시작합니다 — `select.value === 'black'`. 만약 이것이 `true`를 리턴하면, 우리는 검정과 하양의 매개변수를 지니고 있는 `update()`함수를 실행하는데, 이는 배경색은 검정으로 텍스트 색은 하양으로 되는 결과를 의미합니다. 만약 이것이 `false`를 리턴하면, 우리는 하양과 검정의 매개변수를 지니고 있는 `update()`함수를 실행하는데, 이는 사이트의 색상이 반전됐다는 것을 의미합니다.

**참고:** 또한 이 예제를 GitHub에서 찾을 수 있습니다. (see it running live on there also.)

직접 해보기: 간단한 달력 만들기
------------------

이 예제에서는 간단한 달력 어플리케이션을 만들어 볼 것입니다. 코드에는 다음과 같은 것들이 들어 있습니다.

* 유저가 여러 달을 고를 수 있게 하는 `<select>` (en-US) 요소.
* `<select>` 메뉴에서 선택된 값이 변경되었을 때를 탐지하는 `onchange` 이벤트 핸들러.
* `<h1>` 요소에 올바른 달을 표시하고 달력을 생성하는 `createCalendar()` 함수.

`onchange` 핸들러 함수내에 조건문을 작성해야 합니다. 위치는 `// ADD CONDITIONAL HERE` 주석 바로 아래입니다. 조건문은 다음을 만족해야 합니다:

1. 선택된 달 보기 (`choice`변수 안에 저장되어 있습니다. 이것은 값이 변경된 이후에 `<select>` 요소 값일 것입니다. 예를 들자면 "January")
2. `days` 변수를 선택된 달의 일수와 동일하게 설정하기. 이것을 하기 위해서는 1년의 각 달의 일수를 찾아봐야만 할 것입니다. 이 예제의 목적을 위해 윤년은 무시할 수 있습니다.

힌트:

* 논리연산자 OR을 사용해 동일한 일 수인 여러 달을 하나의 조건으로 그룹화하기. 많은 달들이 동일한 일수를 공유합니다.
* 가장 흔한 일 수를 생각해보고, 그것을 기본값으로 사용하기.

만약 실수를 하더라도 'Reset' 버튼으로 초기화 할 수 있습니다. 정말로 해답을 모르겠다면, "Show solution" 으로 해결 방법을 확인하세요.
```

<h2>Live output</h2>
<div class="output" style="height: 500px;overflow: auto;">
  <label for="month">Select month: </label>
  <select id="month">
    <option value="January">January</option>
    <option value="February">February</option>
    <option value="March">March</option>
    <option value="April">April</option>
    <option value="May">May</option>
    <option value="June">June</option>
    <option value="July">July</option>
    <option value="August">August</option>
    <option value="September">September</option>
    <option value="October">October</option>
    <option value="November">November</option>
    <option value="December">December</option>
  </select>

  <h1></h1>

  <ul></ul>
</div>

<h2>Editable code</h2>
<p class="a11y-label">
  Press Esc to move focus away from the code area (Tab inserts a tab character).
</p>

<textarea id="code" class="playable-code" style="height: 400px;width: 95%">
const select = document.querySelector('select');
const list = document.querySelector('ul');
const h1 = document.querySelector('h1');

select.onchange = function() {
  const choice = select.value;

  // ADD CONDITIONAL HERE

  createCalendar(days, choice);
}

function createCalendar(days, choice) {
  list.innerHTML = '';
  h1.textContent = choice;
  for (let i = 1; i <= days; i++) {
    const listItem = document.createElement('li');
    listItem.textContent = i;
    list.appendChild(listItem);
  }
}

createCalendar(31,'January');
</textarea>

<div class="playable-buttons">
  <input id="reset" type="button" value="Reset" />
  <input id="solution" type="button" value="Show solution" />
</div>
```

```
.output \* {
  box-sizing: border-box;
}

.output ul {
  padding-left: 0;
}

.output li {
  display: block;
  float: left;
  width: 25%;
  border: 2px solid white;
  padding: 5px;
  height: 40px;
  background-color: #4a2db6;
  color: white;
}

html {
  font-family: sans-serif;
}

h2 {
  font-size: 16px;
}

.a11y-label {
  margin: 0;
  text-align: right;
  font-size: 0.7rem;
  width: 98%;
}

body {
  margin: 10px;
  background: #f5f9fa;
}
```

```
const textarea = document.getElementById("code");
const reset = document.getElementById("reset");
const solution = document.getElementById("solution");
let code = textarea.value;
let userEntry = textarea.value;

function updateCode() {
  eval(textarea.value);
}

reset.addEventListener("click", function () {
  textarea.value = code;
  userEntry = textarea.value;
  solutionEntry = jsSolution;
  solution.value = "Show solution";
  updateCode();
});

solution.addEventListener("click", function () {
  if (solution.value === "Show solution") {
    textarea.value = solutionEntry;
    solution.value = "Hide solution";
  } else {
    textarea.value = userEntry;
    solution.value = "Show solution";
  }
  updateCode();
});

const jsSolution =
  "const select = document.querySelector('select');\nconst list = document.querySelector('ul');\nconst h1 = document.querySelector('h1');\n\nselect.onchange = function() {\n const choice = select.value;\n let days = 31;\n if(choice === 'February') {\n days = 28;\n } else if(choice === 'April' || choice === 'June' || choice === 'September'|| choice === 'November') {\n days = 30;\n }\n\n createCalendar(days, choice);\n}\n\nfunction createCalendar(days, choice) {\n list.innerHTML = '';\n h1.textContent = choice;\n for(let i = 1; i <= days; i++) {\n const listItem = document.createElement('li');\n listItem.textContent = i;\n list.appendChild(listItem);\n }\n }\n\ncreateCalendar(31,'January');";
let solutionEntry = jsSolution;

textarea.addEventListener("input", updateCode);
window.addEventListener("load", updateCode);

// stop tab key tabbing out of textarea and
// make it write a tab at the caret position instead

textarea.onkeydown = function (e) {
  if (e.keyCode === 9) {
    e.preventDefault();
    insertAtCaret("\t");
  }

  if (e.keyCode === 27) {
    textarea.blur();
  }
};

function insertAtCaret(text) {
  const scrollPos = textarea.scrollTop;
  let caretPos = textarea.selectionStart;
  const front = textarea.value.substring(0, caretPos);
  const back = textarea.value.substring(
    textarea.selectionEnd,
    textarea.value.length,
  );

  textarea.value = front + text + back;
  caretPos = caretPos + text.length;
  textarea.selectionStart = caretPos;
  textarea.selectionEnd = caretPos;
  textarea.focus();
  textarea.scrollTop = scrollPos;
}

// Update the saved userCode every time the user updates the text area code

textarea.onkeyup = function () {
  // We only want to save the state when the user code is being shown,
  // not the solution, so that solution is not saved over the user code
  if (solution.value === "Show solution") {
    userEntry = textarea.value;
  } else {
    solutionEntry = textarea.value;
  }

  updateCode();
};
```

직접 해보기: 색깔 고르기
--------------

이 예제에서는 위에서 봤던 삼항연산자 예제의 삼항연산자를 간단한 웹사이트에 더 많은 선택을 적용할 수 있게 하는 switch문으로 전환할 것입니다. `<select>` (en-US)을 보세요 — 이번에는 이것이 두 개의 테마 옵션을 가지고 있지 않고, 다섯 개를 가지고 있는 것을 보실 수 있을 것입니다. 여러분은 `// ADD SWITCH STATEMENT` 주석 바로 밑에 추가할 필요가 있습니다:

* 이것은 `choice` 변수를 이것의 입력 표현식으로 받아야 합니다.
* 각각의 경우에 대해, 선택은 선택될 수 있는 가능한 값들 중 하나와 동일해야만 합니다. 예: 하양, 검정, 보라, 노랑, 또는 사이키델릭.
* 각각의 경우에 대해, `update()` 함수는 실행되어야만 하고, 두 개의 색상을, 첫번째는 배경색으로, 두번째는 텍스트 색상으로 전달해야만 합니다. 색상값은 문자열이므로, 따옴표로 감싸져야 할 필요가 있다는 것을 기억하세요.

만약 실수를 하더라도 'Reset' 버튼으로 초기화 할 수 있습니다. 정말로 해답을 모르겠다면, "Show solution" 으로 해결 방법을 확인하세요.
```

<h2>Live output</h2>
<div class="output" style="height: 300px;">
  <label for="theme">Select theme: </label>
  <select id="theme">
    <option value="white">White</option>
    <option value="black">Black</option>
    <option value="purple">Purple</option>
    <option value="yellow">Yellow</option>
    <option value="psychedelic">Psychedelic</option>
  </select>

  <h1>This is my website</h1>
</div>

<h2>Editable code</h2>
<p class="a11y-label">
  Press Esc to move focus away from the code area (Tab inserts a tab character).
</p>

<textarea id="code" class="playable-code" style="height: 450px;width: 95%">
const select = document.querySelector('select');
const html = document.querySelector('.output');

select.onchange = function() {
  const choice = select.value;

  // ADD SWITCH STATEMENT
}

function update(bgColor, textColor) {
  html.style.backgroundColor = bgColor;
  html.style.color = textColor;
}</textarea
>

<div class="playable-buttons">
  <input id="reset" type="button" value="Reset" />
  <input id="solution" type="button" value="Show solution" />
</div>
```

```
html {
  font-family: sans-serif;
}

h2 {
  font-size: 16px;
}

.a11y-label {
  margin: 0;
  text-align: right;
  font-size: 0.7rem;
  width: 98%;
}

body {
  margin: 10px;
  background: #f5f9fa;
}
```

```
const textarea = document.getElementById("code");
const reset = document.getElementById("reset");
const solution = document.getElementById("solution");
let code = textarea.value;
let userEntry = textarea.value;

function updateCode() {
  eval(textarea.value);
}

reset.addEventListener("click", function () {
  textarea.value = code;
  userEntry = textarea.value;
  solutionEntry = jsSolution;
  solution.value = "Show solution";
  updateCode();
});

solution.addEventListener("click", function () {
  if (solution.value === "Show solution") {
    textarea.value = solutionEntry;
    solution.value = "Hide solution";
  } else {
    textarea.value = userEntry;
    solution.value = "Show solution";
  }
  updateCode();
});

const jsSolution =
  "const select = document.querySelector('select');\nconst html = document.querySelector('.output');\n\nselect.onchange = function() {\n const choice = select.value;\n\n switch(choice) {\n case 'black':\n update('black','white');\n break;\n case 'white':\n update('white','black');\n break;\n case 'purple':\n update('purple','white');\n break;\n case 'yellow':\n update('yellow','darkgray');\n break;\n case 'psychedelic':\n update('lime','purple');\n break;\n }\n}\n\nfunction update(bgColor, textColor) {\n html.style.backgroundColor = bgColor;\n html.style.color = textColor;\n}";
let solutionEntry = jsSolution;

textarea.addEventListener("input", updateCode);
window.addEventListener("load", updateCode);

// stop tab key tabbing out of textarea and
// make it write a tab at the caret position instead

textarea.onkeydown = function (e) {
  if (e.keyCode === 9) {
    e.preventDefault();
    insertAtCaret("\t");
  }

  if (e.keyCode === 27) {
    textarea.blur();
  }
};

function insertAtCaret(text) {
  const scrollPos = textarea.scrollTop;
  let caretPos = textarea.selectionStart;
  const front = textarea.value.substring(0, caretPos);
  const back = textarea.value.substring(
    textarea.selectionEnd,
    textarea.value.length,
  );

  textarea.value = front + text + back;
  caretPos = caretPos + text.length;
  textarea.selectionStart = caretPos;
  textarea.selectionEnd = caretPos;
  textarea.focus();
  textarea.scrollTop = scrollPos;
}

// Update the saved userCode every time the user updates the text area code

textarea.onkeyup = function () {
  // We only want to save the state when the user code is being shown,
  // not the solution, so that solution is not saved over the user code
  if (solution.value === "Show solution") {
    userEntry = textarea.value;
  } else {
    solutionEntry = textarea.value;
  }

  updateCode();
};
```

실력을 평가해 보세요!
------------

이 문서를 끝까지 읽으셨지만, 중요한 것들을 여전히 기억하고 계신가요? 다음 문서를 읽기 전에 이 문서의 내용을 잘 학습하고 이해하셨는지 확인하실 수 있습니다 — 실력을 평가해 보세요: 조건문.

결론
--

그리고 이것이 여러분이 지금 JavaScript에서 알아야 할 조건문 구조에 대한 모든 것입니다! 저는 여러분이 이 개념들을 이해했고 이 예제들을 쉽게 통과했을 것이라고 확신합니다; 만약 뭐든지 이해하지 못한 게 있다면, 자유롭게 이 문서를 다시 읽거나, 문의하기에서 도움을 요청해 보세요.

같이 보기
-----

* 비교 연산자(Comparison operators)
* 조건문 자세하게 살펴보기
* if...else 참고서
* 삼항연산자 참고서
* Overview: Building blocks
* 다음


함수 — 코드 재사용 - Web 개발 학습하기

함수 — 코드 재사용
===========

* 이전
* Overview: Building blocks
* 다음

코딩에 있어서 또 하나의 필수적인 개념은 **함수**인데, 이는 하나의 일을 하는 코드 조각을 정의된 블록 안에 저장하고, 같은 코드를 여러 번 타이핑하기보다는, 하나의 짧은 명령을 사용하여 여러분이 그 함수가 필요할 때 언제든지 그 코드를 호출할 수 있게 합니다. 이 문서에서 우리는 기본 문법(syntax), 어떻게 함수를 호출하고(invoke) 정의하는지, 스코프(scope), 그리고 매개변수(parameter)와 같은 함수 뒤에 있는 핵심적인 개념들을 탐구할 것입니다.

|  |  |
| --- | --- |
| 필요한 사전 지식: |
 기본적인 컴퓨터 활용 능력, HTML과 CSS의 기본적인 이해,
 JavaScript 첫 단계.
  |
| 목표: | JavaScript 함수의 기본 개념을 이해합니다. |

함수는 어디에서 찾을 수 있나요?
------------------

JavaScript 어디서든 함수를 찾을 수 있습니다. 사실, 우리는 지금까지 수업에서 함수를 계속 사용해왔습니다. 함수에 대해서 아주 많이 말해오지 않았을 뿐이죠. 그러나 이제 함수에 대해서 분명하게 말하고, 실제로 문법을 탐험할 때가 되었습니다.

for loop, while 과 do...while loop, 또는 if...else문과 같은 일반적인 내장 언어 구조를 사용하지 **않고** — `()` —같은 괄호 쌍을 사용했다면 여러분은 함수를 사용하고 있던 겁니다.

브라우저 내장 함수
----------

우리는 이 코스에서 많은 브라우저 내장(built-in) 함수를 사용해왔습니다. 예를 들어, 우리가 매번 텍스트 문자열을 조작할 때마다:

```js
var myText = "I am a string";
var newString = myText.replace("string", "sausage");
console.log(newString);
// the replace() string function takes a string,
// replaces one substring with another, and returns
// a new string with the replacement made
```

또는 우리가 배열을 조작할 때마다:

```js
var myArray = ["I", "love", "chocolate", "frogs"];
var madeAString = myArray.join(" ");
console.log(madeAString);
// the join() function takes an array, joins
// all the array items together into a single
// string, and returns this new string
```

또는 우리가 무작위의 숫자를 생성할 때마다:

```js
var myNumber = Math.random();
// the random() function generates a random
// number between 0 and 1, and returns that
// number
```

...우리는 함수를 사용하고 있었어요!

**참고:** 만약 필요하다면, 이 기능들에 다시 익숙해지기 위해 여러분의 브라우저 JavaScript 콘솔에 자유롭게 이 코드들을 입력해 보세요.

JavaScript 언어는 여러분 스스로 코드 전체를 적을 필요 없이, 유용한 것들을 할 수 있게 해주는 많은 내장 함수를 가지고 있습니다. 사실, 브라우저 내장 함수를 **호출**("함수를 실행하다(run 또는 execute)"는 말을 멋있게 "호출하다(invoke)"라고 하기도 합니다)할 때 호출하는 일부 코드는 JavaScript로 작성될 수 없었습니다 — 이러한 함수 중 상당수는 백그라운드 브라우저 코드의 일부를 호출하고 있으며, 이는 JavaScript와 같은 웹 언어가 아니라 대체로 C++와 같은 저수준 시스템 언어로 작성됩니다.

몇몇 브라우저 내장함수는 핵심(core) JavaScript 언어의 일부가 아니라는 것을 유념하세요. 몇몇은 브라우저 API의 일부로써 정의되어 있는데, 더욱 많은 기능성을 제공하기 위해 기본(default) 언어의 위에 개발되었습니다 (앞선 코스에서 더 자세한 설명을 볼 수 있습니다). 브라우저 API를 다루는 법은 나중에 더 살펴보도록 하겠습니다.

함수 대 메소드
--------

프로그래머들은 객체(object)의 부분인 **함수**를 **메서드**(method)라고 부릅니다. 여러분은 아직 구성된(structured) JavaScript 객체의 내부 작동에 대해서 배울 필요는 없습니다. 차후의 모듈에서 객체의 내부 작동과, 어떻게 객체를 생성하는지에 대한 모든 것을 배울 수 있습니다. 우선은, 우리는 메서드 대 함수에 대해 있을 수 있는 혼란을 단지 정리하기를 원합니다. — 웹 상에서 이용 가능한 관련된 리소스들을 살펴보면서 여러분은 두 용어를 만날 가능성이 있습니다.

우리가 지금까지 사용해 왔던 내장된(built-in) 코드는 두 형태로 나타납니다. 바로 **함수**와 **메서드**입니다. 여러분은 내장 함수의 전체 목록과, 내장 객체와 그들의 해당하는 메서드들 또한 여기서 확인할 수 있습니다.

여러분은 또한 많은 **사용자 정의 함수**(custom functions)들을 이 코스에서 지금까지 봐 왔습니다. — 브라우저 내부에서 정의된 게 아니라, 여러분의 코드에서 정의된 함수 말입니다. 괄호 바로 앞에 있는 사용자 정의 이름을 봤을 때마다, 여러분은 사용자 정의 함수를 사용하고 있었던 것입니다. 반복문(loops) 문서의 random-canvas-circles.html 예제 (전체 소스 코드 또한 보세요)에서, 우리는 다음과 같은 사용자 정의 `draw()` 함수를 포함했었습니다.

```js
function draw() {
  ctx.clearRect(0, 0, WIDTH, HEIGHT);
  for (var i = 0; i < 100; i++) {
    ctx.beginPath();
    ctx.fillStyle = "rgba(255,0,0,0.5)";
    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 \* Math.PI);
    ctx.fill();
  }
}
```

이 함수는 `<canvas>` 요소 안에 100개의 임의의 원을 그립니다. 원할 때마다 아래 코드로 함수를 호출할 수 있습니다.

```js
draw();
```

우리가 이것을 반복하기를 원할 때마다 모든 코드를 또 작성하지 않고 말이죠. 그리고 함수는 여러분이 원하는 코드를 무엇이든지간에 포함할 수 있습니다. 여러분은 심지어 다른 함수들을 함수 내부에서부터 호출할 수 있습니다. 위의 예시는 아래와 같이 정의된 `random()` 함수를 세 번이나 호출하고 있죠.

```js
function random(number) {
  return Math.floor(Math.random() \* number);
}
```

브라우저의 내장 Math.random() 함수는 오직 0과 1사이의 무작위 소수를 생성하기 때문에 우리는 이 함수가 필요했습니다. 우리는 0과 명시된 숫자 사이의 무작위 정수를 원했습니다.

함수 호출
-----

지금까지 꽤 잘 따라온 거 같은데 혹시 모르니깐 말해 주자면... 정의된 함수를 작동시키기 위해선 함수를 '호출' 해야 돼요. 함수 호출은 함수의 이름을 괄호와 함께 코드 내에 적어 주면 됩니다.

```js
function myFunction() {
  alert("hello");
}

myFunction();
// calls the function once
```

**참고:** 이 형태의 함수 생성은 또한 *함수 선언*(function declaration)으로도 알려져 있습니다. 이것은 언제나 호이스팅(hoisting)되어서, 여러분은 함수를 함수 정의 위에서 호출할 수 있고 이것은 잘 작동할 것입니다.

익명 함수
-----

여러분은 조금 다른 방식으로 정의되거나 호출되는 함수를 본 적 있을 거예요. 이제까지 우리는 이런 식으로 함수를 생성했죠:

```js
function myFunction() {
  alert("hello");
}
```

하지만 이름 없는 함수 또한 만들 수 있답니다.

```js
function() {
  alert('hello');
}
```

이건 **익명 함수**라고 불려요. 이름이 없다는 뜻이죠! 익명함수는 스스로 뭘 어쩌지 못 해요. 익명함수는 주로 이벤트 핸들러와 사용됩니다. 아래의 예시는 함수 내의 코드가 관련된 버튼을 클릭함에 따라 작동한다는 걸 보여주죠.

```js
var myButton = document.querySelector("button");

myButton.onclick = function () {
  alert("hello");
};
```

위의 예시는 페이지 상의 클릭을 위해 `<button>` 요소를 필요로 합니다. 여러분은 코스를 거치며 이런 구조의 코드를 꽤 봐왔을 거예요. 다음 문서에서 더 많은 걸 배워 보자구요.

여러분은 변수 속에 익명함수를 넣을 수 있어요. 예시입니다.

```js
var myGreeting = function () {
  alert("hello");
};
```

**참고:** 이 형태의 함수 생성은 또한 *함수 표현식*(function expression)으로도 알려져 있습니다. 함수 선언과는 다르게, 함수 표현식은 호이스팅되지 않습니다.

이 함수는 이런 식으로 호출되죠:

```js
myGreeting();
```

이 방법은 효과적으로 함수에 이름을 부여하고 있어요. 여러분은 다중 변수들에 함수를 할당할 수도 있죠. 예를 들면,

```js
var anotherGreeting = function () {
  alert("hello");
};
```

이제 함수는 이런 식으로도 호출이 가능해졌구요.

```js
myGreeting();
anotherGreeting();
```

하지만 위의 방식은 사람 헷갈리게 만들어요. 그니깐 쓰진 맙시다! 함수를 만들 땐 아래의 형태를 고수하는 게 나아요.

```js
function myGreeting() {
  alert("hello");
}
```

익명함수는 이벤트 발생에 따른 수많은 코드를 작동시키기 위해 주로 쓰이게 돼요. 이벤트 핸들러를 사용한 버튼의 클릭과 같은 상황에 말이죠. 자, 그 코드는 아래와 같이 생겼어요.

```js
myButton.onclick = function () {
  alert("hello");
  // 내가 원하는 만큼 얼마든지
  // 여기에 코드를 작성하면 됩니다!
};
```

함수 매개변수
-------

몇몇 함수는 호출을 위해 매개변수를 필요로 하는 경우가 있습니다. 이것들은 함수 괄호 안에 포함될 필요가 있는 값들인데, 올바르게 동작하기 위해 필요합니다.

**참고:** 매개변수는 종종 arguments, properties, 심지어 attributes 라고도 불려요.

예를 들어, 브라우저의 내장 함수인 Math.random()은 어떤 매개변수도 필요로 하지 않습니다. 이 함수는 호출되면 늘 0과 1사이의 무작위 수를 반환해 주죠.

```js
var myNumber = Math.random();
```

하지만 브라우저의 내장 문자열 replace() (en-US) 함수는 두 개의 매개변수를 필요로 합니다. 대체될 문자와 대체할 문자죠.

```js
var myText = "I am a string";
var newString = myText.replace("string", "sausage");
```

**참고:** 여러 개의 매개변수는 콤마에 의해 구분되어집니다.

매개변수는 이따금 선택 사항이기도 합니다. 여러분이 명시해 줄 필요가 없다는 뜻이죠. 그런 경우, 일반적으로 함수는 기본 기능을 수행합니다. 예를 들어, 배열과 관련된 join() 함수의 매개변수가 그렇죠.

```js
var myArray = ["I", "love", "chocolate", "frogs"];
var madeAString = myArray.join(" ");
// returns 'I love chocolate frogs'
var madeAString = myArray.join();
// returns 'I,love,chocolate,frogs'
```

결합(joining)/한정(delimiting)하는 문자를 명시할 어떠한 매개변수도 포함되지 않는다면, 콤마가 기본으로 사용될 것입니다.

함수 스코프와 충돌(conflicts)
---------------------

우리 '스코프(scope)'에 대해 얘기해 볼까요? '스코프'는 함수와 관련된 매우 중요한 개념입니다. 함수를 생성할 때, 변수 및 함수 내 정의된 코드들은 그들만의 분리된 '스코프' 안에 자리하게 됩니다. 그 말인 즉슨, 다른 함수의 내부나 외부 함수의 코드가 접근할 수 없는 그들만의 구획에 갇혀 있다는 뜻입니다.

함수 바깥에 선언된 가장 상위 레벨의 스코프를 '**전역 스코프**(global scope)' 라고 부릅니다.전역 스코프 내에 정의된 값들은 어느 코드든 접근이 가능합니다.

JavaScript는 다양한 이유로 인해 이와 같이 설정되어 있지만, 주로는 안전성과 구조 때문입니다. 어떤 때에는 여러분의 변수가 어느 코드나 접근 가능한 변수가 되는 걸 원치 않을 겁니다. 여러분이 어딘가에서 불러온 외부 스크립트가 문제를 일으킬 수도 있으니깐요. 외부 스크립트의 코드와 같은 변수 이름을 사용하면 충돌이 일어나게 돼요. 이건 악의적일 수도 있고, 아님 뭐 단순한 우연이겠죠.

예를 들어 , 여러분에게 두 개의 외부 JavaScript 파일을 호출하는 HTML이 있다고 쳐요. 그 둘은 같은 이름으로 정의된 변수와 함수를 사용하고 있습니다.

```html
<!-- Excerpt from my HTML -->
<script src="first.js"></script>
<script src="second.js"></script>
<script>
 greeting();
</script>
```

```js
// first.js
var name = "Chris";
function greeting() {
  alert("Hello " + name + ": welcome to our company.");
}
```

```js
// second.js
var name = "Zaptec";
function greeting() {
  alert("Our company is called " + name + ".");
}
```

여러분이 호출하고 싶은 두 함수 모두 `greeting()` 이지만, 여러분은 오직 `first.js` 파일의 `greeting()` 함수에만 접근할 수 있을 뿐입니다 (두번째 것은 무시됩니다). 추가적으로, `second.js` 파일에서 `let` 키워드로 `name` 변수를 두 번째로 선언하려고 시도하는 것은 오류를 낳습니다.

**참고:** 예제를 GitHub에서 볼 수 있습니다. (소스 코드 또한 볼 수 있습니다).

함수의 일부를 코드 안에 가두는 것은 이러한 문제를 피할 수 있고, 가장 좋은 방법이라 여겨집니다.

동물원 같네요. 사자, 얼룩말, 호랑이, 그리고 펭귄은 자신들만의 울타리 안에 있으며, 그들의 울타리 내부에 있는 것만 건드릴 수 있어요. 함수 스코프처럼 말이죠. 만약 동물들이 다른 울타리 안으로 들어갈 수 있었다면, 문제가 생겼을 겁니다. 좋게는 다른 동물이 낯선 거주 환경에서 불편함을 느끼는 정도겠죠. 사자나 호랑이가 펭귄의 물기 많고 추운 영역 안에서 끔찍함을 느끼듯이요. 하지만 최악의 상황엔 사자나 호랑이가 펭귄을 먹어 치울지도 모르죠!

![](/ko/docs/Learn/JavaScript/Building_blocks/Functions/mdn-mozilla-zoo.png)

사육사는 전역 스코프와 같습니다. 그들은 모든 울타리에 들어갈 수 있고, 먹이를 보충하고, 아픈 동물들을 돌볼 수 있어요.

### 직접 해보기: 스코프랑 놀자

스코프를 설명하기 위해 스코프 사용의 실례를 한번 봅시다.

1. 먼저, 주어진 function-scope.html 예제의 복사본을 만드세요. 예제에는 2개의 함수 `a()` 와 `b()`, 그리고 3개의 변수 — `x`, `y`, 와 `z` —가 있습니다. 그 중 2개는 함수 안에 정의되어 있으며, 1개는 전역 스코프에 정의되어 있습니다. 이것은 또한 세 번째 함수 `output()`을 포함하고 있는데, 이건 하나의 매개변수만 받으며, 페이지의 단락 안에 그것을 출력합니다.
2. 예제를 인터넷 브라우저나 텍스트 에디터를 통해 열어봅시다.
3. 브라우저 개발자 툴에서 JavaScript 콘솔을 엽시다. JavaScript 콘솔에서 아래와 같이 작성해보세요.

```js
output(x);
```

여러분은 브라우저 뷰포트에 출력된 변수 `x`의 값을 볼 수 있을 것입니다.
4. 이제 다음을 콘솔에 입력해 보세요.

```js
output(y);
output(z);
```

이것 모두는 다음의 오류를 리턴할 것입니다. "ReferenceError: y is not defined". 이것은 왜 그럴까요? 왜냐하면 함수 스코프 때문입니다. — `y`와 `z`는 `a()`와 `b()`함수 안에 잡혀 있어서, `output()`은 전역 스코프에서 호출되었을 때 그들에게 접근할 수 없습니다.
5. 그러나, 이것이 다른 함수 안쪽에서 호출되었을 때는 어떨까요? `a()`와 `b()`를 다음과 같이 보이도록 수정해 보세요.

```js
function a() {
  var y = 2;
  output(y);
}

function b() {
  var z = 3;
  output(z);
}
```

코드를 저장하고 브라우저에서 다시 로드한 후, `a()`와 `b()` 함수를 JavaScript 콘솔에서 호출해 보세요.

```js
a();
b();
```

여러분은 페이지에 출력된 `y`와 `z`값들을 볼 수 있을 것입니다. `output()` 함수가 다른 함수 안쪽에서 호출되고 있으므로, 이것은 잘 작동합니다. — 각각의 경우에서, 같은 스코프에서 그것이 출력하고 있는 변수들이 정의되어 있으므로. `output()`는 전역 스코프에서 정의되었으므로, 이 함수 자체는 어디서든 이용할 수 있습니다.
6. 이제 여러분의 코드를 다음과 같이 갱신해 보세요.

```js
function a() {
  var y = 2;
  output(x);
}

function b() {
  var z = 3;
  output(x);
}
```

7. 저장하고 다시 로드한 후 이것을 JavaScript 콘솔에서 시도해 보세요.

```js
a();
b();
```

8. 브라우저 뷰포트에 `a()` 와 `b()` 모두 x 값을 출력해야 합니다. 왜냐하면 비록 `output()` 호출이 `x`가 정의되어 있는 같은 스코프에 있지 않더라도, `x`는 전역 변수이므로 모든 코드 어디서든 이용 가능하기 때문에 이것들은 잘 작동합니다.
9. 마지막으로, 여러분의 코드를 다음과 같이 갱신해 보세요.

```js
function a() {
  var y = 2;
  output(z);
}

function b() {
  var z = 3;
  output(y);
}
```

10. 저장하고 다시 로드한 후, JavaScript 콘솔에서 다시 다음을 시도해 보세요.

```js
a();
b();
```

이번에는 `a()` 와 `b()` 호출이 둘 다 이 짜증나는 "ReferenceError: z is not defined" 오류를 리턴할 것입니다. — 이것은 왜냐하면 `output()` 호출과 그들이 출력하기를 시도하는 변수들이 같은 함수 스코프 내부에 정의되어 있지 않기 때문입니다. — 변수들은 효과적으로 이 함수 호출에 보이지 않습니다.

**참고:** 같은 스코프 규칙은 반복문 (예: `for() { ... }`)과 조건문(conditional blocks) (예: `if() { ... }`)에 적용되지 않습니다. — 이것들은 아주 비슷하게 생겼지만, 같은 것이 아닙니다! 헷갈리지 않도록 조심하세요.

**참고:** ReferenceError: "x" is not defined 오류는 여러분이 마주칠 가장 일반적인 것들 중 하나입니다. 만약 여러분이 이 오류를 얻었고 여러분이 문제의 변수를 정의했다는 것이 확실하다면, 그것이 어떤 스코프 안에 들어있는지 확인해 보세요.

### 함수 내부의 함수

여러분은 함수를 어디에서나, 심지어 다른 함수 내에서도 호출할 수 있다는 것을 명심하세요. 이것은 종종 코드를 깔끔하게 유지하기 위한 방법으로써 사용됩니다. — 만약 여러분이 크고 복잡한 함수를 가지고 있다면, 만약 여러분이 그것을 몇몇의 하위 함수(sub-functions)로 나눈다면 이해하기 더 쉬울 것입니다.

```js
function myBigFunction() {
  var myValue;

  subFunction1();
  subFunction2();
  subFunction3();
}

function subFunction1() {
  console.log(myValue);
}

function subFunction2() {
  console.log(myValue);
}

function subFunction3() {
  console.log(myValue);
}
```

함수 내부에서 사용되고 있는 값들이 올바르게 스코프 내에 있는지 확실히 하세요. 상기의 예시는 `ReferenceError: myValue is not defined` 오류를 던질 것인데, 이는 왜냐하면 비록 `myValue` 변수가 함수가 호출되는 같은 스코프 내에 정의되어 있긴 하지만, 이것은 함수 정의 (함수가 호출될 때 실행되는 실제 코드) 내부에 정의되어 있지 않습니다. 이것을 작동하게 하려면, 여러분은 값을 함수 내부에 매개변수로써 다음과 같이 전달해야만 합니다.

```js
function myBigFunction() {
  var myValue = 1;

  subFunction1(myValue);
  subFunction2(myValue);
  subFunction3(myValue);
}

function subFunction1(value) {
  console.log(value);
}

function subFunction2(value) {
  console.log(value);
}

function subFunction3(value) {
  console.log(value);
}
```

실력을 평가해 보세요!
------------

이 문서를 끝까지 읽으셨지만, 중요한 것들을 여전히 기억하고 계신가요? 다음 문서를 읽기 전에 이 문서의 내용을 잘 학습하고 이해하셨는지 확인하실 수 있습니다 — 실력을 평가해 보세요: 함수. 이 테스트들은 다음 두 문서에서 다뤄지는 기술들을 요구하므로, 여러분은 그 문서들을 이 테스트를 시도해 보기 전에 먼저 읽기를 원할지도 모릅니다.

결론
--

이 문서는, 여러분만의 사용자 정의 함수 만들기를 익히도록 돕고 실제적인 것을 다루는 다음 문서에 대한 길을 만들며, 함수 뒤에 있는 핵심적인 개념들을 탐구했습니다.

같이 보기
-----

* 자세한 함수 가이드 — 여기 포함되지 않은 몇몇 고급 기능들을 다룹니다.
* 함수 참고서
* 기본 매개변수, 화살표 함수 — 고급 개념 참고서
* 이전
* Overview: Building blocks
* 다음