this - JavaScript

this
====

JavaScript에서 **함수의 `this` 키워드**는 다른 언어와 조금 다르게 동작합니다. 또한 엄격 모드와 비엄격 모드에서도 일부 차이가 있습니다.

대부분의 경우 `this`의 값은 함수를 호출한 방법에 의해 결정됩니다. 실행중에는 할당으로 설정할 수 없고 함수를 호출할 때 마다 다를 수 있습니다. ES5는 `함수를 어떻게 호출했는지 상관하지 않고 `this` 값을 설정할 수 있는` `bind` 메서드를 도입했고, ES2015는 스스로의 `this` 바인딩을 제공하지 않는 화살표 함수를 추가했습니다(이는 렉시컬 컨텍스트안의 `this`값을 유지합니다).

시도해보기
-----

구문
--

```js
this;
```

### 값

실행 컨텍스트(global, function 또는 eval)의 프로퍼티는 비엄격 모드에서 항상 객체를 참조하며, 엄격 모드에서는 어떠한 값이든 될 수 있습니다.

전역 문맥
-----

전역 실행 맥락에서 `this`는 엄격 모드 여부에 관계 없이 전역 객체를 참조합니다.

```js
// 웹 브라우저에서는 window 객체가 전역 객체
console.log(this === window); // true

a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b); // "MDN"
console.log(b); // "MDN"
```

>
> **노트:** global `globalThis` 프로퍼티를 사용하여 코드가 실행중인 현재 컨텍스트와 관계없이 항상 전역 객체를 얻을 수 있습니다.
>
>
>

함수 문맥
-----

함수 내부에서 `this`의 값은 함수를 호출한 방법에 의해 좌우됩니다.

### 단순 호출

다음 예제는 엄격 모드가 아니며 `this`의 값이 호출에 의해 설정되지 않으므로, 기본값으로 브라우저에서는 `window`인 전역 객체를 참조합니다.

```js
function f1() {
  return this;
}

// 브라우저
f1() === window; // true

// Node.js
f1() === global; // true
```

반면에 엄격 모드에서 `this` 값은 실행 문맥에 진입하며 설정되는 값을 유지하므로 다음 예시에서 보여지는 것 처럼 `this`는 `undefined`로 남아있습니다.

```js
function f2() {
  "use strict"; // 엄격 모드 참고
  return this;
}

f2() === undefined; // true
```

두번째 예제에서 `f2`를 객체의 메서드나 속성(예: `window.f2()`)으로써가 아닌 직접 호출했기 때문에 `this`는 `undefined`여야 합니다. 그러나 엄격 모드를 처음 지원하기 시작한 초기 브라우저에서는 구현하지 않았고, `window` 객체를 잘못 반환했습니다.

`this`의 값을 한 문맥에서 다른 문맥으로 넘기려면 다음 예시와 같이 `call()`이나 `apply()`를 사용하세요.

### 예시 1

```js
// call 또는 apply의 첫 번째 인자로 객체가 전달될 수 있으며 this가 그 객체에 묶임
var obj = { a: "Custom" };

// 변수를 선언하고 변수에 프로퍼티로 전역 window를 할당
var a = "Global";

function whatsThis() {
  return this.a; // 함수 호출 방식에 따라 값이 달라짐
}

whatsThis(); // this는 'Global'. 함수 내에서 설정되지 않았으므로 global/window 객체로 초기값을 설정한다.
whatsThis.call(obj); // this는 'Custom'. 함수 내에서 obj로 설정한다.
whatsThis.apply(obj); // this는 'Custom'. 함수 내에서 obj로 설정한다.
```

### 예시 2

```js
function add(c, d) {
  return this.a + this.b + c + d;
}

var o = { a: 1, b: 3 };

// 첫 번째 인자는 'this'로 사용할 객체이고,
// 이어지는 인자들은 함수 호출에서 인수로 전달된다.
add.call(o, 5, 7); // 16

// 첫 번째 인자는 'this'로 사용할 객체이고,
// 두 번째 인자는 함수 호출에서 인수로 사용될 멤버들이 위치한 배열이다.
add.apply(o, [10, 20]); // 34
```

비엄격 모드에서 `this`로 전달된 값이 객체가 아닌 경우, `call`과 `apply`는 이를 객체로 변환하기 위한 시도를 합니다. `null`과 `undefined` 값은 전역 객체가 됩니다. `7`이나 `'foo'`와 같은 원시값은 관련된 생성자를 사용해 객체로 변환되며, 따라서 원시 숫자 `7`은 `new Number(7)`에 의해 객체로 변환되고 문자열 `'foo'`는 `new String('foo')`에 의해 객체로 변환됩니다.

```js
function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7); // [object Number]
bar.call("foo"); // [object String]
bar.call(undefined); // [object global]
```

### `bind` 메서드

ECMAScript 5는 `Function.prototype.bind`를 도입했습니다. `f.bind(someObject)`를 호출하면 `f`와 같은 본문(코드)과 범위를 가졌지만 this는 원본 함수를 가진 새로운 함수를 생성합니다. 새 함수의 `this`는 호출 방식과 상관없이 영구적으로`bind()`의 첫 번째 매개변수로 고정됩니다.

```js
function f() {
  return this.a;
}

var g = f.bind({ a: "azerty" });
console.log(g()); // azerty

var h = g.bind({ a: "yoo" }); // bind는 한 번만 동작함!
console.log(h()); // azerty

var o = { a: 37, f: f, g: g, h: h };
console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty
```

### 화살표 함수

화살표 함수에서 `this`는 자신을 감싼 정적 범위입니다. 전역 코드에서는 전역 객체를 가리킵니다.

```js
var globalObject = this;
var foo = () => this;
console.log(foo() === globalObject); // true
```

**참고**: 화살표 함수를 `call()`, `bind()`, `apply()`를 사용해 호출할 때 `this`의 값을 정해주더라도 무시합니다. 사용할 매개변수를 정해주는 건 문제 없지만, 첫 번째 매개변수(`thisArg`)는 `null`을 지정해야 합니다.

```js
// 객체로서 메서드 호출
var obj = { func: foo };
console.log(obj.func() === globalObject); // true

// call을 사용한 this 설정 시도
console.log(foo.call(obj) === globalObject); // true

// bind를 사용한 this 설정 시도
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
```

어떤 방법을 사용하든 `foo`의 `this`는 생성 시점의 것으로 설정됩니다(위 예시에서는 global 객체). 다른 함수 내에서 생성된 화살표 함수에도 동일하게 적용됩니다. `this`는 싸여진 렉시컬 컨텍스트의 것으로 유지됩니다.

```js
// this를 반환하는 메소드 bar를 갖는 obj를 생성합니다.
// 반환된 함수는 화살표 함수로 생성되었으므로,
// this는 감싸진 함수의 this로 영구적으로 묶입니다.
// bar의 값은 호출에서 설정될 수 있으며, 이는 반환된 함수의 값을 설정하는 것입니다.
var obj = {
  bar: function () {
    var x = () => this;
    return x;
  },
};

// obj의 메소드로써 bar를 호출하고, this를 obj로 설정
// 반환된 함수로의 참조를 fn에 할당
var fn = obj.bar();

// this 설정 없이 fn을 호출하면,
// 기본값으로 global 객체 또는 엄격 모드에서는 undefined
console.log(fn() === obj); // true

// 호출 없이 obj의 메소드를 참조한다면 주의하세요.
var fn2 = obj.bar;
// 화살표 함수의 this를 bar 메소드 내부에서 호출하면
// fn2의 this를 따르므로 window를 반환할것입니다.
console.log(fn2()() == window); // true
```

위 예시에서, `obj.bar`에 할당된 함수(익명 함수 A라고 지칭)는 화살표 함수로 생성된 다른 함수(익명 함수 B라고 지칭)를 반환합니다. 결과로써 함수 B가 호출될 때 B의 `this`는 영구적으로 `obj.bar`(함수 A)의 `this`로 설정됩니다. 반환됨 함수(함수 B)가 호출될 때, `this`는 항상 초기에 설정된 값일 것입니다. 위 코드 예시에서, 함수 B의 `this`는 함수 A의 `this`인 `obj`로 설정되므로, 일반적으로 `this`를 `undefined`나 global 객체로 설정하는 방식으로 호출할 때도(또는 이전 예시에서처럼 global 실행 컨텍스트에서 다른 방법을 사용할 때에도) obj의 설정은 유지됩니다.

### 객체의 메서드로서

함수를 어떤 객체의 메서드로 호출하면 `this`의 값은 그 객체를 사용합니다.

다음 예제에서 `o.f()`를 실행할 때 `o` 객체가 함수 내부의 `this`와 연결됩니다.

```js
var o = {
  prop: 37,
  f: function () {
    return this.prop;
  },
};

console.log(o.f()); // 37
```

이 행동이 함수가 정의된 방법이나 위치에 전혀 영향을 받지 않는 것에 유의해라. 이전 예제에서, `o` 의 정의 중 `f` 함수를 구성원으로 내부에 정의 하였다. 그러나, 간단하게 함수를 먼저 정의하고 나중에 `o.f`를 추가할 수 있다. 이렇게 하면 동일한 동작 결과 이다 :

```js
var o = { prop: 37 };

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37
```

이는 함수가 `o`의 멤버 `f`로 부터 호출 된 것만이 중요하다는 것을 보여준다.

마찬가지로, 이 `this` 바인딩은 가장 즉각으로 멤버 대상에 영향을 받는다. 다음 예제에서, 함수를 실행할 때, 객체 `o.b`의 메소드 `g` 로서 호출한다. 이것이 실행되는 동안, 함수 내부의 `this`는 `o.b`를 나타낸다. 객체는 그 자신이 `o`의 멤버 중 하나라는 사실은 중요하지 않다. 가장 즉각적인 참조가 중요한 것이다.

```js
o.b = { g: independent, prop: 42 };
console.log(o.b.g()); // logs 42
```

#### 객체의 프로토타입 체인에서의 `this`

같은 개념으로 객체의 프로토타입 체인 어딘가에 정의한 메서드도 마찬가지입니다. 메서드가 어떤 객체의 프로토타입 체인 위에 존재하면, `this`의 값은 그 객체가 메서드를 가진 것 마냥 설정됩니다.

```js
var o = {
  f: function () {
    return this.a + this.b;
  },
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5
```

이 예제에서, `f` 속성을 가지고 있지 않은 변수 `p` 가 할당된 객체는, 프로토타입으로 부터 상속받는다. 그러나 그것은 결국 `o` 에서 `f` 이름을 가진 멤버를 찾는 되는 문제가 되지 않는다; `p.f` 를 찾아 참조하기 시작하므로, 함수 내부의 `this` 는 `p` 처럼 나타나는 객체 값을 취한다. 즉, `f` 는 `p` 의 메소드로서 호출된 이후로, `this` 는 `p` 를 나타낸다. 이것은 JavaScript 의 프로토타입 상속의 흥미로운 기능이다.

#### 접근자와 설정자의 `this`

다시 한 번 같은 개념으로, 함수를 접근자와 설정자에서 호출하더라도 동일합니다. 접근자나 설정자로 사용하는 함수의 `this`는 접근하거나 설정하는 속성을 가진 객체로 묶입니다.

```js
function sum() {
  return this.a + this.b + this.c;
}

var o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3;
  },
};

Object.defineProperty(o, "sum", {
  get: sum,
  enumerable: true,
  configurable: true,
});

console.log(o.average, o.sum); // 2, 6
```

### 생성자로서

함수를 `new` 키워드와 함께 생성자로 사용하면 `this`는 새로 생긴 객체에 묶입니다.

While the default for a constructor is to return the object referenced by `this`, it can instead return some other object (if the return value isn't an object, then the `this` object is returned).

```js
/\*
 \* Constructors work like this:
 \*
 \* function MyConstructor(){
 \* // Actual function body code goes here.
 \* // Create properties on |this| as
 \* // desired by assigning to them. E.g.,
 \* this.fum = "nom";
 \* // et cetera...
 \*
 \* // If the function has a return statement that
 \* // returns an object, that object will be the
 \* // result of the |new| expression. Otherwise,
 \* // the result of the expression is the object
 \* // currently bound to |this|
 \* // (i.e., the common case most usually seen).
 \* }
 \*/

function C() {
  this.a = 37;
}

var o = new C();
console.log(o.a); // 37

function C2() {
  this.a = 37;
  return { a: 38 };
}

o = new C2();
console.log(o.a); // 38
```

### DOM 이벤트 처리기로서

함수를 이벤트 처리기로 사용하면 this는 이벤트를 발사한 요소로 설정됩니다. 일부 브라우저는 `addEventListener()` 외의 다른 방법으로 추가한 처리기에 대해선 이 규칙을 따르지 않습니다.

```js
// 처리기로 호출하면 관련 객체를 파랗게 만듦
function bluify(e) {
  // 언제나 true
  console.log(this === e.currentTarget);
  // currentTarget과 target이 같은 객체면 true
  console.log(this === e.target);
  this.style.backgroundColor = "#A5D9F3";
}

// 문서 내 모든 요소의 목록
var elements = document.getElementsByTagName("\*");

// 어떤 요소를 클릭하면 파랗게 변하도록
// bluify를 클릭 처리기로 등록
for (var i = 0; i < elements.length; i++) {
  elements[i].addEventListener("click", bluify, false);
}
```

### 인라인 이벤트 핸들러에서

코드를 인라인 이벤트 처리기로 사용하면 `this`는 처리기를 배치한 DOM 요소로 설정됩니다.

```js
<button onclick="alert(this.tagName.toLowerCase());">this 표시</button>
```

위의 경고창은 `button`을 보여줍니다. 다만 바깥쪽 코드만 `this`를 이런 방식으로 설정합니다.

```js
<button onclick="alert((function() { return this; })());">
  내부 this 표시
</button>
```

위의 경우, 내부 함수의 this는 정해지지 않았으므로 전역/`window` 객체를 반환합니다. 즉 비엄격 모드에서 `this`를 설정하지 않은 경우의 기본값입니다.

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # sec-this-keyword |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* 엄격 모드


null - JavaScript

null
====

**`null`** 은 JavaScript의 원시 값 중 하나로, 어떤 값이 의도적으로 비어있음을 표현하며 불리언 연산에서는 거짓으로 취급합니다.

시도해보기
-----

구문
--

```js
null;
```

설명
--

`null`은 리터럴로서 `null`이라 씁니다. `null`은 `undefined`과 같이 글로벌 객체의 속성에 대한 식별자가 아닙니다. 대신 `null`은 식별되지 않은 것을 표현합니다. 즉, 변수가 아무런 객체를 가리키지 않음을 표현합니다. API에서는 `null`을 종종 관련된 객체가 존재하지 않을 때 그 객체 대신 사용합니다.

```js
// 정의되지 않고 초기화된 적도 없는 foo
foo; //ReferenceError: foo is not defined

// 존재하지만 값이나 자료형이 존재하지 않는 foo
var foo = null;
foo; //null
```

### `null`과 `undefined`의 차이

`null` 또는 `undefined`를 검사할 때, 동등 연산자(==)와 일치 연산자(===)의 차이를 주의하세요. 동등 연산자는 자료형 변환을 수행합니다.

```js
typeof null; // "object" (하위호환 유지를 위해 "null"이 아님)
typeof undefined; // "undefined"
null === undefined; // false
null == undefined; // true
null === null; // true
null == null; // true
!null; // true
isNaN(1 + null); // false
isNaN(1 + undefined); // true
```

명세
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-null-value |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* `undefined`
* `NaN`
* `void` 연산자


await - JavaScript

await
=====

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since April 2017.

* Learn more
* See full compatibility
* Report feedback
`await`연산자는 `Promise`를 기다리기 위해 사용됩니다. 연산자는 `async function` 내부에서만 사용할 수 있습니다.구문
--

```js
[rv] = await expression;
```

`expression`

`Promise` 혹은 기다릴 어떤 값입니다.

`rv`

`Promise`에 의해 만족되는 값이 반환됩니다. `Promise`가 아닌 경우에는 그 값 자체가 반환됩니다.

설명
--

`await` 문은 `Promise`가 fulfill되거나 `reject` 될 때까지 `async` 함수의 실행을 일시 정지하고, `Promise`가 fulfill되면 `async` 함수를 일시 정지한 부분부터 실행합니다. 이때 `await` 문의 반환값은 `Promise` 에서 fulfill된 값이 됩니다.

만약 `Promise`가 `reject`되면, `await` 문은 `reject`된 값을 `throw`합니다.

`await` 연산자 다음에 나오는 문의 값이 `Promise`가 아니면 해당 값을 resolved Promise로 변환시킵니다.

An `await` can split execution flow, allowing the caller of the `await`'s function to resume execution before the deferred continuation of the `await`'s function. After the `await` defers the continuation of its function, if this is the first `await` executed by the function, immediate execution also continues by returning to the function's caller a pending `Promise` for the completion of the `await`'s function and resuming execution of that caller.

예제
--

만약 `Promise`가 `await`에 넘겨지면, `await`은 `Promise`가 fulfill되기를 기다렸다가, 해당 값을 리턴합니다.

```js
function resolveAfter2Seconds(x) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function f1() {
  var x = await resolveAfter2Seconds(10);
  console.log(x); // 10
}

f1();
```

`Thenable objects` will be fulfilled just the same.

```js
async function f2() {
  const thenable = {
    then: function (resolve, \_reject) {
      resolve("resolved!");
    },
  };
  console.log(await thenable); // resolved!
}

f2();
```

만약 값이 `Promise`가 아니라면, 해당 값은 `resolve`된 `Promise`로 변환되며 이를 기다립니다.

```js
async function f2() {
  var y = await 20;
  console.log(y); // 20
}
f2();
```

만약 `Promise`가 `reject`되면, `reject`된 값이 `throw`됩니다.

```js
async function f3() {
  try {
    var z = await Promise.reject(30);
  } catch (e) {
    console.log(e); // 30
  }
}
f3();
```

try블럭 없이 rejected `Promise`다루기

```js
var response = await promisedFunction().catch((err) => {
  console.error(err);
});
// response will be undefined if the promise is rejected
```

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # sec-async-function-definitions |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `async function`
* `async function expression`
* `AsyncFunction` object


나머지 (%) - JavaScript

나머지 (%)
=======

나머지 연산자(`%`)는 왼쪽 피연산자를 오른쪽 피연산자로 나눴을 때의 나머지를 구합니다. 부호는 항상 왼쪽 피연산자의 부호를 따릅니다.

시도해보기
-----

구문
--

```js
x % y;
```

예제
--

### 양의 피제수의 나머지

```js
12 % 5; // 2
1 % -2; // 1
1 % 2; // 1
2 % 3; // 2
5.5 % 2; // 1.5
```

### 음의 피제수의 나머지

```js
(-12 % 5) - // -2
  (1 % 2) - // -1
  (4 % 2); // -0
```

### NaN의 나머지

```js
NaN % 2; // NaN
```

### Infinity의 나머지

```js
Infinity % 2; // NaN
Infinity % 0; // NaN
Infinity % Infinity; // NaN
```

명세
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-multiplicative-operators |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* 더하기 연산자
* 빼기 연산자
* 나누기 연산자
* 곱하기 연산자
* 거듭제곱 연산자
* 증가 연산자
* 감소 연산자
* 단항 부정 연산자
* 단항 플러스 연산자


거듭제곱 할당 (**=) - JavaScript

거듭제곱 할당 (\*\*=)
===============

거듭제곱 할당 연산자(`**=`)는 오른쪽 피연산자의 값으로 변수를 거듭제곱한 결과를 다시 변수에 할당합니다.

시도해보기
-----

구문
--

```js
x \*\*= y; // x = x \*\* y
```

예제
--

### 거듭제곱 할당 사용하기

```js
// bar = 5
// 위와 같은 변수를 가정할 때

bar \*\*= 2; // 25
bar \*\*= "foo"; // NaN
```

명세
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* JavaScript 안내서의 할당 연산자
* 거듭제곱 연산자


yield - JavaScript

yield
=====

`yield` 키워드는 제너레이터 함수 (`function*` 또는 레거시 generator (en-US) 함수)를 중지하거나 재개하는데 사용됩니다.

문법
--

```js
[rv] = yield [expression];
```

`expression`

제너레이터 함수에서 제너레이터 프로토콜을 통해 반환할 값을 정의합니다. 값이 생략되면, `undefined를 반환합니다.`

`rv`

제너레이터 실행을 재개 하기 위해서, optional value을 제너레이터의 `next()` 메서드로 전달하여 반환합니다.

설명
--

`yield 키워드`는 제너레이터 함수의 실행을 중지시키거나 그리고 `yield` 키워드 뒤에오는 표현식[expression]의 값은 제너레이터의 caller로 반환된다. 제너레이터 버전의 `return` 키워드로 생각 할 수 있다.

`yield` 키워드는 실질적으로 value 와 done 이라는 두 개의 속성을 가진 `IteratorResult` 객체를 반환한다. `value` 속성은 `yield` 표현(expression)의 실행 결과를 나타내고, `done` 속성은 제너레이터 함수가 완전히 종료되었는지 여부를 불린(Boolean) 형태로 보여줍니다.

yield 표현식에서 중지되면 ,제너레이터의 next()가 메서드가 호출될 때까지 제너레이터의 코드 실행이 중지된다. 제너레이터의 next()메서드를 호출할 때마다 제너레이터는 실행을 재개하며 그리고 다음의 같은 경우에 진행될 때 실행된다:

* `yield 는` 제너레이터가 한번 멈추게 하고 제너레이터의 새로운 값을 반환한다. 다음번의 next()가 호출된 후, yield 이후에 선언된 코드가 바로 실행된다.
* `throw`는 제네레이터에서 예외를 설정할 때 사용된다. 예외가 발생할 경우 제너레이터의 전체적으로 실행이 중지되고, 그리고 다시 켜는 것이 일반적으로 실행됩니다.
* 제너레이터 함수가 종료가 되었다; 이 경우, 제너레이터 실행이 종료되고 `IteratorResult` 는 `caller` 로 값이 `undefined`이고 done의 값이 true 로 리턴한다.
* `return` 문에 도달했다. 이 경우에는, 이 값이 종료되고 `IteratorResult` 는 `caller` 로 `return` 문에 의해 반환되는 값과 done의 값이 true 로 리턴한다.

만약에 optional value가 제너레이터의 next() 메서드로 전달되면, optional value는 제너레이터의 현재 yield의 연산으로 반환되는 값이 된다.

generator 코드 경로, yield연산자, `Generator.prototype.next()`에 이르기까지 새로운 시작 값을 지정할 수 있는 능력과 제네레이터는 커다란 힘과 제어를 제공한다.

예시
--

다음 코드는 제너레이터 함수의 선언의 예시이다.

```js
function\* foo() {
  var index = 0;
  while (index <= 2)
    // when index reaches 3,
    // yield's done will be true
    // and its value will be undefined;
    yield index++;
}
```

제너레이터 함수가 정의되면 , 아래 코드와 보여지는 것처럼 iterator로 만들어 사용할 수 있다.

```js
var iterator = foo();
console.log(iterator.next()); // { value: 0, done: false }
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
```

명세
--

| Specification |
| --- |
| ECMAScript Language Specification # prod-YieldExpression |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* The Iterator protocol (en-US)
* `function*`
* `function* expression`
* `yield*`


Optional chaining - JavaScript

Optional chaining
=================

**optional chaining** 연산자 (**`?.`**) 는 체인의 각 참조가 유효한지 명시적으로 검증하지 않고, 연결된 객체 체인 내에 깊숙이 위치한 속성 값을 읽을 수 있다.

`?.` 연산자는 `.` 체이닝 연산자와 유사하게 작동하지만, 만약 참조가 nullish (`null` 또는 `undefined`)이라면, 에러가 발생하는 것 대신에 표현식의 리턴 값은 `undefined`로 단락된다. 함수 호출에서 사용될 때, 만약 주어진 함수가 존재하지 않는다면, `undefined`를 리턴한다.

따라서 참조가 누락될 가능성이 있는 경우 연결된 속성으로 접근할 때 더 짧고 간단한 표현식이 생성된다. 어떤 속성이 필요한지에 대한 보증이 확실하지 않는 경우 객체의 내용을 탐색하는 동안 도움이 될 수 있다.

optional chaining은 선언되지 않은 루트 객체에 사용할 수 없지만, 정의되지 않은 루트 객체와는 함께 사용할 수 있다.

시도해보기
-----

문법
--

```js
obj?.prop;
obj?.[expr];
arr?.[index];
func?.(args);
```

설명
--

optional chaining 연산자는 참조나 기능이 `undefined` 또는 `null`일 수 있을 때 연결된 객체의 값에 접근하는 단순화할 수 있는 방법을 제공한다.

예를 들어, 중첩된 구조를 가진 객체에서 `obj`가 있다. optional chaining이 없이 깊이 중첩된 하위 속성을 찾으려면, 다음과 같이 참조를 확인해야 한다:

```js
let nestedProp = obj.first && obj.first.second;
```

`obj.first`의 값은 `obj.first.second`의 값에 접근하기 전에 `null` (그리고 `undefined`)가 아니라는 점을 검증한다. 이는 만약에 `obj.first`를 테스트 없이 `obj.first.second` 에 직접 접근할 때 일어날 수 있는 에러를 방지한다.

그러나 optional chaining 연산자(`?.`)를 사용하여, `obj.first.second` 에 접근하기 전에 `obj.first`의 상태에 따라 명시적으로 테스트하거나 단락시키지 않아도 된다:

```js
let nestedProp = obj.first?.second;
```

`.` 대신에 `?.` 연산자를 사용함으로써, JavaScript는 `obj.first.second`에 접근하기 전에 `obj.first`가 `null` 또는 `undefined`가 아니라는 것을 암묵적으로 확인하는 것을 알고 있다. 만약 `obj.first`가 `null` 또는 `undefined`이라면, 그 표현식은 자동으로 단락되어 `undefined`가 반환된다.

이는 임시 변수가 실제로 생성되지 않는다는 점을 제외하고 다음과 동일하다.

```js
let temp = obj.first;
let nestedProp = temp === null || temp === undefined ? undefined : temp.second;
```

### 함수의 호출과 Optional chaining

존재하지 않을 수 있는 매서드를 호출할 때, optional chaining을 사용할 수 있다. 예를 들어, 구현 기간이나 사용자 장치에서 사용할 수 없는 기능 때문에 메서드를 사용할 수 없는 API를 사용할 경우, 유용할 수 있다.

함수 호출과 optional chaining을 사용함으로써 메서드를 찾을 수 없는 경우에 예외를 발생시키는 것 대신에 그 표현식은 자동으로 `undefined`를 반환한다:

```js
let result = someInterface.customMethod?.();
```

**메모:** 만약 속성에 해당 이름이 있지만 함수가 아니라면, `?.`의 사용은 여전히 예외를 발생시킨다. `TypeError` exception (`x.y` `is not a function`).

**메모:** 만약 `someInterface` 자체가 `null`이나 `undefined`이면, `TypeError` 예외가 여전히 발생 할 것이다. `someInterface` 자체가 `null`이나 `undefined`으로 예상된다면, `?.`을 사용해야한다: `someInterface?.customMethod?.()`

#### optional callbacks과 event handlers 다루기

만약 객체에서 destructuring assignment로 callbacks 또는 fetch 메서드를 사용한다면, 그 존재 여부를 테스트하지 않으면 함수로 호출할 수 없는 존재 하지 않는 값을 가질 수 있다. `?.`을 사용하면, 다음 추가 테스트를 피할 수 있다:

```js
// Written as of ES2019
function doSomething(onContent, onError) {
  try {
    // ... do something with the data
  } catch (err) {
    if (onError) {
      // Testing if onError really exists
      onError(err.message);
    }
  }
}
```

```js
// Using optional chaining with function calls
function doSomething(onContent, onError) {
  try {
    // ... do something with the data
  } catch (err) {
    onError?.(err.message); // no exception if onError is undefined
  }
}
```

### 표현식에서 Optional chaining

optional chaining 연산자를 속성에 표현식으로 접근할 때 대괄호 표기법(the bracket notation of the property accessor)을 사용할 수 있다:

```js
let nestedProp = obj?.["prop" + "Name"];
```

### Optional chaining은 할당자 왼쪽에서 유효하지 않습니다

```js
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
```

### Optional chaining으로 배열 항목에 접근하기

```js
let arrayItem = arr?.[42];
```

예제
--

### 기본 예제

이 예제는 해당 멤버가 없을 때, map에서 멤버 bar의 `name`의 속성 값을 찾는다. 그러므로 결과는 `undefined`이다.

```js
let myMap = new Map();
myMap.set("foo", { name: "baz", desc: "inga" });

let nameBar = myMap.get("bar")?.name;
```

### 단락 평가

표현식에서 optional chaining을 사용할 때, 만약 왼쪽에 있는 피연산자가 `null` or `undefined`인 경우, 그 표현식은 평가되지 않는다. 예들 들어:

```js
let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // 0 x는 증가하지 않음
```

### optional chaining 연산자 쌓기

중첩된 구조에서는 optional chaining을 여러 번 사용할 수 있다:

```js
let customer = {
  name: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls", // detailed address is unknown
  },
};
let customerCity = customer.details?.address?.city;

// … this also works with optional chaining function call
let duration = vacations.trip?.getTime?.();
```

### 널 병합 연산자와 같이 사용하기

널 병합 연산자는 optional chaining를 사용한 후에 아무 값도 찾을 수 없을 때 기본 값을 주기 위해 사용될 수 있다:

```js
let customer = {
  name: "Carl",
  details: { age: 82 },
};
const customerCity = customer?.city ?? "Unknown city";
console.log(customerCity); // Unknown city
```

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # prod-OptionalExpression |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

참고
--

* The Nullish Coalescing Operator
* TC39 proposals


나누기 (/) - JavaScript

나누기 (/)
=======

나누기 연산자(`/`)는 왼쪽 피연산자를 피제수, 오른쪽 피연산자를 제수로 하여 몫을 구합니다.

시도해보기
-----

구문
--

```js
x / y;
```

예제
--

### 기본 나눗셈

```js
1 / 2; // 0.5

Math.floor(3 / 2); // 1

1.0 / 2.0; // 0.5
```

### 0으로 나누기

```js
2.0 / 0; // Infinity

2.0 / 0.0; // Infinity, 0.0 === 0이기 때문

2.0 / -0.0; // -Infinity
```

명세
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-multiplicative-operators |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* 더하기 연산자
* 빼기 연산자
* 곱하기 연산자
* 나머지 연산자
* 거듭제곱 연산자
* 증가 연산자
* 감소 연산자
* 단항 부정 연산자
* 단항 플러스 연산자


static - JavaScript

static
======

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2017.

* Learn more
* See full compatibility
* Report feedback
**static** 키워드는 클래스의 정적 메서드를 정의합니다.

시도해보기
-----

문법
--
```

    static methodName() { ... }
```

설명
--

정적 메서드는 클래스의 인스턴스 없이 호출이 가능하며 클래스가 인스턴스화되면 호출할 수 없다. 정적 메서드는 종종 어플리케이션의 유틸리티 함수를 만드는데 사용된다.

정적 메서드의 호출
----------

#### 다른 정적 메서드에서의 호출

동일한 클래스 내의 다른 정적 메서드 내에서 정적 메서드를 호출하는 경우 키워드 `this`를 사용할 수 있다.

```js
class StaticMethodCall {
  static staticMethod() {
    return "Static method has been called";
  }
  static anotherStaticMethod() {
    return this.staticMethod() + " from another static method";
  }
}
StaticMethodCall.staticMethod();
// 'Static method has been called'

StaticMethodCall.anotherStaticMethod();
// 'Static method has been called from another static method'
```

### 클래스 생성자 및 다른 메서드에서의 호출

정적 메서드가 비정적 메서드에서 키워드`this` 를 써서는 직접적인 접근을 할 수 없다. 바른 호출 방법은 클래스 명칭을 쓰거나, 즉 `CLASSNAME.STATIC_METHOD_NAME()` 을 이용하거나 혹은 그 메서드를 생성자의 한 속성으로 부르는 것으로, 즉 `constructor` : `this.constructor.STATIC_METHOD_NAME()`를 이용한다.

```js
class StaticMethodCall {
  constructor() {
    console.log(StaticMethodCall.staticMethod());
    // 'static method has been called.'

    console.log(this.constructor.staticMethod());
    // 'static method has been called.'
  }

  static staticMethod() {
    return "static method has been called.";
  }
}
```

예제
--

아래 예제는 여러가지 내용을 설명합니다.

1. 어떻게 정적 메서드가 클래스에서 구현되는지
2. 클래스의 정적 맴버가 서브클래스화 되는 것을 보여줍니다.
3. 정적 메서드가 어떤 경우에 호출 될 수 있는지와 없는지를 설명합니다.

```js
class Triple {
  static triple(n) {
    n = n || 1; //비트연산이 아니어야 합니다.
    return n \* 3;
  }
}

class BiggerTriple extends Triple {
  static triple(n) {
    return super.triple(n) \* super.triple(n);
  }
}

console.log(Triple.triple()); // 3
console.log(Triple.triple(6)); // 18
console.log(BiggerTriple.triple(3)); // 81
var tp = new Triple();
console.log(BiggerTriple.triple(3)); // 81 (부모의 인스턴스에 영향을 받지 않습니다.)
console.log(tp.triple()); // 'tp.triple은 함수가 아닙니다.'.
console.log(tp.constructor.triple(4)); // 12
```

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # sec-class-definitions |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

참고
--

* `class` expression
* `class` declaration
* Classes


Class static initialization blocks - JavaScript

Class static initialization blocks
==================================

**클래스 정적 초기화 블록**은 필드별 초기화를 사용하는 것보다 더 유연하게 `정적` 속성을 초기화 하는 `클래스`의 특수 기능입니다.

정적 블록을 사용하면 초기화 중에 명령문을 실행할 수 있으며, 이를 통해 `try...catch`를 포함하거나 단일 값에서 여러 필드를 설정하는 초기화 등을 가능하게 합니다.

 초기화는 현재 클래스의 선언 컨텍스트에서 프라이빗 상태에 대한 특별한 권한으로 수행됩니다.
 이는 정적 블록을 사용하여 인스턴스 프라이빗 필드가 있는 클래스와 같은 범위에서 선언된 다른 클래스 또는 함수 간에 정보를 공유할 수도 있음을 의미합니다. (C++의 "friend" 클래스와 유사)

시도해보기
-----

구문
--

```js
static { /\* … \*/ }
```

설명
--

`클래스`는 클래스 본문에 `static {}` 초기화 블록을 얼마든지 가질 수 있습니다.
 이들은 선언된 순서대로 인터리브된 정적 필드 이니셜라이저와 함께 계산됩니다.
 super 클래스의 정적 초기화는 하위 클래스보다 먼저 수행됩니다.

 정적 블록 내부에 선언된 변수의 범위는 해당 블록에 대한 로컬입니다.
 `static {}` 초기화 블록에서 선언된 `var`, `function`, `const` 또는 `let`은 해당 블록에 대해 로컬이므로 블록의 모든 `var` 선언은 호이스트 되지 않습니다.

```js
var y = "외부 y";

class A {
  static field = "내부 y";
  static {
    var y = this.field;
  }
}

// 정적 블록에서 정의된 var는 호이스티되지 않음
console.log(y);
// > '외부 y'
```

 정적 블록 내부의 `this`는 클래스의 생성자 객체를 참조합니다.
 `super.<property>`는 super 클래스의 속성에 액세스하는 데 사용할 수 있습니다.
 그러나 클래스 정적 초기화 블록에서 `super()`를 호출하거나 클래스 생성자 함수의 인수에 접근하려고 시도하는 것은 구문 오류라는 것을 알아두세요.

정적 블록의 범위는 클래스 본문의 lexical scope 내에 중첩되어 클래스의 프라이빗 인스턴스 변수에 접근할 수 있습니다.

정적 초기화 블록에는 데코레이터가 없을 수 있습니다. (클래스 자체는 있을 수 있음)

예제
--

### 다중 블록

 아래 코드는 정적 초기화 블록과 인터리브된 정적 필드 이니셜라이저가 있는 클래스를 보여줍니다.
 출력은 블록과 필드가 실행 순서대로 계산되었음을 보여줍니다.

```js
class MyClass {
  static field1 = console.log("필드1 호출됨");
  static {
    console.log("1번 정적 클래스 블록 호출됨");
  }
  static field2 = console.log("필드2 호출됨");
  static {
    console.log("2번 정적 클래스 블록 호출됨");
  }
}

/\*
> "필드1 호출됨"
> "1번 정적 클래스 블록 호출됨"
> "필드2 호출됨"
> "2번 정적 클래스 블록 호출됨"
\*/
```

super 클래스의 정적 초기화는 하위 클래스보다 먼저 수행됩니다.

### this와 super 사용하기

 정적 블록 내부의 `this`는 클래스의 생성자 객체를 참조합니다.
 이 코드는 퍼블릭 정적 필드에 접근하는 방법을 보여줍니다.

```js
class A {
  static field = "정적 필드";
  static {
    console.log(this.field);
  }
}
```

`super.property`는 `static` 블록 내에서 super 클래스의 속성을 참조하는 데 사용할 수 있습니다.
 여기에는 아래와 같이 정적 속성이 포함됩니다.

```js
class A {
  static fieldA = "A.fieldA";
}
class B extends A {
  static {
    console.log(super.fieldA);
    // 'A.fieldA'
  }
}
```

### 프라이빗 필드에 접근하기

아래의 예제는 클래스 외부의 객체에서 클래스의 프라이빗 객체에 대한 액세스 권한을 부여하는 방법을 보여줍니다. (v8.dev blog 블로그의 예제).

```js
let getDPrivateField;

class D {
  #privateField;
  constructor(v) {
    this.#privateField = v;
  }
  static {
    getDPrivateField = (d) => d.#privateField;
  }
}

getDPrivateField(new D("private"));
// > private
```

### 제2의 해결책

ES13 이전에는 정적 초기화를 수행하기 위해 다른 속성 다음에 호출되는 정적 메서드를 사용하거나 클래스 외부에 있는 초기화 메서드를 사용하는 복잡한 초기화를 진행했습니다.

두 경우 모두 접근 방식이 우아하지않고 클래스의 프라이빗 메서드에 대한 접근 권한을 부여하는것이 아니었습니다.

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # prod-ClassStaticBlock |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Class static initialization blocks (v8.dev blog)
* ES2022 feature: class static initialization blocks (2ality.com blog)
* Classes
* `super()`
* Object.prototype.constructor


extends - JavaScript

extends
=======

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2017.

* Learn more
* See full compatibility
* Report feedback
**`extends`** 키워드는 클래스를 다른 클래스의 자식으로 만들기 위해 class 선언 또는 class 식에 사용됩니다.

시도해보기
-----

구문
--
```

    class ChildClass extends ParentClass { ... }
```

설명
--

`extends` 키워드는 내장 객체뿐만 아니라 사용자 정의 클래스를 하위 클래스로 만들기 위해 사용될 수 있습니다.

확장( 클래스)의 `.prototype`은 `Object` 또는 `null`이어야 합니다.

예
-

### `extends` 사용하기

첫 번째 예는 `Polygon` 클래스로부터 `Square` 클래스를 만듭니다. 이 예는 live demo (source)에서 발췌했습니다.

```js
class Square extends Polygon {
  constructor(length) {
    // 여기서, length와 함께 부모 클래스의 생성자를 호출
    // Polygon의 너비 및 높이가 제공됨
    super(length, length);
    // 주의: 파생 클래스에서, super()가 먼저 호출되어야 'this'를
    // 사용할 수 있습니다. 이를 빼먹으면 참조 오류가 발생합니다.
    this.name = "Square";
  }

  get area() {
    return this.height \* this.width;
  }

  set area(value) {
    this.area = value;
  }
}
```

### 내장 객체에 `extends` 사용하기

이 예제는 내장 객체 `Date`를 확장합니다. 이 예제는 live demo (source)에서 발췌했습니다.

```js
class myDate extends Date {
  constructor() {
    super();
  }

  getFormattedDate() {
    var months = [
      "Jan",
      "Feb",
      "Mar",
      "Apr",
      "May",
      "Jun",
      "Jul",
      "Aug",
      "Sep",
      "Oct",
      "Nov",
      "Dec",
    ];
    return (
      this.getDate() + "-" + months[this.getMonth()] + "-" + this.getFullYear()
    );
  }
}
```

### `null` 확장

`null`에서 확장은 prototype 객체가 `Object.prototype` (en-US)으로부터 상속받지 않은 것을 제외하면 보통 클래스처럼 동작합니다.

```js
class nullExtends extends null {
  constructor() {}
}

Object.getPrototypeOf(nullExtends); // Function.prototype
Object.getPrototypeOf(nullExtends.prototype); // null
```

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # sec-class-definitions |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

참조
--

* Classes
* super


Private class fields - JavaScript

Private class fields
====================

class 의 속성(property)들은 기본적으로 public 하며 class 외부에서 읽히고 수정될 수 있다. 하지만, ES2019 에서는 해쉬 `#` prefix 를 추가해 private class 필드를 선언할 수 있게 되었다.

Syntax
------

```js
class ClassWithPrivateField {
  #privateField;
}

class ClassWithPrivateMethod {
  #privateMethod() {
    return "hello world";
  }
}

class ClassWithPrivateStaticField {
  static #PRIVATE\_STATIC\_FIELD;
}
```

Examples
--------

### Private static fields

private 필드는 class 선언문 내부의 class 생성자(class constructor)에서 접근이 가능하다.

static 메소드에서만 static 변수들을 호출할 수 있다는 제약은 그대로 유지된다.

```js
class ClassWithPrivateStaticField {
  static #PRIVATE\_STATIC\_FIELD;

  static publicStaticMethod() {
    ClassWithPrivateStaticField.#PRIVATE\_STATIC\_FIELD = 42;
    return ClassWithPrivateStaticField.#PRIVATE\_STATIC\_FIELD;
  }
}

console.assert(ClassWithPrivateStaticField.publicStaticMethod() === 42);
```

Private static 필드는 class evaluation 시 class 생성자(class constructor)에 추가된다.

Private static 필드는 해당 필드를 선언한 class 에서만 접근할 수 있다.

이는 `this` 를 사용함에 있어 예상치 못한 동작을 야기할 수 있다.

```js
class BaseClassWithPrivateStaticField {
  static #PRIVATE\_STATIC\_FIELD;

  static basePublicStaticMethod() {
    this.#PRIVATE\_STATIC\_FIELD = 42;
    return this.#PRIVATE\_STATIC\_FIELD;
  }
}

class SubClass extends BaseClassWithPrivateStaticField {}

let error = null;

try {
  SubClass.basePublicStaticMethod();
} catch (e) {
  error = e;
}

console.assert(error instanceof TypeError);
```

### Private instance fields

private 인스턴스 필드는 **# 이름 ('해쉬 이름' 으로 발음)**, 즉 `#` prefix 를 가진 식별자로 선언된다. `#` 은 그 이름 자체의 일부이며 선언과 접근 시에 모두 사용된다.

캡슐화(encapsulation) 는 언어로부터 강제된다(enforced by the language). 즉, scope 밖에서 `#` 이름에 접근하는 것은 syntax error 이다.

```js
class ClassWithPrivateField {
  #privateField;

  constructor() {
    this.#privateField = 42;
    this.#randomField = 444; // Syntax error
  }
}

const instance = new ClassWithPrivateField();
instance.#privateField === 42; // Syntax error
```

### Private Methods

#### Private static methods

**private static 메소드**는 public static 메소드처럼 인스턴스가 아닌 class 로부터 호출된다. 그리고 private static 필드처럼 class 선언문 내부에서만 접근 가능하다.

```js
private static 메소드는 generator, async 그리고 async generator 함수가 될 수 있다.

    class ClassWithPrivateStaticMethod {
      static #privateStaticMethod() {
        return 42
      }

      static publicStaticMethod1() {
        return ClassWithPrivateStaticMethod.#privateStaticMethod();
      }

      static publicStaticMethod2() {
        return this.#privateStaticMethod();
      }
    }

    console.assert(ClassWithPrivateStaticMethod.publicStaticMethod1() === 42);
    console.assert(ClassWithPrivateStaticMethod.publicStaticMethod2() === 42);
```

이는 `this` 를 사용할 때 예상치 못한 동작을 발생시킬 수 있다. (이는 `this` binding rule 이 적용되기 때문이다.) 다음 예시에서 `Derived.publicStaticMethod2()` 를 호출할 때, `this` 는 class `Derived` (`Base` 가 아니라) 를 가리킨다.

```js
class Base {
  static #privateStaticMethod() {
    return 42;
  }
  static publicStaticMethod1() {
    return Base.#privateStaticMethod();
  }
  static publicStaticMethod2() {
    return this.#privateStaticMethod();
  }
}

class Derived extends Base {}

console.log(Derived.publicStaticMethod1()); // 42
console.log(Derived.publicStaticMethod2()); // TypeError
```

#### Private instance methods

private 인스턴스 메소드는 private 인스턴스 필드와는 다르게 class 인스턴스로부터 접근 가능하다.

```js
class ClassWithPrivateMethod {
  #privateMethod() {
    return "hello world";
  }

  getPrivateMessage() {
    return this.#privateMethod();
  }
}

const instance = new ClassWithPrivateMethod();
console.log(instance.getPrivateMessage());
// expected output: "hello world"
```

private 인스턴스 메소드는 generator, async 그리고 async generator 함수가 될 수 있다. private getter 와 setter 또한 가능하다:

```js
class ClassWithPrivateAccessor {
  #message;

  get #decoratedMessage() {
    return `✨${this.#message}✨`;
  }
  set #decoratedMessage(msg) {
    this.#message = msg;
  }

  constructor() {
    this.#decoratedMessage = "hello world";
    console.log(this.#decoratedMessage);
  }
}

new ClassWithPrivateAccessor();
// expected output: "✨hello world✨"
```

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # prod-PrivateIdentifier |
| ECMAScript Language Specification # prod-00OK517S |

브라우저 호환성
--------

### javascript.classes.private\_class\_fields

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### javascript.classes.private\_class\_fields\_in

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### javascript.classes.private\_class\_methods

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Public class fields (en-US)
* The Semantics of All JS Class Elements


constructor - JavaScript

constructor
===========

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2017.

* Learn more
* See full compatibility
* Report feedback
**`constructor`** 메서드는 클래스의 인스턴스 객체를 생성하고 초기화하는 특별한 메서드입니다.

시도해보기
-----

구문
--

```js
constructor() { ... }
constructor(argument0) { ... }
constructor(argument0, argument1) { ... }
constructor(argument0, argument1, ... , argumentN) { ... }
```

설명
--

`constructor`를 사용하면 다른 모든 메서드 호출보다 앞선 시점인, 인스턴스 객체를 초기화할 때 수행할 초기화 코드를 정의할 수 있습니다.

```js
class Person {
  constructor(name) {
    this.name = name;
  }

  introduce() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const otto = new Person("Otto");

otto.introduce();
```

클래스에 생성자를 정의하지 않으면 기본 생성자를 사용합니다. 아무것도 상속하지 않는 기본 클래스일 때의 기본 생성자는 빈 메서드입니다.

```js
constructor() {}
```

다른 클래스를 상속하는 경우, 기본 생성자는 자신의 매개변수를 부모 클래스의 생성자로 전달합니다.

```js
constructor(...args) {
  super(...args);
}
```

따라서 다음과 같은 코드를 작성할 수 있습니다.

```js
class ValidationError extends Error {
  printCustomerMessage() {
    return `Validation failed :-( (details: ${this.message})`;
  }
}

try {
  throw new ValidationError("Not a valid phone number");
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.name); // ValidationError가 아니라 Error!
    console.log(error.printCustomerMessage());
  } else {
    console.log("Unknown error", error);
    throw error;
  }
}
```

`ValidationError` 클래스는 아무런 초기화 동작도 필요하지 않으므로 생성자를 별도로 명시하지 않았으며, 대신 기본 생성자가 매개변수로 부모 `Error` 클래스의 초기화를 처리하고 있습니다.

그러나, 파생 클래스에 직접 생성자를 정의할 경우, 부모 클래스의 생성자를 호출하려면 직접 `super()`를 호출해야 합니다.

```js
class ValidationError extends Error {
  constructor(message) {
    super(message); // 부모 클래스의 생성자 호출
    this.name = "ValidationError";
    this.code = "42";
  }

  printCustomerMessage() {
    return `Validation failed :-( (details: ${this.message}, code: ${this.code})`;
  }
}

try {
  throw new ValidationError("Not a valid phone number");
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.name); // 이제 ValidationError!
    console.log(error.printCustomerMessage());
  } else {
    console.log("Unknown error", error);
    throw error;
  }
}
```

"`constructor`"라는 이름의 메서드는 하나의 클래스에 오직 하나만 존재할 수 있습니다. 두 개 이상의 `constructor` 메서드를 정의하면 `SyntaxError`가 발생합니다.

예제
--

### `constructor` 메서드 사용하기

```js
class Square extends Polygon {
  constructor(length) {
    // length로 다각형의 넓이와 높이를 정의하기 위해 부모 클래스의 생성자를 호출합니다.
    super(length, length);
    // 참고: 파생 클래스에서, this를 사용하기 전에는 반드시 super()를 먼저 호출해야 합니다.
    // 그렇지 않으면 ReferenceError가 발생합니다.
    this.name = "Square";
  }

  get area() {
    return this.height \* this.width;
  }

  set area(value) {
    this.height = value \*\* 0.5;
    this.width = value \*\* 0.5;
  }
}
```

### 다른 예제

아래 예제에서, `Square` 클래스의 프로토타입을 `Rectangle`의 프로토타입으로 바꾼 후에도, `Square`의 인스턴스를 생성할 때 부모 클래스인 `Polygon` 생성자를 호출하는 것을 확인할 수 있습니다.

```js
class Polygon {
  constructor() {
    this.name = "Polygon";
  }
}

class Square extends Polygon {
  constructor() {
    super();
  }
}

class Rectangle {}

Object.setPrototypeOf(Square.prototype, Rectangle.prototype);

console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false
console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true

let newInstance = new Square();
console.log(newInstance.name); //Polygon
```

명세
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-static-semantics-constructormethod |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* `super()`
* 클래스 선언문
* 클래스 표현식
* 클래스
* `Object.prototype.constructor`


Using promises - JavaScript

Using promises
==============

* « 이전 (en-US)
* 다음 »

`Promise`는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체입니다. 대부분 여러분은 이미 만들어진 promise를 사용했었기 때문에 이 가이드에서는 어떻게 promise를 만드는지 설명하기에 앞서 promise의 사용법에 대해 설명합니다.

기본적으로 promise는 함수에 콜백을 전달하는 대신에, 콜백을 첨부하는 방식의 객체입니다.

비동기로 음성 파일을 생성해주는 `createAudioFileAsync()`라는 함수가 있었다고 생각해보세요. 해당 함수는 음성 설정에 대한 정보를 받고, 두 가지 콜백 함수를 받습니다. 하나는 음성 파일이 성공적으로 생성되었을때 실행되는 콜백, 그리고 다른 하나는 에러가 발생했을때 실행되는 콜백입니다.

`createAudioFileAsync()`는 함수는 아래와 같이 사용됩니다.

```js
function successCallback(result) {
  console.log("Audio file ready at URL: " + result);
}

function failureCallback(error) {
  console.log("Error generating audio file: " + error);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
```

…모던한 함수들은 위와 같이 콜백들을 전달하지 않고 콜백을 붙여 사용할 수 있게 Promise를 반환해줍니다.

만약 `createAudioFileAsync()` 함수가 Promise를 반환하도록 수정한다면, 다음과 같이 간단하게 사용될 수 있습니다.

```js
createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
```

…조금 더 간단하게 써보자면:

```js
const promise = createAudioFileAsync(audioSettings);
promise.then(successCallback, failureCallback);
```

우리는 이와 같은 것을 *비동기 함수 호출*이라고 부릅니다. 이런 관례는 몇 가지 장점을 갖고 있습니다. 각각에 대해 한번 살펴보도록 합시다.

Guarantees
----------

콜백 함수를 전달해주는 고전적인 방식과는 달리, Promise는 아래와 같은 특징을 보장합니다.

* 콜백은 JavaScript Event Loop가 현재 실행중인 콜 스택을 완료하기 이전에는 절대 호출되지 않습니다.
* 비동기 작업이 성공하거나 실패한 뒤에 `then()` 을 이용하여 추가한 콜백의 경우에도 위와 같습니다.
* `then()`을 여러번 사용하여 여러개의 콜백을 추가 할 수 있습니다. 그리고 각각의 콜백은 주어진 순서대로 하나 하나 실행되게 됩니다.

Promise의 가장 뛰어난 장점 중의 하나는 **chaining**입니다.

Chaining
--------

보통 두 개 이상의 비동기 작업을 순차적으로 실행해야 하는 상황을 흔히 보게 됩니다. 순차적으로 각각의 작업이 이전 단계 비동기 작업이 성공하고 나서 그 결과값을 이용하여 다음 비동기 작업을 실행해야 하는 경우를 의미합니다. 우리는 이런 상황에서 **promise chain**을 이용하여 해결하기도 합니다.

`then()` 함수는 새로운 promise를 반환합니다. 처음에 만들었던 promise와는 다른 새로운 promise입니다.

```js
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
```

또는

```js
const promise2 = doSomething().then(successCallback, failureCallback);
```

두 번째 promise는 `doSomething()` 뿐만 아니라 `successCallback` or `failureCallback` 의 완료를 의미합니다. `successCallback` or `failureCallback` 또한 promise를 반환하는 비동기 함수일 수도 있습니다. 이 경우 `promise2`에 추가된 콜백은 `successCallback`또는 `failureCallback`에 의해 반환된 promise 뒤에 대기합니다.

기본적으로, 각각의 promise는 체인 안에서 서로 다른 비동기 단계의 완료를 나타냅니다.

예전에는 여러 비동기 작업을 연속적으로 수행하면 고전적인 '지옥의 콜백 피라미드'가 만들어 졌었습니다.

```js
doSomething(function (result) {
  doSomethingElse(
    result,
    function (newResult) {
      doThirdThing(
        newResult,
        function (finalResult) {
          console.log("Got the final result: " + finalResult);
        },
        failureCallback,
      );
    },
    failureCallback,
  );
}, failureCallback);
```

모던한 방식으로 접근한다면, 우리는 콜백 함수들을 반환된 promise에 promise chain을 형성하도록 추가할 수 있습니다:

```js
doSomething()
  .then(function (result) {
    return doSomethingElse(result);
  })
  .then(function (newResult) {
    return doThirdThing(newResult);
  })
  .then(function (finalResult) {
    console.log("Got the final result: " + finalResult);
  })
  .catch(failureCallback);
```

`then` 에 넘겨지는 인자는 선택적(optional)입니다. 그리고 `catch(failureCallback)` 는 `then(null, failureCallback)` 의 축약입니다. 이 표현식을 화살표 함수로 나타내면 다음과 같습니다.

```js
doSomething()
  .then((result) => doSomethingElse(result))
  .then((newResult) => doThirdThing(newResult))
  .then((finalResult) => {
    console.log(`Got the final result: ${finalResult}`);
  })
  .catch(failureCallback);
```

**중요:** 반환값이 반드시 있어야 합니다, 만약 없다면 콜백 함수가 이전의 promise의 결과를 받지 못합니다.
 (화살표 함수 () => x는 () => {return x;}와 같습니다.)

### Chaining after a catch

chain에서 작업이 실패한 후에도 새로운 작업을 수행하는 것이 가능하며 매우 유용합니다. (예 : `catch`) 다음 예를 읽으십시오:

```js
new Promise((resolve, reject) => {
  console.log("Initial");

  resolve();
})
  .then(() => {
    throw new Error("Something failed");

    console.log("Do this");
  })
  .catch(() => {
    console.log("Do that");
  })
  .then(() => {
    console.log("Do this, whatever happened before");
  });
```

그러면 다음 텍스트가 출력됩니다.
```

    Initial
    Do that
    Do this, whatever happened before
```

**참고:** "Do this" 텍스트가 출력되지 않은 것을 주의깊게 보십시오. "Something failed" 에러가 rejection을 발생시켰기 때문입니다.

Error propagation
-----------------

'콜백 지옥'에서 `failureCallback`이 3번 발생한 것을 기억할 것입니다. promise chain에서는 단 한 번만 발생하는 것과 비교되죠.

```js
doSomething()
  .then((result) => doSomethingElse(result))
  .then((newResult) => doThirdThing(newResult))
  .then((finalResult) => console.log(`Got the final result: ${finalResult}`))
  .catch(failureCallback);
```

기본적으로 promise chain은 예외가 발생하면 멈추고 chain의 아래에서 catch를 찾습니다. 이것은 동기 코드가 어떻게 동작하는지 모델링 한 것입니다.

```js
try {
  const result = syncDoSomething();
  const newResult = syncDoSomethingElse(result);
  const finalResult = syncDoThirdThing(newResult);
  console.log(`Got the final result: ${finalResult}`);
} catch (error) {
  failureCallback(error);
}
```

비동기 코드를 사용한 이러한 대칭성은 ECMAScript 2017에서 `async`/`await` 구문(Syntactic sugar) 에서 최고로 느낄 수 있습니다.

```js
async function foo() {
  try {
    const result = await doSomething();
    const newResult = await doSomethingElse(result);
    const finalResult = await doThirdThing(newResult);
    console.log(`Got the final result: ${finalResult}`);
  } catch (error) {
    failureCallback(error);
  }
}
```

이것은 promise를 기반으로 합니다. `doSomething()`은 이전 함수와 같습니다. 문법은 이곳에서 확인할 수 있습니다.

Promise는 모든 오류를 잡아내어, 예외 및 프로그래밍 오류가 발생해도 콜백 지옥의 근본적인 결함을 해결합니다. 이는 비동기 작업의 기능 구성에 필수적입니다.

Promise rejection events
------------------------

Promise가 reject될 때마다 두 가지 이벤트 중 하나가 전역 범위에 발생합니다.(일반적으로, 전역 범위는 `window`거나, 웹 워커에서 사용되는 경우, `Worker`, 혹은 워커 기반 인터페이스입니다.) 두 가지 이벤트는 다음과 같습니다.

`rejectionhandled` (en-US)

executor의 `reject`함수에 의해 reject가 처리 된 후 promise가 reject 될 때 발생합니다.

`unhandledrejection` (en-US)

promise가 reject되었지만 사용할 수 있는 reject 핸들러가 없을 때 발생합니다.

(`PromiseRejectionEvent` (en-US) 유형인) 두 이벤트에는 멤버 변수인 promise와 reason 속성이 있습니다. `promise` (en-US)는 reject된 promise를 가리키는 속성이고, `reason` (en-US)은 promise가 reject된 이유를 알려 주는 속성입니다.

이들을 이용해 프로미스에 대한 에러 처리를 대체(fallback)하는 것이 가능해지며, 또한 프로미스 관리시 발생하는 이슈들을 디버깅하는 데 도움을 얻을 수 있습니다. 이 핸들러들은 모든 맥락에서 전역적(global)이기 때문에, 모든 에러는 발생한 지점(source)에 상관없이 동일한 핸들러로 전달됩니다.

특히 유용한 사례 : Node.js로 코드를 작성할 때, 흔히 프로젝트에서 사용하는 모듈이 reject된 프로미스를 처리하지 않을 수 있습니다. 이런 경우 노드 실행 시 콘솔에 로그가 남습니다. 이를 수집에서 분석하고 직접 처리할 수도 있습니다. 아니면 그냥 콘솔 출력을 어지럽히는 것을 막기 위해 그럴 수도 있죠. 이런 식으로 `unhandledrejection` (en-US)(영어 (en-US)) 이벤트를 처리하는 핸들러를 추가하면 됩니다.

```js
window.addEventListener(
  "unhandledrejection",
  (event) => {
    /\* You might start here by adding code to examine the
 promise specified by event.promise and the reason in
 event.reason \*/

    event.preventDefault();
  },
  false,
);
```

이벤트의 `preventDefault()` 메서드를 호출하면 reject 된 프로미스가 처리되지 않았을 때 JavaScript 런타임이 기본 동작을 수행하지 않습니다. 이 기본 동작은 대개 콘솔에 오류를 기록하는 것이기 때문에, 이것은 확실히 NodeJS를 위한 것이죠.

제대로 하려면, 당연한 말이지만, 이 이벤트를 그냥 무시해버리기 전에 reject된 프로미스 코드에 실제로 버그가 없는지 확실히 검사해야 합니다.

오래된 콜백 API를 사용하여 Promise만들기
---------------------------

`Promise`는 생성자를 사용하여 처음부터 생성 될 수 있습니다. 이것은 오래된 API를 감쌀 때만 필요합니다.

이상적인 프로그래밍 세계에서는 모든 비동기 함수는 promise을 반환해야 하지만, 불행히도 일부 API는 여전히 success 및 / 또는 failure 콜백을 전달하는 방식일거라 생각합니다. 예를 들면 `setTimeout ()` 함수가 있습니다.

```js
setTimeout(() => saySomething("10 seconds passed"), 10000);
```

예전 스타일의 콜백과 Promise를 합치는 것은 문제가 있습니다. 함수 `saySomething()`이 실패하거나 프로그래밍 오류가 있으면 아무 것도 잡아 내지 않습니다. `setTimeout`의 문제점 입니다.

다행히도 우리는 `setTimeout`을 Promise로 감쌀 수 있습니다. 가장 좋은 방법은 가능한 가장 낮은 수준에서 문제가 되는 함수를 감싼 다음 다시는 직접 호출하지 않는 것입니다.

```js
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

wait(10000)
  .then(() => saySomething("10 seconds"))
  .catch(failureCallback);
```

기본적으로 promise constructor는 promise를 직접 해결하거나 reject 할 수 있는 실행자 함수를 사용합니다. `setTimeout()`은 함수에서 fail이 일어나거나 error가 발생하지 않기 때문에 이 경우 reject를 사용하지 않습니다.

Composition
-----------

`Promise.resolve ()`와 `Promise.reject ()`는 각각 이미 resolve되거나 reject 된 promise를 여러분이 직접 생성하기위한 바로 가기입니다. 가끔 유용하게 사용됩니다.

`Promise.all()`와 `Promise.race()`는 비동기 작업을 병렬로 실행하기위한 두 가지 구성 도구입니다.

우리는 병렬로 작업을 시작하고 다음과 같이 모두 완료될 때까지 기다릴 수 있습니다.

```js
Promise.all([func1(), func2(), func3()]).then(([result1, result2, result3]) => {
  /\* use result1, result2 and result3 \*/
});
```

고급진 JavaScript를 사용하여 순차적 구성이 가능합니다.

```js
[func1, func2, func3]
  .reduce((p, f) => p.then(f), Promise.resolve())
  .then((result3) => {
    /\* use result3 \*/
  });
```

기본적으로, 우리는 비동기 함수 배열을 다음과 같은 promise 체인으로 줄입니다. `Promise.resolve().then(func1).then(func2).then(func3);`

이것을 재사용 가능한 합성 함수로 만들 수 있는데, 이는 함수형 프로그래밍에서 일반적인 방식입니다.

```js
const applyAsync = (acc, val) => acc.then(val);
const composeAsync =
  (...funcs) =>
  (x) =>
    funcs.reduce(applyAsync, Promise.resolve(x));
```

`composeAsync()` 함수는 여러 함수를 인수로 받아들이고 composition 파이프 라인을 통해 전달되는 초기 값을 허용하는 새 함수를 반환합니다.

```js
const transformData = composeAsync(func1, func2, func3);
const result3 = transformData(data);
```

ECMAScript 2017에서는 async / await를 사용하여 순차적 구성을 보다 간단하게 수행할 수 있습니다.

```js
let result;
for (const f of [func1, func2, func3]) {
  result = await f(result);
}
/\* use last result (i.e. result3) \*/
```

Timing
------

놀라움(역자 주. 에러가 난다거나, 코드가 문제가 생긴다거나..했을때의 그 놀라움..)을 피하기 위해 `then()`에 전달된 함수는 already-resolved promise에 있는 경우에도 동기적으로 호출되지 않습니다.

```js
Promise.resolve().then(() => console.log(2));
console.log(1); // 1, 2
```

즉시 실행되는 대신 전달된 함수는 마이크로 태스크 대기열에 저장됩니다. 즉, 자바 스크립트 이벤트 루프의 현재 실행이 끝나고, 대기열도 비어있을 때에 제어권이 이벤트 루프로 반환되기 직전에 실행됩니다.

```js
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

wait().then(() => console.log(4));
Promise.resolve()
  .then(() => console.log(2))
  .then(() => console.log(3));
console.log(1); // 1, 2, 3, 4
```

Nesting
-------

간단한 promise 체인은 평평하게 유지하는 것이 가장 좋습니다. 중첩된 체인은 부주의한 구성의 결과일 수 있습니다. common mistakes를 참조하십시오.

중첩은 `catch` 문 범위를 제한하는 제어 구조입니다. 특히, 중첩된 `catch`는 중첩된 범위 외부의 체인에 있는 오류가 아닌 범위 및 그 이하의 오류만 잡습니다. 올바르게 사용하면 오류 복구 시 더 정확한 결과를 얻을 수 있습니다.

```js
doSomethingCritical()
  .then((result) =>
    doSomethingOptional(result)
      .then((optionalResult) => doSomethingExtraNice(optionalResult))
      .catch((e) => {}),
  ) // Ignore if optional stuff fails; proceed.
  .then(() => moreCriticalStuff())
  .catch((e) => console.log("Critical failure: " + e.message));
```

여기에 있는 선택적 단계는 들여 쓰기가 아닌 중첩되어 있지만 주위의 바깥 쪽 `(` 및 `)` 의 규칙적이지 않은 배치를 하지않도록 조심하세요.

inner neutralizing `catch` 문은 `doSomethingOptional()`및 `doSomethingExtraNice()`에서 발생한 오류를 catch 한 후에 코드가 `moreCriticalStuff()`로 다시 시작됩니다. 중요한 것은 `doSomethingCritical()`이 실패하면 해당 오류는 최종 (외부) `catch`에서만 포착된다는 것입니다.

Common mistakes
---------------

promise chains을 작성할 때 주의해야 할 몇 가지 일반적인 실수는 다음과 같습니다. 이러한 실수 중 몇 가지는 다음 예제에서 나타납니다.

```js
// Bad example! Spot 3 mistakes!

doSomething()
  .then(function (result) {
    doSomethingElse(result) // Forgot to return promise from inner chain + unnecessary nesting
      .then((newResult) => doThirdThing(newResult));
  })
  .then(() => doFourthThing());
// Forgot to terminate chain with a catch!
```

첫 번째 실수는 제대로 체인을 연결하지 않는 것입니다. 이것은 우리가 새로운 promise를 만들었지만 그것을 반환하는 것을 잊었을 때 일어납니다. 결과적으로 체인이 끊어지거나 오히려 두 개의 독립적인 체인이 경쟁하게 됩니다. 즉, `doFourthThing()`은 `doSomethingElse()` 또는 `doThirdThing()`이 완료될 때까지 기다리지 않고 우리가 의도하지 않았지만 이들과 병렬로 실행됩니다. 또한 별도의 체인은 별도의 오류 처리 기능을 가지고 있어서 잡기 어려운 오류가 발생합니다.

두 번째 실수는 불필요하게 중첩되어 첫 번째 실수를 가능하게 만드는 것입니다. 또한 중첩은 내부 오류 처리기의 범위를 제한하며, 의도하지 않은 에러가 캐치되지 않는 오류가 발생할 수 있습니다. 이 변형은 promise constructor anti-pattern입니다. 이 패턴은 이미 약속을 사용하는 코드를 감싸기 위해 promise 생성자의 중복 사용과 중첩을 결합합니다.

세 번째 실수는 `catch`로 체인을 종료하는 것을 잊는 것입니다. 종료되지 않은 promise 체인은 대부분의 브라우저에서 예상하지 못한 promise rejection을 초래합니다.

좋은 경험 법칙은 항상 promise 체인을 반환하거나 종결하는 것이며, 새로운 promise를 얻자마자 즉시 반환하여 복잡도를 낮추는 것입니다.

```js
doSomething()
  .then(function (result) {
    return doSomethingElse(result);
  })
  .then((newResult) => doThirdThing(newResult))
  .then(() => doFourthThing())
  .catch((error) => console.log(error));
```

`() => x` 은 `() => { return x; }`의 축약형임을 참고하세요.

이제 우리는 적절한 오류 처리 기능을 갖춘 결정성있는 단일 체인이 있습니다.

`async`/`await`를 사용하면 대부분의 문제를 해결할 수 있습니다. 이러한 문법의 가장 흔한 실수는 `await`키워드를 빼먹는 것입니다.

promise와 작업이 충돌할 때
------------------

예측할 수 없는 순서로 실행되는 promise 및 작업(예: 이벤트 또는 콜백)이 있는 상황에 직면하면 마이크로 태스크를 사용하여 상태를 확인하거나 promise가 조건부로 생성될 때 promise의 균형을 맞추는 것이 좋습니다.

마이크로 태스크가 이 문제를 해결하는 데 도움이 될 수 있다고 생각되면, queueMicrotask()를 사용해서 함수를 마이크로 태스크로 대기열에 넣는 방법을 마이크로 태스크 가이드에서 자세히 알아보십시오.

See also
--------

* `Promise.then()`
* `async`/`await`
* Promises/A+ specification
* Venkatraman.R - JS Promise (Part 1, Basics)
* Venkatraman.R - JS Promise (Part 2 - Using Q.js, When.js and RSVP.js)
* Venkatraman.R - Tools for Promises Unit Testing
* Nolan Lawson: We have a problem with promises — Common mistakes with promises
* « 이전 (en-US)
* 다음 »


정규 표현식 - JavaScript

정규 표현식
======

* « 이전
* 다음 »

정규 표현식, 또는 정규식은 문자열에서 특정 문자 조합을 찾기 위한 패턴입니다. JavaScript에서는 정규 표현식도 객체로서, `RegExp`의 `exec()` (en-US)와 `test()` 메서드를 사용할 수 있습니다. `String`의 `match()`, `matchAll()` (en-US), `replace()` (en-US), `replaceAll()`, `search()` (en-US), `split()` 메서드와도 함께 사용할 수 있습니다. 이 장에서는 JavaScript의 정규 표현식을 설명합니다.

정규 표현식 만들기
----------

정규 표현식은 두 가지 방법으로 만들 수 있습니다.

* 정규 표현식 리터럴. 다음과 같이 슬래시로 패턴을 감싸서 작성합니다.

```js
const re = /ab+c/;
```

정규 표현식 리터럴은 스크립트를 불러올 때 컴파일되므로, 바뀔 일이 없는 패턴의 경우 리터럴을 사용하면 성능이 향상될 수 있습니다.
* `RegExp` 객체의 생성자 호출.

```js
const re = new RegExp("ab+c");
```

생성자 함수를 사용하면 정규 표현식이 런타임에 컴파일됩니다. 바뀔 수 있는 패턴이나, 사용자 입력 등 외부 출처에서 가져오는 패턴의 경우 이렇게 사용하세요.
정규 표현식 패턴 작성하기
--------------

정규 표현식 패턴은 `/abc/`처럼 단순한 문자로 구성하거나, `/ab+c/`와 `/Chapter (\d+)\.\d*/`처럼 단순한 문자와 특수 문자의 조합으로 구성할 수도 있습니다. 특히 `(\d+)`에 나타난 괄호는 정규 표현식에서 기억 장치처럼 쓰여서, 괄호의 안쪽 패턴과 일치한 부분을 나중에 사용할 수 있도록 기억합니다. 그룹 사용하기 (en-US)에서 더 알아보세요.

### 단순 패턴 사용하기

단순 패턴은 문자열을 있는 그대로 탐색할 때 사용합니다. 예를 들어, `/abc/` 패턴은 문자열에서 정확한 순서로 `"abc"`라는 문자의 조합이 나타나는 부분과 일치합니다. 그러므로 이 패턴은 `"Hi, do you know your abc's?"`와 `"The latest airplane designs evolved from slabcraft."` 두 문자열에서 일치에 성공하고, 일치하는 부분은 `"abc"`일 것입니다. 반면 `"Grab crab"`에서는 일치하지 않는데, 이 문자열은 부분 문자열로 `"ab c"`를 포함하긴 하지만, 정확하게 `"abc"`를 포함하지는 않기 때문입니다.

### 특수 문자 사용하기

하나 이상의 "b"를 찾는다거나 공백 문자를 찾는 등 직접적인 일치 이상의 탐색이 필요할 땐 특수 문자를 사용합니다. 예컨대 "하나의 `"a"` 이후에 0개 이상의 `"b"`, 그 뒤의 `"c"`"와 일치해야 하면 `/ab*c/` 패턴을 사용할 수 있습니다. `"b"` 뒤의 `*`는 "이전 항목의 0번 이상 반복"을 의미합니다. 이 패턴을 문자열 `"cbbabbbbcdebc"`에 대해 사용하면, 일치하는 부분 문자열은 `"abbbbc"`일 것입니다.

아래의 문서들에선 각각의 범주에 속하는 다양한 특수 문자의 목록과 설명, 예제를 찾아볼 수 있습니다.

어서션 (en-US)

어서션에는 줄이나 단어의 시작과 끝을 나타내는 경계와, 일치가 가능한 방법을 나타내는 패턴(전방탐색, 후방탐색, 조건 표현식 등)이 포함됩니다.

문자 클래스 (en-US)

글자와 숫자처럼 다른 유형의 문자를 구분합니다.

그룹과 범위 (en-US)

표현 문자의 그룹과 범위를 나타냅니다.

수량자 (en-US)

일치할 문자나 표현이 반복되어야 할 횟수를 나타냅니다.

유니코드 속성 이스케이프 (en-US)

대/소문자, 수학 기호, 문장 부호처럼, 유니코드 문자 속성에 따라 문자를 구분합니다.

아래 표는 정규 표현식에서 사용하는 모든 특수문자의 목록입니다.

정규 표현식 특수문자| 문자 / 조합 | 문서 |
| --- | --- |
| `\`, `.`, `\cX`, `\d`,
 `\D`, `\f`, `\n`, `\r`,
 `\s`, `\S`, `\t`, `\v`,
 `\w`, `\W`, `\0`, `\xhh`,
 `\uhhhh`, `\uhhhhh`, `[\b]` | 문자 클래스 (en-US) |
| `^`, `$`, `x(?=y)`,
 `x(?!y)`, `(?<=y)x`,
 `(?<!y)x`, `\b`, `\B` | 어서션 (en-US) |
| `(x)`, `(?:x)`, `(?<Name>x)`,
 `x|y`, `[xyz]`, `[^xyz]`,
 `\*Number*` | 그룹과 범위 (en-US) |
| `*`, `+`, `?`,
 `x{*n*}`, `x{*n*,}`,
 `x{*n*,*m*}` | 수량자 (en-US) |
| `\p{*UnicodeProperty*}`,
 `\P{*UnicodeProperty*}` | 유니코드 속성 이스케이프 (en-US) |

**참고:** 위 문서의 일부만 발췌해 정리해놓은, 더 큰 치트 시트도 있습니다 (en-US).

### 이스케이핑

특수 문자를 있는 그대로 탐색(`"*"`을 직접 찾는 등)해야 하는 경우, 특수 문자 앞에 역슬래시(\)를 배치해서 이스케이프 해야 합니다. 예를 들어 `"a"` 뒤의 별표(`"*"`) 뒤의 `"b"`와 일치해야 하면 `/a\*b/`를 사용하면 됩니다. 역슬래시가 `"*"`를 "이스케이프"해서, 특수 문자가 아닌 문자 리터럴로 취급합니다.

마찬가지로, 슬래시(/)와 일치해야 하는 경우에도 이스케이프를 해야 합니다. 그냥 빗금을 사용하면 패턴이 끝나버립니다. 예를 들어 문자열 "/example/"과 그 뒤 하나 이상의 알파벳을 찾으려면 `/\/example\/[a-z]/`를 사용할 수 있습니다. 각각의 슬래시 앞에 놓인 역슬래시가 슬래시를 이스케이프합니다.

리터럴 역슬래시에 일치하려면 역슬래시를 이스케이프합니다. "A:\", "B:\", "C:\", ..., "Z:\"와 일치하는 패턴은 `/[A-Z]:\\/`입니다. 앞의 역슬래시가 뒤의 역슬래시를 이스케이프해서, 결과적으로 하나의 리터럴 역슬래시와 일치하게 됩니다.

`RegExp` 생성자와 문자열 리터럴을 사용하는 경우, 역슬래시가 문자열 리터럴의 이스케이프로도 작동한다는 것을 기억해야 합니다. 그러므로 정규 표현식의 역슬래시를 나타내려면 문자열 리터럴 수준의 이스케이프도 해줘야 합니다. 즉, 앞서 살펴본 `/a\*b/` 패턴을 생성하려면 `new RegExp("a\\*b")`가 되어야 합니다.

이스케이프 되지 않은 문자열을 이미 가지고 있을 땐 `String.replace` (en-US)를 활용해 이스케이프를 해줄 수 있습니다.

```js
function escapeRegExp(string) {
  return string.replace(/[.\*+?^${}()|[\]\\]/g, "\\$&"); // $&은 일치한 문자열 전체를 의미
}
```

정규 표현식 뒤의 "g"는 전체 문자열을 탐색해서 모든 일치를 반환하도록 지정하는 전역 탐색 플래그입니다. 플래그에 대해서는 아래의 플래그를 활용한 고급 탐색에서 확인할 수 있습니다.

"왜 `escapeRegExp()`가 JavaScript의 일부가 아닌가요?" 관련 제안은 있었으나 TC39가 거부했습니다.

### 괄호 사용하기

정규 표현식의 아무 부분이나 괄호로 감싸게 되면, 그 부분과 일치하는 부분 문자열을 기억하게 됩니다. 기억한 부분 문자열은 불러와서 다시 사용할 수 있습니다. 그룹과 범위 (en-US) 문서에서 자세히 알아보세요.

JavaScript에서 정규 표현식 사용하기
------------------------

정규 표현식은 `RegExp`의 메서드 `test()`와 `exec()` (en-US), `String`의 메서드 `match()`, `replace()` (en-US), `search()` (en-US), `split()`에서 사용할 수 있습니다.

| 메서드 | 설명 |
| --- | --- |
| `exec()` (en-US) | 문자열에서 일치하는 부분을 탐색합니다. 일치 정보를 나타내는 배열, 또는 일치가 없는 경우 `null`을 반환합니다. |
| `test()` | 문자열에 일치하는 부분이 있는지 확인합니다. `true` 또는 `false`를 반환합니다. |
| `match()` | 캡처 그룹을 포함해서 모든 일치를 담은 배열을 반환합니다. 일치가 없으면 `null`을 반환합니다. |
| `matchAll()` (en-US) | 캡처 그룹을 포함해서 모든 일치를 담은 반복기를 반환합니다. |
| `search()` (en-US) | 문자열에서 일치하는 부분을 탐색합니다. 일치하는 부분의 인덱스, 또는 일치가 없는 경우 `-1`을 반환합니다. |
| `replace()` (en-US) | 문자열에서 일치하는 부분을 탐색하고, 그 부분을 대체 문자열로 바꿉니다. |
| `replaceAll()` | 문자열에서 일치하는 부분을 모두 탐색하고, 모두 대체 문자열로 바꿉니다. |
| `split()` | 정규 표현식 또는 문자열 리터럴을 사용해서 문자열을 부분 문자열의 배열로 나눕니다. |

문자열 내부에 패턴과 일치하는 부분이 존재하는지만 알아내려면 `test()`나 `search()` 메서드를 사용하세요. 더 느리더라도 일치에 관한 추가 정보가 필요하면 `exec()`과 `match()` 메서드를 사용하세요. 일치하는 부분이 존재하면, `exec()`과 `match()`는 일치에 관한 데이터를 포함한 배열을 반환하고, 일치에 사용한 정규 표현식 객체의 속성을 업데이트합니다. 일치하지 못한 경우 `null`을 반환합니다. (`null`은 조건 평가 시 `false`와 같습니다)

아래의 예제에서는, 문자열에서 일치하는 부분을 찾기 위해 `exec()` 메서드를 사용합니다.

```js
const myRe = /d(b+)d/g;
const myArray = myRe.exec("cdbbdbsbz");
```

만약 정규 표현식 객체의 속성에 접근할 필요가 없으면 아래와 같이 짧게 쓸 수도 있습니다.

```js
const myArray = /d(b+)d/g.exec("cdbbdbsbz");
// 'cdbbdbsbz'.match(/d(b+)d/g); 와 비슷하지만,
// 'cdbbdbsbz'.match(/d(b+)d/g)의 반환 값은 [ 'dbbd' ]인 반면
// /d(b+)d/g.exec('cdbbdbsbz')의 반환 값은 [ 'dbbd', 'bb', index: 1, input: 'cdbbdbsbz' ]
```

(아래의 `exec()`과 전역 탐색 플래그 사용하기에서 동작 방식의 차이에 대해 더 알아보세요)

정규 표현식을 문자열에서 만들고 싶으면 아래처럼 사용할 수도 있습니다.

```js
const myRe = new RegExp("d(b+)d", "g");
const myArray = myRe.exec("cdbbdbsbz");
```

아래의 표는 위 스크립트에서 일치를 성공한 후, 반환하는 배열과 업데이트되는 정규 표현식 객체의 속성입니다.

정규 표현식 실행 결과| 객체 | 속성 또는 인덱스 | 설명 | 위 예제에서의 값 |
| --- | --- | --- | --- |
| `myArray` |  | 일치한 문자열 및 기억한 모든 부분 문자열. | `['dbbd', 'bb', index: 1, input: 'cdbbdbsbz']` |
| `index` | 일치한 부분이 주어진 문자열에서 위치한 인덱스. (0부터 시작) | `1` |
| `input` | 주어진 원본 문자열. | `'cdbbdbsbz'` |
| `[0]` | 마지막으로 일치한 부분 문자열. | `'dbbd'` |
| `myRe` | `lastIndex` |
 다음 일치를 시작할 인덱스. (g 옵션을 지정한 정규 표현식의 경우에만 설정됩니다.
 플래그를 활용한 고급 탐색을 참고하세요)
  | `5` |
| `source` | 패턴의 텍스트. 정규 표현식이 생성될 때 갱신됩니다. 실행 시점에는 갱신되지 않습니다. | `'d(b+)d'` |

위 예제의 두 번째 형태처럼, 정규 표현식 객체를 변수에 대입하지 않고도 사용할 수 있습니다. 하지만, 이러면 매 사용마다 정규 표현식 객체가 새로 생성되며, 업데이트되는 속성에 접근할 수 없습니다. 다음과 같은 코드를 생각해보겠습니다.

```js
const myRe = /d(b+)d/g;
const myArray = myRe.exec("cdbbdbsbz");
console.log(`lastIndex의 값은 ${myRe.lastIndex}`);

// "lastIndex의 값은 5"
```

그러나 위의 코드 대신 아래 코드를 사용하게 되면...

```js
const myArray = /d(b+)d/g.exec("cdbbdbsbz");
console.log(`lastIndex의 값은 ${/d(b+)d/g.lastIndex}`);

// "lastIndex의 값은 0"
```

두 개의 `/d(b+)d/g` 는 서로 다른 정규 표현식 객체이므로 별개의 `lastIndex` 속성을 갖습니다. 정규 표현식 객체의 속성에 접근해야 하면, 우선 변수에 할당하세요.

### 플래그를 활용한 고급 탐색

정규 표현식은 전역 탐색이나 대소문자 무시와 같은 특성을 지정하는 플래그를 가질 수 있습니다. 플래그는 단독으로 사용할 수도 있고, 순서에 상관 없이 한꺼번에 여럿을 지정할 수도 있습니다.

| 플래그 | 설명 | 대응하는 속성 |
| --- | --- | --- |
| `d` | 부분 문자열 일치에 대해 인덱스 생성. | `RegExp.prototype.hasIndices` (en-US) |
| `g` | 전역 탐색. | `RegExp.prototype.global` |
| `i` | 대소문자를 구분하지 않음. | `RegExp.prototype.ignoreCase` |
| `m` | 여러 줄에 걸쳐 탐색. | `RegExp.prototype.multiline` |
| `s` | 개행 문자가 `.`과 일치함. | `RegExp.prototype.dotAll` |
| `u` | "unicode", 패턴을 유니코드 코드 포인트의 시퀀스로 간주함. | `RegExp.prototype.unicode` (en-US) |
| `y` | "접착" 탐색, 대상 문자열의 현재 위치에서 탐색을 시작함. `sticky` (en-US)를 참고하세요. | `RegExp.prototype.sticky` (en-US) |

플래그는 다음과 같은 구문으로 정규 표현식에 지정할 수 있습니다.

```js
const re = /pattern/flags;
```

생성자를 사용할 경우 이렇게 지정합니다.

```js
const re = new RegExp("pattern", "flags");
```

플래그는 정규식과 완전히 합쳐지므로 나중에 추가하거나 제거할 수 없습니다.

예를 들어, `re = /\w+\s/g`는 한 개 이상의 글자와 그 뒤의 공백 하나를, 문자열 전체에 대해 탐색합니다.

```js
const re = /\w+\s/g;
const str = "fee fi fo fum";
const myArray = str.match(re);
console.log(myArray);

// ["fee ", "fi ", "fo "]
```

아래 코드는...

```js
const re = /\w+\s/g;
```

이렇게 생성자를 사용하도록 바꿀 수도 있습니다.

```js
const re = new RegExp("\\w+\\s", "g");
```

두 구문 모두 동일한 결과를 낳습니다.

`m` 플래그는 여러 줄에 걸친 입력 문자열을 여러 줄로 취급하게 합니다. 달리 말해, `m` 플래그를 지정할 경우, `^`와 `$`는 각각 전체 입력 문자열의 시작과 끝이 아니라, 각 줄의 시작과 끝에 대응하게 됩니다.

#### exec()과 전역 탐색 플래그 사용하기

`RegExp.prototype.exec()` (en-US) 메서드와 `g` 플래그를 사용하면, 일치한 부분 문자열들과 각각의 인덱스를 하나씩 순차적으로 반환합니다.

```js
const str = "fee fi fo fum";
const re = /\w+\s/g;

console.log(re.exec(str)); // ["fee ", index: 0, input: "fee fi fo fum"]
console.log(re.exec(str)); // ["fi ", index: 4, input: "fee fi fo fum"]
console.log(re.exec(str)); // ["fo ", index: 7, input: "fee fi fo fum"]
console.log(re.exec(str)); // null
```

반면, `String.prototype.match()` 메서드는 모든 일치를 한 번에 반환하지만, 각각의 인덱스는 포함하지 않습니다.

```js
console.log(str.match(re)); // ["fee ", "fi ", "fo "]
```

예제
--

**참고:** 다음 문서에서도 정규 표현식의 사용 예제를 볼 수 있습니다.

* `exec()` (en-US), `test()`, `match()`, `matchAll()` (en-US), `search()` (en-US), `replace()` (en-US), `split()` 메서드 참조
* 이 안내서의 하위 문서: 문자 클래스 (en-US), 어서션 (en-US), 그룹과 범위 (en-US), 수량자 (en-US), 유니코드 속성 이스케이프 (en-US)

### 정규 표현식 특수 문자를 사용한 입력 값 검증

아래 예제에서는 사용자가 전화번호를 입력해야 합니다. 사용자가 "확인" 버튼을 누르면 입력한 값을 스크립트로 검증합니다. 값이 유효하면, 즉 정규 표현식과 일치하는 문자의 시퀀스를 받았으면, 스크립트는 감사 메시지를 출력합니다. 값이 유효하지 않으면, 사용자에게 올바르지 않은 값임을 알려줍니다.

정규 표현식의 구조는 다음과 같습니다.

1. 데이터의 시작점(`^`)
2. 비캡처 그룹(`(?:)`)으로, 1의 뒤를 잇는 세 개의 숫자(`\d{3}`), 또는(`|`), 여는 괄호(`\(`)의 뒤를 잇는 세 개의 숫자(`\d{3}`)의 뒤를 잇는 닫는 괄호(`\)`)
3. 캡처 그룹(`()`)으로, 2의 뒤를 잇는 하나의 대시, 슬래시, 또는 마침표
4. 3의 뒤를 잇는 네 개의 숫자(`\d{4}`)
5. 4의 뒤를 잇는, 첫 번째 캡처 그룹에서 기억한 부분 문자열(`\1`)
6. 5의 뒤를 잇는 네 개의 숫자(`\d{4}`)
7. 데이터의 끝점(`$`)

#### HTML

```html
<p>
  전화번호를 입력 후 "확인" 버튼을 누르세요.
  <br />
  ###-####-####의 형식으로 입력하세요.
</p>
<form id="form">
  <input id="phone" />
  <button type="submit">확인</button>
</form>
<p id="output"></p>
```

#### JavaScript

```js
const form = document.querySelector("#form");
const input = document.querySelector("#phone");
const output = document.querySelector("#output");

const re = /^(?:\d{3}|\(\d{3}\))([-\/\.])\d{4}\1\d{4}$/;

function testInfo(phoneInput) {
  const ok = re.exec(phoneInput.value);

  if (!ok) {
    output.textContent = `형식에 맞지 않는 전화번호입니다. (${phoneInput.value})`;
  } else {
    output.textContent = `감사합니다. 전화번호는 ${ok[0]} 입니다.`;
  }
}

form.addEventListener("submit", (event) => {
  event.preventDefault();
  testInfo(input);
});
```

#### 결과

도구
--

RegExr

정규 표현식을 배우고, 만들고, 시험할 수 있는 온라인 도구입니다.

Regex tester

정규 표현식 생성기/디버거입니다.

Regex visualizer

시각적 정규 표현식 테스터입니다.

* « 이전
* 다음 »


문법과 자료형 - JavaScript

문법과 자료형
=======

* « 이전
* 다음 »

이 장은 JavaScript의 기본 문법과 변수 선언, 자료형 및 리터럴을 다룹니다.

기본
--

JavaScript는 문법의 대부분을 Java와 C, C++로부터 차용하고 있으며, Awk, Perl, Python의 영향도 받았습니다.

JavaScript는 **대소문자를 구별**하며 **유니코드** 문자셋을 이용합니다. 예를 들면, Früh(독일어로 "이른")을 변수명으로 사용할 수도 있습니다.

```js
var 갑을 = "병정";
var Früh = "foobar";
```

하지만 `Früh`는 `früh`와 다릅니다. 대소문자를 구분하기 때문입니다.

JavaScript에서는 명령을 명령문(statement)이라고 부르며, 세미콜론(;)으로 구분합니다.

명령문이 한 줄을 다 차지할 경우에는 세미콜론이 필요하지 않습니다. 그러나 한 줄에 두 개 이상의 명령문이 필요하다면 반드시 세미콜론으로 구분해야 합니다.

**참고:** ECMAScript는 세미콜론을 자동으로 삽입해 명령문을 끝내는 규칙(ASI (en-US))도 가지고 있습니다. (더 많은 정보는 JavaScript의 어휘 문법 (en-US)에 대한 자세한 참고서를 참고하세요.)

하지만, 세미콜론이 필요하지 않은 경우라도 항상 세미콜론으로 끝마치는 편이 버그 예방 차원에서 더 좋은 습관이라고 여겨집니다.

JavaScript의 스크립트 소스는 왼쪽에서 오른쪽으로 탐색하면서 토큰, 제어 문자, 줄바꿈 문자, 주석이나 공백으로 이루어진 입력 요소의 시퀀스로 변환됩니다. (스페이스, 탭, 줄바꿈 문자는 공백으로 간주됩니다.)

주석
--

**주석**의 구문은 C++ 및 다른 많은 언어와 똑같습니다.

```js
// 한 줄 주석

/\* 이건 더 긴,
 \* 여러 줄 주석입니다.
 \*/

/\* 그러나, /\* 중첩된 주석은 쓸 수 없습니다 \*/ SyntaxError \*/
```

주석은 공백처럼 행동하며 스크립트 실행 시 버려집니다.

**참고:** 몇몇 JavaScript 파일의 시작부에 `#!/usr/bin/env node`와 같은 형태의 주석 문법이 쓰이는 것을 볼 수 있습니다.

이것은 **해시뱅 주석** 구문이라고 하는데, 이 특별한 주석은 스크립트를 실행할 때 쓸 특별한 JavaScript 인터프리터의 경로를 설정할 때 쓰입니다. 해시뱅 주석 (en-US)을 참고하여 자세한 내용을 확인할 수 있습니다.

선언
--

JavaScript의 선언에는 3가지 방법이 있습니다.

`var`

변수를 선언. 추가로 동시에 값을 초기화.

`let`

블록 스코프 지역 변수를 선언. 추가로 동시에 값을 초기화.

`const`

블록 스코프 읽기 전용 상수를 선언.

### 변수

애플리케이션에서 값에 상징적인 이름으로 변수를 사용합니다. 변수명은 식별자(identifiers)라고 불리며 특정 규칙을 따릅니다.

JavaScript 식별자는 문자, 밑줄 (`_`) 혹은 달러 기호 (`$`)로 시작해야 하는 반면 이후는 숫자 (`0`–`9`) 일 수도 있습니다.

JavaScript가 대소문자를 구분하기에, 문자는 "`A`"부터 "`Z`" (대문자)와 "`a`"부터 "`z`" (소문자)까지 모두 포함합니다.

ISO 8859-1 혹은 Unicode 문자(가령 `å` 나 `ü`)도 식별자에 사용할 수 있습니다. (좀 더 상세한 내용은 이 블로그 글을 참고.) 또한 Unicode escape sequences (en-US)도 식별자에 문자로 사용할 수 있습니다.

적절한 이름으로는 `Number_hits`, `temp99`, `$credit` 및 `_name` 등 입니다.

### 변수 선언

변수 선언은 아래 3가지 방법으로 가능합니다.

* `var x = 42`와 같이 `var` 키워드로 변수를 선언할 수 있습니다. 이 구문은 실행 맥락에 따라 **지역 및 전역 변수**를 선언하는데 모두 사용될 수 있습니다.
* `let y = 13`와 같이 `const` 혹은 `let` 키워드로 변수를 선언할 수 있습니다. 이 구문은 블록 스코프 지역 변수를 선언하는데 사용될 수 있습니다. 아래 변수 스코프를 참고하세요.

구조 분해 할당 구문을 사용하여 객체 리터럴에서 값을 풀기 위해 변수를 선언할 수 있습니다. 예를 들면, `let { bar } = foo`. 이 구문은 `bar`라는 이름의 변수를 생성하고 `foo` 객체에 있는 동일한 이름의 키에 해당하는 값을 변수에 할당합니다.

간단히 변수에 값을 할당 할 수도 있습니다. 예를 들어, `x = 42` 와 같은 구문은 **선언되지 않은 전역변수**를 만듭니다. 뿐만 아니라, JavaScript의 엄격한 경고를 만들어냅니다. 선언되지 않은 전역변수는 의도되지 않은 동작을 만들어내고는 합니다. 따라서 선언되지 않은 전역변수를 사용하면 안됩니다.

### 변수 할당

지정된 초기 값 없이 `var` 혹은 `let` 문을 사용해서 선언된 변수는 `undefined` 값을 갖습니다.

선언되지 않은 변수에 접근을 시도하는 경우 `ReferenceError` 예외가 발생합니다.

```js
var a;
console.log("a 값은 " + a); // a 값은 undefined

console.log("b 값은 " + b); // b 값은 undefined
var b;
// 이것은 아래의 '변수 호이스팅'을 읽기 전에는 혼란스러울 수 있음

console.log("c 값은 " + c); // Uncaught ReferenceError: c is not defined

let x;
console.log("x 값은 " + x); // x 값은 undefined

console.log("y 값은 " + y); // Uncaught ReferenceError: y is not defined
let y;
```

`undefined`를 사용하여 변수 값이 있는지 확인할 수 있습니다. 아래 코드에서, `input` 변수는 값이 할당되지 않았고 `if`문은 `true`로 평가합니다.

```js
var input;
if (input === undefined) {
  doThis();
} else {
  doThat();
}
```

`undefined` 값은 불리언 맥락(context)에서 사용될 때 `false`로 동작합니다. 예를 들어, 아래 코드는 `myArray` 요소가 `undefined`이므로 `myFunction` 함수를 실행합니다.

```js
var myArray = [];
if (!myArray[0]) myFunction();
```

`undefined` 값은 수치 맥락에서 사용될 때 `NaN`으로 변환됩니다.

```js
var a;
a + 2; // NaN으로 평가
```

`null` 값을 평가할 때, 수치 맥락에서는 `0`으로, 불리언 맥락에서는 `false`로 동작합니다. 예를 들면,

```js
var n = null;
console.log(n \* 32); // 콘솔에 0 으로 로그가 남음
```

### 변수 스코프

어떤 함수의 바깥에 변수를 선언하면, 현재 문서의 다른 코드에 해당 변수를 사용할 수 있기에 전역 변수라고 합니다. 만약 함수 내부에 변수를 선언하면, 오직 그 함수 내에서만 사용할 수 있기에 지역 변수라고 부릅니다.

ECMAScript 2015 이전의 JavaScript는 블록 문 스코프가 없습니다. 그래서 오히려, 블록 내에 선언된 변수는 그 블록 내에 존재하는 함수(혹은 전역 스코프)에 지역적입니다.

예를 들어서 아래의 코드는 `5`라는 로그가 남는데. `x`의 스코프가 전역 맥락 (혹은 코드가 함수의 일부분이라면 함수 맥락)이기 때문입니다. `x`의 스코프는 `if`문 블록에 제한되지 않습니다.

```js
if (true) {
  var x = 5;
}
console.log(x); // 5
```

이 동작은 `let` 선언을 사용하면 바뀝니다 (ECMAScript 2015에 도입됨).

```js
if (true) {
  let y = 5;
}
console.log(y); // ReferenceError: y is not defined
```

### 변수 호이스팅

또 다른 JavaScript 변수의 특이한 점은 예외를 받지 않고도, 나중에 선언된 변수를 참조할 수 있다는 것입니다.

이 개념은 **호이스팅**(hoisting)으로 알려져 있습니다. 즉 JavaScript 변수가 어떤 의미에서 함수나 문의 최상단으로 "올려지는" (혹은 "끌어올려지는") 것을 말합니다. 하지만, 끌어올려진 변수는 `undefined` 값을 반환합니다. 그래서 심지어 이 변수를 사용 혹은 참조한 후에 선언 및 초기화하더라도, 여전히 `undefined`를 반환합니다.

```js
/\*\*
 \* Example 1
 \*/
console.log(x === undefined); // true
var x = 3;

/\*\*
 \* Example 2
 \*/
// undefined 값을 반환함.
var myvar = "my value";

(function () {
  console.log(myvar); // undefined
  var myvar = "local value";
})();
```

위 예제는 아래 예제와 동일하게 볼 수 있습니다.

```js
/\*\*
 \* Example 1
 \*/
var x;
console.log(x === undefined); // true
x = 3;

/\*\*
 \* Example 2
 \*/
var myvar = "my value";

(function () {
  var myvar;
  console.log(myvar); // undefined
  myvar = "local value";
})();
```

호이스팅 때문에, 함수 내의 모든 `var` 문은 가능한 함수 상단 근처에 두는 것이 좋습니다. 이 방법은 코드를 더욱 명확하게 만들어줍니다.

ECMAScript 2015의 `let`과 `const`는 변수를 블록의 상단으로 **끌어올리지만 초기화하지 않습니다.** 변수가 선언되기 전에 블록 안에서 변수를 참조하게 되면 `ReferenceError`를 발생시키게 되는데, 변수는 블록 시작부터 선언이 처리될 때까지 "temporal dead zone"에 위치하게 되기 때문입니다.

```js
console.log(x); // ReferenceError
let x = 3;
```

### 함수 호이스팅

함수에서는 함수 선언으로는 호이스팅되지만 함수 표현식으로는 호이스팅 되지 않습니다.

```js
/\* 함수 선언 \*/

foo(); // "bar"

function foo() {
  console.log("bar");
}

/\* 함수 표현식 \*/

baz(); // TypeError: baz is not a function

var baz = function () {
  console.log("bar2");
};
```

### 전역 변수

전역 변수는 사실 전역 객체의 속성(property)입니다.

웹 페이지에서 전역 객체는 `window` 이므로, `windows.variable` 구문을 통해 전역 변수를 설정하고 접근할 수 있습니다.

그 결과, `window` 혹은 `frame`의 이름을 지정하여 한 window 혹은 frame에서 다른 window 혹은 frame에 선언된 전역 변수에 접근할 수 있습니다. 예를 들어, `phoneNumber` 라는 변수가 문서에 선언된 경우, `iframe`에서 `parent.phoneNumber`로 이 변수를 참조할 수 있습니다.

### 상수

`const` 키워드로 읽기 전용 상수를 만들 수 있습니다.

상수 식별자의 구문은 변수 식별자와 같습니다. 문자, 밑줄이나 달러 기호 (`$`) 로 시작해야 하고 문자, 숫자나 밑줄을 포함할 수 있습니다.

```js
const PI = 3.14;
```

상수는 스크립트가 실행 중인 동안 대입을 통해 값을 바꾸거나 재선언될 수 없습니다. 값으로 초기화해야 합니다.

상수에 대한 스코프 규칙은 `let` 블록 스코프 변수와 동일합니다. 만약 `const` 키워드가 생략된 경우에는, 식별자는 변수를 나타내는 것으로 간주됩니다.

상수는 같은 스코프에 있는 함수나 변수와 동일한 이름으로 선언할 수 없습니다. 예를 들어,

```js
// 오류가 발생합니다
function f() {}
const f = 5;

// 역시 오류가 발생합니다
function f() {
  const g = 5;
  var g;

  //statements
}
```

그러나, 상수에 할당된 객체의 속성은 보호되지 않아서 다음의 문은 문제없이 실행됩니다.

```js
const MY\_OBJECT = { key: "value" };
MY\_OBJECT.key = "otherValue";
```

또한, 배열의 내용도 보호되지 않아서 다음의 문도 문제없이 실행됩니다.

```js
const MY\_ARRAY = ["HTML", "CSS"];
MY\_ARRAY.push("JAVASCRIPT");
console.log(MY\_ARRAY); //logs ['HTML','CSS','JAVASCRIPT'];
```

데이터 구조 및 형
----------

### 데이터 형

최신 ECMAScript 표준은 8가지 데이터 형을 정의합니다.

* 7가지 원시 데이터 형
    1. Boolean. `true`와 `false`
    2. null. null 값을 나타내는 특별한 키워드. (JavaScript는 대소문자를 구분하므로, `null`은 `Null`, `NULL` 혹은 다른 변형과도 다릅니다.)
    3. undefined. 값이 정의되어 있지 않은 최상위 속성.
    4. Number. 정수 또는 실수형 숫자. 예: `42` 혹은 `3.14159`.
    5. BigInt. 임의 정밀도의 정수. 예: `9007199254740992n`.
    6. String. 문자열. 예:"안녕"
    7. Symbol. (ECMAScript 2015에 도입) 인스턴스가 고유하고 불변인 데이터 형.
* 그리고 Object

이러한 데이터 형이 비교적 많지 않지만, 애플리케이션에 유용한 기능을 수행할 수 있습니다. `객체`와 `함수`는 언어의 다른 기본 요소입니다. 객체는 값을 위한 컨테이너, 함수는 애플리케이션이 수행할 수 있는 절차(procedure)로 생각할 수 있습니다.

### 자료형 변환

JavaScript는 동적 형지정(정형) 언어입니다. 이는 변수를 선언할 때 데이터 형을 지정할 필요가 없음을 의미합니다. 또한 데이터 형이 스크립트 실행 도중 필요에 의해 자동으로 변환됨을 뜻합니다.

그래서, 예를 들어, 다음과 같이 변수를 정의할 수 있습니다.

```js
var answer = 42;
```

그리고 나중에, 동일한 변수에 문자열 값을 할당할 수도 있습니다. 아래와 같이,

```js
answer = "Thanks for all the fish...";
```

JavaScript는 동적 형지정 언어이므로, 이 할당은 오류 메시지가 발생하지 않습니다.

### 숫자와 '+' 연산자

숫자와 문자열 값 사이에 `+` 연산자를 포함한 식에서, JavaScript는 숫자 값을 문자열로 변환합니다. 예를 들어, 아래와 같은 문이 있습니다.

```js
x = "The answer is " + 42; // "The answer is 42"
y = 42 + " is the answer"; // "42 is the answer"
```

다른 연산자를 포함한 식의 경우, JavaScript는 숫자 값을 문자열로 변환하지 않습니다. 예를 들면,

```js
"37" - 7; // 30
"37" + 7; // "377"
```

### 문자열을 숫자로 변환하기

숫자를 나타내는 값이 문자열로 메모리에 있는 경우, 변환을 위한 메서드가 있습니다.

* `parseInt()`
* `parseFloat()`

`parseInt`는 오직 정수만 반환하므로, 소수에서는 사용성이 떨어집니다.

**참고:** 게다가 `parseInt`를 잘 사용하기 위해서는 항상 진법(Radix) 매개변수를 포함해야 합니다. 진법 매개변수는 변환에 사용될 진법을 지정하는데 사용됩니다.

```js
parseInt("101", 2); // 5
```

문자열을 숫자로 변환하는 대안은 `+` (단항 더하기) 연산자입니다.

```js
'1.1' + '1.1'; // '1.11.1'
(+'1.1') + (+'1.1'); // 2.2
// 참고: 괄호는 명확성을 위해 추가, 필요한 것은 아닙니다.
```

리터럴
---

JavaScript에서 값을 나타내기 위해 리터럴을 사용합니다. 이는 말 그대로 스크립트에 부여한 고정 값으로, 변수가 아닙니다. 이 구획에서는 다음과 같은 형태의 리터럴을 설명합니다.

* 배열 리터럴
* 불리언 리터럴
* 부동 소수점 리터럴
* 숫자 리터럴
* 객체 리터럴
* 정규식 리터럴
* 문자열 리터럴
### 배열 리터럴

배열 리터럴은 0개 이상의 식(expression) 목록입니다. 각 식은 배열 요소를 나타내고 대괄호(`[]`)로 묶입니다. 배열 리터럴을 사용하여 배열을 만들 때, 그 요소로 지정된 값으로 초기화되고, 그 `length`는 지정된 인수의 갯수로 설정됩니다.

아래 예제는 요소가 3개로 `length`가 3인 `coffees` 배열을 만듭니다.

```js
let coffees = ["French Roast", "Colombian", "Kona"];
```

**참고:** 배열 리터럴은 일종의 객체 초기자(initializer) 입니다. 객체 초기자 사용하기 참고.

배열이 최상단 스크립트에서 리터럴을 사용하여 만들어진 경우, JavaScript는 배열 리터럴을 포함한 식을 평가할 때마다 배열로 해석합니다. 게다가, 함수에서 사용되는 리터럴은 함수가 호출될 때마다 생성됩니다.

**참고:** 배열 리터럴은 `Array` 객체입니다. `Array` 객체에 대한 자세한 내용은 `Array`와 Indexed collections 참고.

#### 배열 리터럴의 추가 쉼표

배열 리터럴에서 모든 요소를 지정할 필요는 없습니다. 만약 잇달아 두 개의 쉼표를 두면, 배열은 지정되지 않은 요소를 `undefined`로 채웁니다. 다음 예제는 `fish` 배열을 만듭니다.

```js
let fish = ["Lion", , "Angel"];
```

이 배열은 값이 있는 두 요소와 빈 요소 하나를 가집니다.

* `fish[0]`은 "Lion"
* `fish[1]`은 `undefined`
* `fish[2]`는 "Angel"

만약 요소 목록을 후행(trailing) 쉼표로 끝낸다면, 그 쉼표는 무시됩니다.

다음 예제에서, 배열의 `length`는 3입니다. `myList[3]`은 없습니다. 목록의 다른 모든 쉼표는 새로운 요소를 나타냅니다.

**참고:** 후행 쉼표는 구버전 브라우저에서 오류를 유발할 수 있으므로 제거하는게 최선입니다.

```js
var myList = ["home", , "school", ];
```

아래 예제에서, 배열의 `length`는 4이며, `myList[0]`과 `myList[2]`는 값이 빠졌습니다.

```js
var myList = [, "home", , "school"];
```

아래 예제에서, 배열의 `length`는 4이며, `myList[1]`과 `myList[3]`은 값이 빠졌습니다. **마지막 쉼표는 무시됩니다.**

```js
var myList = ["home", , "school", ,];
```

추가 쉼표의 동작을 이해하는 것은 JavaScript를 언어로서 이해하는데 중요합니다.

하지만 코드를 작성할 때는 빠진 요소의 값을 명시적으로 `undefined`로 선언하는 것이 코드의 명확성과 유지보수성을 높입니다.

### 불리언 리터럴

불리언 형은 `true`와 `false`의 리터럴 값을 가집니다.

**참고:** 원시 불리언 값 `true` 및 `false`와 `Boolean` 객체의 true 및 false 값을 혼동하지 마세요.

불리언 객체는 원시 불린 데이터 형을 감싸는 래퍼(wrapper)입니다. 더 많은 정보는 `Boolean`을 참고하세요.

### 숫자 리터럴

JavaScript 숫자 리터럴은 다른 진법의 정수 리터럴과 10진수의 부동 소수점 리터럴이 포함됩니다.

언어 명세서에 따르면 숫자 리터럴에 부호가 없어야 합니다. 그럼에도 불구하고, `-123.4` 와 같은 코드 괜찮습니다. 숫자 리터럴 `123.4` 에 단항 연산자 `-` 가 붙은 것으로 해석됩니다.

#### 정수 리터럴

정수와 `BigInt` 리터럴은 10진수, 16진수, 8진수 및 2진수로 표현될 수 있습니다.

* 10진수 정수 리터럴은 `0`으로 시작(leading zero)하지 않는 숫자열로 이루어집니다.
* 정수 리터럴에서 `0`으로 시작하거나 `0o`(혹은 `0O`)으로 시작하는 숫자열은 8진수임을 나타냅니다. 8진수 정수 리터럴은 오직 숫자 `0`-`7`만 포함할 수 있습니다.
* `0x`(나 `0X`)로 시작하는 숫자열은 16진수 정수 리터럴 임을 나타냅니다. 16진수 정수는 숫자 (`0`-`9`) 및 문자 `a`-`f`, `A`-`F`를 포함할 수 있습니다. (문자의 대소문자는 그 값을 변경하지 않습니다. 그러므로 `0xa` = `0xA` = `10` 그리고 `0xf` = `0xF` = `15` 입니다.)
* `0b` (나 `0B`)로 시작하는 숫자열은 2진수 정수 리터럴 임을 나타냅니다. 2진수 정수 리터럴은 오직 숫자 `0`과 `1`만 포함할 수 있습니다.
* `n`으로 끝나는 숫자열은 `BigInt` 리터럴 임을 나타냅니다. 정수 리터럴은 위의 어떤 진수든 사용할 수 있습니다. `0123n`과 같은 `0`으로 시작하는 8진수 구문은 허용되지 않으나, `0o123n`은 허용됩니다.

다음은 정수 리터럴 예제입니다.
```

0, 117, 123456789123456789n             (10진수)
015, 0001, 0o777777777777n              (8진수)
0x1123, 0x00111, 0x123456789ABCDEFn     (16진수)
0b11, 0b0011, 0b11101001010101010101n   (2진수)
```

더 많은 정보는 어휘 문법의 숫자 리터럴 (en-US)를 참고하세요.

#### 부동 소수점 리터럴

부동 소수점 리터럴은 아래와 같은 부분으로 이루어집니다.

* 부호없는 10진 정수,
* 소수점 ("`.`"),
* 소수 (또 다른 10진수),
* 지수.

지수부는 "`e`"나 "`E`" 다음에 오며 부호("`+`"나 "`-`")가 달릴 수 있는 정수입니다. 부동 소수점 리터럴은 적어도 숫자 하나와 소수점 혹은 "`e`"(나 "`E`")가 있어야 합니다.

더 간결하게 설명하면, 구문은 다음과 같습니다.
```

[digits].[digits][(E|e)[(+|-)]digits]
```

예를 들면,
```

3.1415926
.123456789
3.1E+12
.1e-23
```

### 객체 리터럴

객체 리터럴은 중괄호(`{}`)로 묶인 0개 이상인 객체의 속성명과 관련 값 쌍 목록입니다.

>
> **주의:** 문(statement)의 시작에 객체 리터럴을 사용해서는 안됩니다. 이는 `{`가 블록의 시작으로 해석되기 때문에 오류를 유발하거나 의도한 대로 동작하지 않습니다.
>
>
>

아래는 객체 리터럴의 예제입니다. `car` 객체의 첫째 요소는 `myCar` 속성을 정의하고 문자열 `"Saturn"`을 할당합니다. 반면 둘째 요소인 `getCar` 속성은 함수 `(carTypes("Honda"))`을 호출한 결과가 즉시 할당됩니다. 셋째 요소 `special` 속성은 기존 변수 (`sales`)를 사용합니다.

```js
var sales = "Toyota";

function carTypes(name) {
  if (name === "Honda") {
    return name;
  } else {
    return "Sorry, we don't sell " + name + ".";
  }
}

var car = { myCar: "Saturn", getCar: carTypes("Honda"), special: sales };

console.log(car.myCar); // Saturn
console.log(car.getCar); // Honda
console.log(car.special); // Toyota
```

게다가, 속성명으로 숫자나 문자열 리터럴을 사용하거나 또다른 객체 리터럴 내부에 객체를 중첩할 수도 있습니다. 아래 예제는 이 옵션을 사용합니다.

```js
var car = { manyCars: { a: "Saab", b: "Jeep" }, 7: "Mazda" };

console.log(car.manyCars.b); // Jeep
console.log(car[7]); // Mazda
```

객체 속성명은 빈 문자열 포함 어떤 문자열도 될 수 있습니다. 속성명이 유효한 JavaScript 식별자나 숫자가 아닌 경우, 따옴표로 묶여야 합니다.

또한 유효한 식별자가 아닌 속성명은 점(`.`) 속성으로 접근할 수 없습니다. 대신 배열 같은 표기법("`[]`")으로 접근하고 값을 설정할 수 있습니다.

```js
var unusualPropertyNames = {
  '': 'An empty string',
  '!': 'Bang!'
}
console.log(unusualPropertyNames.'');   // SyntaxError: Unexpected string
console.log(unusualPropertyNames['']);  // An empty string
console.log(unusualPropertyNames.!);    // SyntaxError: Unexpected token !
console.log(unusualPropertyNames['!']); // Bang!
```

#### 향상된 객체 리터럴

ES2015에서, 객체 리터럴은 구성에서 프로토타입 설정, `foo: foo` 할당을 위한 단축 표기, 메서드 정의, `super` 클래스 호출 및 식으로 동적인 속성명 계산을 지원하기 위해 확장됐습니다.

그에 따라 객체 리터럴 및 클래스 선언이 함께 더 가까워지고, 객체 기반 설계는 같은 일부 편의기능으로 득을 볼 수 있습니다.

```js
var obj = {
  // \_\_proto\_\_
  \_\_proto\_\_: theProtoObj,
  // ‘handler: handler’의 단축 표기
  handler,
  // Methods
  toString() {
    // Super calls
    return "d " + super.toString();
  },
  // Computed (dynamic) property names
  ["prop\_" + (() => 42)()]: 42,
};
```

### 정규식 리터럴

정규식 리터럴은 (정규식 상세) 슬래시 사이에 감싸인 패턴입니다. 다음은 정규식 리터럴 예제입니다.

```js
var re = /ab+c/;
```

### 문자열 리터럴

문자열 리터럴은 큰 따옴표(`"`) 혹은 작은 따옴표(`'`)로 묶인 0개 이상의 문자입니다. 문자열은 같은 형 따옴표 (즉 큰 따옴표 쌍이나 작은 따옴표 쌍) 로 구분되어야 합니다.

아래는 문자열 리터럴의 예제입니다.

```js
'foo';
"bar";
'1234';
'one line \n another line';
"John's cat";
```

꼭 `String` 객체를 사용할 필요가 없는 경우 문자열 리터럴을 사용해야 합니다. `String` 객체에 대해 자세한 사항은 `String`을 참고하세요.

문자열 리터럴 값은 `String` 객체의 모든 메서드를 호출할 수 있습니다. JavaScript는 자동으로 문자열 리터럴을 임시 문자열 객체로 변환, 메서드를 호출하고 나서 임시 문자열 객체를 폐기합니다. 또한 문자열 리터럴에서도 `String.length` 속성을 사용할 수 있습니다.

```js
// 공백을 포함한 문자열 내 심볼 갯수가 출력됩니다.
console.log("John's cat".length); // 여기서는, 10.
```

템플릿 리터럴도 사용할 수 있습니다. 템플릿 리터럴은 큰 따옴표나 작은 따옴표 대신 백틱 (```) (억음 부호) 으로 문자를 감쌉니다.

템플릿 리터럴은 문자열 구성을 위한 달콤한 구문을 제공합니다. (이는 Perl, Python 등에 있는 문자열 삽입(interpolation) 기능과 비슷합니다.)

```js
// 기본적인 문자열 리터럴 생성
`In JavaScript '\n' is a line-feed.`;

// 여러 줄 문자열
`In JavaScript, template strings can run
 over multiple lines, but double and single
 quoted strings cannot.`;

// 문자열 삽입
var name = "Bob",
  time = "today";
`Hello ${name}, how are you ${time}?`;
```

Tagged templates은 구문 분석을 위한 "태그" 함수에 대한 호출과 함께 템플릿 리터럴을 지정하기 위한 간결한 구문입니다. 템플릿 태그 함수의 이름은 아래 예제에서 `myTag` 가 템플릿 태그 함수 이름인 것과 같이 템플릿 리터럴 앞에 옵니다.

```js
let myTag = (str, name, age) => `${str[0]}${name}${str[1]}${age}${str[2]}`;
let [name, age] = ["Mika", 28];
myTag`Participant "${name}" is ${age} years old.`;
// Participant "Mika" is 28 years old.
```

#### 문자열에서 특수 문자 사용

보통 문자에 더해서, 문자열에 아래 예제와 같이 특수 문자도 포함할 수 있습니다.

```js
"one line \n another line";
```

다음 표는 JavaScript 문자열에 사용할 수 있는 특수 문자 목록입니다.

표: JavaScript 특수 문자| 문자 | 뜻 |
| --- | --- |
| `\0` | Null Byte |
| `\b` | Backspace |
| `\f` | Form feed |
| `\n` | New line |
| `\r` | Carriage return |
| `\t` | Tab |
| `\v` | Vertical tab |
| `\'` | Apostrophe 혹은 작은 따옴표 |
| `\"` | 큰 따옴표 |
| `\\` | 백슬래시 |
| `\*XXX*` | Latin-1 인코딩 문자는 `0` - `377` 사이 8진수 3자리 *XXX*까지 지정될 수 있습니다.예를 들어, `\251`은 copyright 심볼을 표현하는 8진수 시퀀스입니다. |
| `\x*XX*` | Latin-1 인코딩 문자는 `00` - `FF` 사이의 16진수 2자리 *XX*로 지정될 수 있습니다.예를 들어, `\xA9`는 copyright 심볼을 표현하는 16진수 시퀀스입니다. |
| `\u*XXXX*` | 유니코드 문자는 16진수 4자리 *XXXX*로 지정될 수 있습니다.예를 들어, `\u00A9`는 copyright 심볼을 표현하는 유니코드 시퀀스입니다. Unicode escape sequences (en-US)를 참고하세요. |
| `\u*{XXXXX}*` | 유니코드 코드 포인트 이스케이프.예를 들어, `\u{2F804}`는 간단한 유니코드 이스케이프 `\uD87E\uDC04`와 같습니다. |

#### 문자 이스케이프

표에 없는 문자의 경우 전행 백슬래시는 무시되지만, 이 용법은 더 이상 사용되지 않으며, 사용을 피해야 합니다.

전행 백슬래시와 함께 문자열 안에 따옴표를 사용할 수 있습니다. 이것을 따옴표 이스케이프라고 합니다. 예를 들어,

```js
var quote = "He read \"The Cremation of Sam McGee\" by R.W. Service.";
console.log(quote);
```

이 코드의 결과는,
```

He read "The Cremation of Sam McGee" by R.W. Service.
```

백슬래시를 문자열 내에 포함시키기 위해서는, 백슬래시 문자를 이스케이프 해야 합니다. 예를 들어, 파일 경로 `c:\temp`를 문자열에 할당하기 위해서는 아래와 같이 사용합니다.

```js
var home = "c:\\temp";
```

또한 줄바꿈 역시 전행 백슬래시로 이스케이프할 수 있습니다. 백슬래시와 줄바꿈 모두 문자열 값에서는 사라집니다.

```js
var str =
  "this string \
is broken \
across multiple \
lines.";
console.log(str); // this string is broken across multiple lines.
```

JavaScript에는 "heredoc" 구문은 없지만, 줄바꿈 이스케이프와 각 줄 끝 이스케이프된 줄바꿈을 추가하여 흉내낼 수 있습니다.

```js
var poem =
  "Roses are red,\n\
Violets are blue.\n\
Sugar is sweet,\n\
and so is foo.";
```

ECMAScript 2015에서는 **템플릿 리터럴**이라는 새로운 리터럴이 소개되었습니다. 이것은 다중 문자열을 포함한 많은 새로운 기능을 가지고 있습니다!

```js
var poem = `Roses are red,
Violets are blue.
Sugar is sweet,
and so is foo.`;
```

추가 정보
-----

이 장은 선언과 형에 대한 기본 구문에 초점을 맞춥니다. JavaScript 언어 구조에 대해 더 많이 배우려면, 다음 장을 참고하세요.

* 흐름 제어와 에러 처리
* 루프와 반복
* 함수
* 표현식과 연산자

다음 장에서는, 흐름 제어 구조와 에러 처리를 살펴 볼 것입니다.

* « 이전
* 다음 »


제어 흐름과 오류 처리 - JavaScript

제어 흐름과 오류 처리
============

* « 이전
* 다음 »

JavaScript는 애플리케이션에 다양한 상호작용을 추가하기 위한 일련의 명령문, 특히 제어 흐름 명령문을 지원합니다. 이번 장에서는 이 명령문들을 간략하게 살펴보겠습니다.

여기서 다룬 명령문들의 자세한 설명은 JavaScript 참고서에서 읽을 수 있습니다. 세미콜론(`;`)은 두 명령문을 분리하기 위해 사용했습니다.

모든 JavaScript 표현식은 명령문이기도 합니다. 표현식에 대한 자세한 정보는 표현식과 연산자에서 확인하세요.

블록문
---

가장 기본적인 명령문은, 명령문들을 그룹으로 묶을 수 있는 **블록문**입니다. 블록문의 블록은 한 쌍의 중괄호로 감싸는 것으로 나타냅니다.

```js
{
  statement_1;
  statement_2;
  ⋮
  statement_n;
}
```

### 예제

블록문은 제어 흐름 명령문과 많이 사용합니다. (`if`, `for`, `while`)

```js
while (x < 10) {
  x++;
}
```

여기서 `{ x++; }`가 블록문입니다.

**참고:** ECMA2015 (제6판) 이전의 JavaScript에는 블록 스코프가 **없었습니다**! 구형 JavaScript 코드에서는 블록 내에 정의한 변수의 스코프를 그 블록이 아니라, 변수 선언을 포함한 함수 또는 스크립트로 설정합니다. 때문에 변수 할당의 영향은 블록을 넘어서도 확인할 수 있습니다. 즉, 블록문이 스코프를 정의하지 않습니다.

JavaScript의 "독립 블록"은 C나 Java에서 기대할 수 있는 것과는 완전히 다른 결과를 낳습니다. 예를 들어,

```js
var x = 1;
{
  var x = 2;
}
console.log(x); // 2 출력
```

위 코드가 `2`를 출력하는 이유는, 블록 내의 `var x`가 블록 밖의 `var x`와 같은 스코프를 갖기 때문입니다. C와 Java였다면, 위와 같은 코드에선 `1`을 출력했을 것입니다.

**ECMAScript 2015**에 도입된 `let`과 `const` 변수 선언은 블록 스코프를 가집니다. 참고서의 `let`과 `const` 문서에서 더 많은 정보를 확인하세요.

조건문
---

조건문은 지정한 조건이 참인 경우에 실행하는 명령 집합입니다. JavaScript는 `if...else`와 `switch` 두 종류의 조건문을 지원합니다.

### `if...else` 문

명령문을 논리 조건이 참일 때 실행하려면 `if` 문을 사용하세요. 선택적으로, `else` 절을 추가해서 조건이 거짓인 경우에 실행할 명령문을 지정할 수 있습니다.

`if` 문의 형태는 다음과 같습니다.

```js
if (condition) {
  statement_1;
} else {
  statement_2;
}
```

위 코드에서, `condition`에는 `true`나 `false`로 평가할 수 있는 아무 표현식이나 대입할 수 있습니다. (`Boolean` 문서에서 `true`와 `false` 평가에 대해 더 알아보세요.)

`condition`이 `true`로 평가되면 `statement_1`을 실행합니다. 그렇지 않으면 `statement_2`를 실행합니다. `statement_1`과 `statement_2`에는 다른 `if` 문을 포함해 아무 명령문이나 사용할 수 있습니다.

`else if`를 사용해서 다수의 조건을 순차적으로 검사할 수도 있습니다.

```js
if (condition_1) {
  statement_1;
} else if (condition_2) {
  statement_2;
} else if (condition_n) {
  statement_n;
} else {
  statement_last;
}
```

이 경우, 처음으로 `true`로 평가되는 조건의 명령문들만 실행됩니다.

#### 모범 사례

일반적으로는 `if`에 항상, 특히 `if` 문을 중첩할 때는 블록문을 함께 사용하는 것이 좋습니다.

```js
if (condition) {
  statement_1_runs_if_condition_is_true;
  statement_2_runs_if_condition_is_true;
} else {
  statement_3_runs_if_condition_is_false;
  statement_4_runs_if_condition_is_false;
}
```

또한 `if...else`의 조건에 "`x = y`"와 같은 할당은 지양하세요.

```js
if ((x = y)) {
  /\* 명령문 \*/
}
```

그러나 가끔은 조건에서 할당하는 것이 더 편한 경우도 있습니다. 이런 상황에 참고할 수 있도록, `while` 문서의 "할당을 조건으로 사용하기"에서 일반적인 모범 구문의 안내를 제공하고 있습니다.

#### 거짓 값

다음 값은 `false`로 평가됩니다. (거짓 값이라고 부릅니다)

* `false`
* `undefined`
* `null`
* `0`
* `NaN`
* 빈 문자열 (`""`)

객체를 포함해 다른 모든 값은 조건문에 전달했을 때 `true`로 평가됩니다.

**참고:** `true`와 `false` 원시 값을 `Boolean` 객체의 참과 거짓 값과 혼동하지 마세요!

예를 들어,

```js
const b = new Boolean(false);
if (b)         // 참으로 평가
if (b == true) // 거짓으로 평가
```

#### 예제

다음 예제에서, 함수 `checkData`는 `Text` 객체에 포함된 문자의 수가 3이면 `true`를 반환합니다. 그렇지 않으면 경고를 표시한 후 `false`를 반환합니다.

```js
function checkData() {
  if (document.form1.threeChar.value.length == 3) {
    return true;
  } else {
    alert(
      "정확히 세 글자를 입력하세요. " +
        `${document.form1.threeChar.value}은(는) 유효하지 않습니다.`,
    );
    return false;
  }
}
```

### `switch` 문

`switch` 문은 프로그램이 표현식을 평가한 후, 그 값과 `case` 레이블의 값을 비교해 일치하는 `case`의 명령문을 실행합니다.

`switch` 문의 모습은 다음과 같습니다.

```js
switch (expression) {
  case label\_1:
    statements_1;
    break;
  case label\_2:
    statements_2;
    break;
    …
  default:
    statements_default;
}
```

JavaScript는 위의 `switch` 문을 다음의 과정으로 평가합니다.

* 우선 표현식(`expression`)의 결과와 일치하는 레이블을 가진 `case` 절을 찾아, 관련된 명령문을 실행합니다.
* 일치하는 레이블을 찾지 못했으면 `default` 절을 탐색합니다.
    + `default` 절을 찾았으면 관련된 명령문을 실행합니다.
    + `default` 절을 찾지 못했으면 `switch` 문 바깥의 다음 명령문을 실행합니다.
    + (`default`를 마지막에 배치하는 것은 관습적인 것으로, 사실 위치는 상관 없습니다.)

#### break 문

각각의 `case`에는 선택적으로 `break` 문을 추가할 수 있습니다. `break`는 `case`의 명령문을 실행한 후에 프로그램이 `switch`의 밖으로 나가도록 합니다. `break`를 생략하면 프로그램은 `switch` 문을 탈출하지 않고, 다음 `case`의 명령문을 실행합니다.

#### 예제

이 예제에서는 `fruitType`이 `'바나나'`라면 `'바나나'` 레이블을 가진 `case`의 명령문을 실행합니다. `break`를 마주치면 프로그램이 `switch` 밖으로 나가서 바로 다음 명령문을 실행합니다. `'바나나'`에 `break`가 없었다면 `case '체리'` 아래의 명령문도 실행했을 것입니다.

```js
switch (fruittype) {
  case "오렌지":
    console.log("오렌지는 파운드 당 $0.59입니다.");
    break;
  case "사과":
    console.log("사과는 파운드 당 $0.32입니다.");
    break;
  case "바나나":
    console.log("바나나는 파운드 당 $0.48입니다.");
    break;
  case "체리":
    console.log("체리는 파운드 당 $3.00입니다.");
    break;
  case "망고":
    console.log("망고는 파운드 당 $0.56입니다.");
    break;
  case "파파야":
    console.log("망고와 파파야는 파운드 당 $2.79입니다.");
    break;
  default:
    console.log(`죄송합니다. ${fruitType}은 품절입니다.`);
}
console.log("더 필요한게 있으신가요?");
```

예외 처리 명령문
---------

`throw` 문을 사용하면 예외를 던질 수 있고, 던진 예외는 `try...catch` 문으로 처리할 수 있습니다.

* `throw` 문
* `try...catch` 문
### 예외 유형

JavaScript에서는 모든 것을 `throw`로 던질 수 있습니다. 그래서 숫자나 문자열을 오류로 던지는 경우도 많지만, 예외를 나타내기 위해 사전에 정의된 예외 유형을 쓰는 것이 보통 더 효과적입니다.

* ECMAScript 예외
* `DOMException` (en-US), `DOMError` (en-US)
### `throw` 문

예외를 던질 땐 `throw` 문을 사용하세요. `throw`에 던질 값을 지정하면 됩니다.

```js
throw expression;
```

특정 타입의 표현식이 아니라 무엇이든 던질 수 있습니다. 아래 코드에서 다양한 타입을 예외로 던지는 모습을 볼 수 있습니다.

```js
throw "Error2"; // String
throw 42; // Number
throw true; // Boolean
throw {
  toString: function () {
    return "저는 객체예요";
  },
};
```

### `try...catch` 문

`try...catch` 문은 실행을 시도할 블록을 표시하고, 그 안에서 예외가 발생할 경우 처리를 맡을 하나 이상의 반응 명령문을 지정합니다. 예외가 발생하면, `try...catch` 문이 잡아냅니다.

`try...catch` 문은 하나 이상의 명령문을 포함하는 `try` 블록, 그리고 `try`에서 예외가 발생할 경우 그 예외를 처리할 명령문을 담은 하나의 `catch` 블록으로 구성합니다.

다르게 설명해보면, `try...catch`는 성공하길 바라는 코드(`try` 블록)가 만약 실패하면 `catch`로 제어권을 넘겨야 할 때 사용합니다. `try` 블록의 명령문 중 하나에서 예외를 던지면, 실행 제어권은 그 즉시 `catch` 블록으로 넘어갑니다. `try` 블록 내에서 예외가 발생하지 않았으면 `catch` 블록은 실행되지 않습니다.

다음은 `try...catch`의 사용 모습을 보이는 예제입니다. `getMonthName()`은 매개변수의 값을 사용해 `months` 배열에서 영어 월 이름을 가져옵니다. 그런데 유효한 월(`1`-`12`) 범위의 숫자 값을 받은 것이 아니라면 `'InvalidMonthNo'`를 값으로 한 예외를 던집니다. 그러면 `catch` 블록의 명령문이 `monthName` 변수를 `'unknown'`으로 설정합니다.

```js
function getMonthName(mo) {
  mo = mo - 1; // 배열 인덱스에 맞춰 월 조절 (1 = Jan, 12 = Dec)
  let months = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
  ];
  if (months[mo]) {
    return months[mo];
  } else {
    throw "InvalidMonthNo"; // 여기서 throw 키워드 사용
  }
}

try {
  // 시도할 명령문
  monthName = getMonthName(myMonth); // 예외가 발생할 수 있는 함수
} catch (e) {
  monthName = "unknown";
  logMyErrors(e); // 오류 처리기에 예외 객체 전달
}
```

#### `catch` 블록

`try` 블록에서 발생할 수 있는 모든 예외는 `catch` 블록에서 처리할 수 있습니다.

```js
catch (catchID) {
  statements;
}
```

`catch` 블록은 `throw` 명령문이 던진 예외의 값을 담을 식별자(위 코드 블록에서는 `catchID`)를 지정합니다. 이 식별자를 통해, 발생한 예외의 정보를 알아낼 수 있습니다.

JavaScript는 `catch` 블록에 진입해야 예외의 식별자를 생성하고, `catch` 블록의 밖으로 나가면 식별자를 더 이상 유지하지 않습니다. 즉, `catch` 블록의 실행이 끝나면 예외 식별자에 접근할 수 없습니다.

아래는 예외를 던지고 잡는 예제 코드입니다. 예외를 던지면 그 순간 제어권이 `catch` 블록으로 넘어갑니다.

```js
try {
  throw "myException"; // 예외 생성
} catch (e) {
  // 모든 예외를 처리하기 위한 명령문
  logMyErrors(e); // 오류 처리기에 예외 객체 전달
}
```

**참고:** `catch` 블록 안에서 오류를 기록할 땐 `console.log()`보다 `console.error()`를 사용하는 것을 추천합니다. `console.error()`는 출력 형식도 오류에 적합하고, 현재 페이지에서 발생한 오류의 목록도 업데이트합니다.

#### `finally` 블록

`finally` 블록은 `try`와 `catch` 블록 실행이 끝난 후 이어서, 그리고 `try...catch...finally` 문 이후의 명령문들보다는 먼저 실행할 명령문을 담습니다.

`finally` 블록은 `try` 블록 안에서 예외가 발생했는지 여부에 관계 없이, `catch` 블록이 따로 존재하지 않더라도 항상 실행됩니다.

`finally` 블록을 활용하면 예외가 발생했을 때 프로그램이 우아하게 실패하도록 방어할 수 있습니다. 예를 들어, 예외의 발생 여부를 따지지 않고 스크립트가 점유한 리소스를 해제해야 할 때 사용하세요.

다음의 코드 예제는 파일을 열어서 그 안의 데이터를 사용하는 함수(`writeMyFile()`)를 호출하는 예시입니다. (서버사이드 JavaScript에서는 파일에 접근할 수 있습니다) 파일이 열려있는 동안 예외가 나타나면, 스크립트가 실패하기 전에 `finally` 블록이 파일을 닫아줍니다. `finally`를 사용함으로써 오류가 발생하더라도 파일이 열린 채 방치되는 일을 방지할 수 있는 것입니다.

```js
openMyFile();
try {
  writeMyFile(theData); // 오류가 발생할 수 있는 코드
} catch (e) {
  handleError(e); // 오류가 발생하면 처리함
} finally {
  closeMyFile(); // 항상 리소스 해제
}
```

만약 `finally` 블록이 값을 반환한다면, 그 값이 전체 `try...catch...finally` 문의 반환 값이 됩니다. `try`와 `catch` 블록에서 반환하는 값은 무시합니다.

```js
function f() {
  try {
    console.log(0);
    throw "bogus";
  } catch (e) {
    console.log(1);
    return true; // finally 블록의 실행이 끝날 때까지 중단됨
    console.log(2); // 접근 불가
  } finally {
    console.log(3);
    return false; // 앞선 return보다 우선함
    console.log(4); // 접근 불가
  }
  // return false가 실행됨
  console.log(5); // 접근 불가
}
console.log(f()); // 0, 1, 3, false
```

`finally`의 반환 값이 우선하는 것은 `catch` 블록에서 던진 예외에도 적용됩니다.

```js
function f() {
  try {
    throw "예외";
  } catch (e) {
    console.log('내부 "예외" 포획');
    throw e; // finally 블록의 실행이 끝날 때까지 중단
  } finally {
    return false; // 앞선 throw보다 우선함
  }
  // return false가 실행됨
}

try {
  console.log(f());
} catch (e) {
  // 도달 불가능한 catch 블록!
  // f()가 실행되면 `finally`에서 false를 반환함
  // 반환이 catch의 throw보다 우선했으므로 예외가 없음
  console.log('caught outer "bogus"');
}

// 출력 결과
// 내부 "예외" 포획
// false
```

#### try...catch 문 중첩하기

`try...catch` 문을 하나 이상 중첩할 수 있습니다.

안쪽 `try` 블록이 `catch` 블록을 가지지 않을 경우,

1. 이 `try` 블록에는 반드시 `finally` 블록이 있어야 합니다.
2. 바깥 `try...catch` 문의 `catch` 블록이 안쪽 예외를 처리하게 됩니다.

더 자세한 정보는 `try...catch` (en-US) 참고서의 중첩 try 블록 (en-US)을 참고하세요.

### Error 객체 활용하기

`Error` 객체의 `name`과 `message` 속성으로부터 오류의 유형에 따라 좀 더 정제된 메시지를 가져올 수 있습니다.

`name`은 `Error`의 일반적인 클래스(`DOMException`, `Error`, 등등)를 제공합니다. `message`는 오류 메시지인데, 대개 오류 객체를 문자열로 변환한 결과보다 더 간결한 형태입니다.

직접 예외를 던지려는 경우에는, 특히 `catch` 블록이 시스템 오류와 직접 던지는 예외를 구분하지 않는다면, `Error` 생성자를 사용해서 두 속성을 제공할 수 있습니다.

```js
function doSomethingErrorProne () {
  if (ourCodeMakesAMistake()) {
    throw (new Error('메시지'));
  } else {
    doSomethingToGetAJavascriptError();
  }
}
⋮
try {
  doSomethingErrorProne();
}
catch (e) {
  console.log(e.name); // 'Error' 기록
  console.log(e.message); // '메시지' 또는 JavaScript 오류 메시지 기록
}
```

* « 이전
* 다음 »


JavaScript 형식화 배열 - JavaScript

JavaScript 형식화 배열
=================

JavaScript 형식화 배열(typed array)은 배열같은 객체이고 원시(raw) 이진 데이터에 액세스하기 위한 메커니즘을 제공합니다. 이미 아시다시피, `Array` 객체는 동적으로 늘었다 줄고 어떤 JavaScript 값이든 가질 수 있습니다. JavaScript 엔진은 이러한 배열이 빨라지도록 최적화를 수행합니다. 그러나, audio 및 video 조작과 같은 기능 추가, WebSocket을 사용한 원시 데이터에 액세스 등 웹 어플리케이션이 점점 더 강력해짐에 따라, 빠르고 쉽게 형식화 배열의 원시 이진 데이터를 조작할 수 있게 하는 것이 JavaScript 코드에 도움이 될 때가 있음이 분명해 졌습니다.

그러나, 형식화 배열은 보통 배열과 혼동되지는 않습니다, 형식화 배열에 `Array.isArray()` 호출은 `false`를 반환하기에. 게다가, 보통 배열에 이용할 수 있는 모든 메서드가 형식화 배열에 의해 지원되지는 않습니다(가령 push 및 pop).

버퍼 및 뷰: 형식화 배열 구조
-----------------

최대 유연성 및 효율을 달성하기 위해, JavaScript 형식화 배열은 구현을 **버퍼** 및 **뷰**로 나눕니다. 버퍼 (`ArrayBuffer` 객체에 의해 구현됨)는 데이터 부분(chunk, 덩어리)을 나타내는 객체입니다; 이야기 할 형식이 없으며, 그 콘텐츠에 액세스하기 위한 메커니즘을 제공하지 않습니다. 버퍼에 포함된 메모리에 액세스하기 위해, 뷰를 사용할 필요가 있습니다. 뷰는 문맥(context, 즉 데이터 형, 시작 오프셋 및 요소 수)을 제공해 데이터를 실제 형식화 배열로 바꿉니다.

![Typed arrays in an ArrayBuffer](/ko/docs/Web/JavaScript/Guide/Typed_arrays/typed_arrays.png)

### ArrayBuffer

`ArrayBuffer`는 일반 고정 길이 이진 데이터 버퍼를 나타내는 데 사용되는 데이터 형입니다. `ArrayBuffer` 콘텐츠를 직접 조작할 수는 없습니다; 대신에, 형식화 배열 뷰 또는 특정 형식으로 버퍼를 나타내는 `DataView`를 만들어 버퍼의 콘텐츠를 읽고 쓰기 위해 사용합니다.

### 형식화 배열 뷰

형식화 배열 뷰는 자체 설명형 이름이 있으며 `Int8`, `Uint32`, `Float64` 등과 같은 모든 일반 숫자 형을 위한 뷰를 제공합니다. 특별한 형식화 배열 뷰가 하나 있습니다, `Uint8ClampedArray`. 값은 0에서 255 사이로 단속(제한)합니다. 예를 들어, 이는 Canvas 데이터 처리에 유용합니다.

| Type | Value Range | Size in bytes | Description | Web IDL type | Equivalent C type |
| --- | --- | --- | --- | --- | --- |
| `Int8Array` | `-128` to `127` | 1 | 8-bit two's complement signed integer | `byte` | `int8_t` |
| `Uint8Array` | `0` to `255` | 1 | 8-bit unsigned integer | `octet` | `uint8_t` |
| `Uint8ClampedArray` | `0` to `255` | 1 | 8-bit unsigned integer (clamped) | `octet` | `uint8_t` |
| `Int16Array` | `-32768` to `32767` | 2 | 16-bit two's complement signed integer | `short` | `int16_t` |
| `Uint16Array` | `0` to `65535` | 2 | 16-bit unsigned integer | `unsigned short` | `uint16_t` |
| `Int32Array` | `-2147483648` to `2147483647` | 4 | 32-bit two's complement signed integer | `long` | `int32_t` |
| `Uint32Array` | `0` to `4294967295` | 4 | 32-bit unsigned integer | `unsigned long` | `uint32_t` |
| `Float32Array` | `-3.4E38` to `3.4E38` and `1.2E-38` is the min positive number | 4 | 32-bit IEEE floating point number (7 significant digits e.g., `1.123456`) | `unrestricted float` | `float` |
| `Float64Array` | `-1.8E308` to `1.8E308` and `5E-324` is the min positive number | 8 | 64-bit IEEE floating point number (16 significant digits e.g., `1.123...15`) | `unrestricted double` | `double` |
| `BigInt64Array` | `-2^63` to `2^63 - 1` | 8 | 64-bit two's complement signed integer | `bigint` | `int64_t (signed long long)` |
| `BigUint64Array` | `0` to `2^64 - 1` | 8 | 64-bit unsigned integer | `bigint` | `uint64_t (unsigned long long)` |

### DataView

`DataView`는 버퍼에 임의 데이터를 읽고 쓰기 위해 getter/setter API를 제공하는 저레벨 인터페이스입니다. 예를 들어, 서로 다른 유형의 데이터를 처리하는 경우 유용합니다. 형식화 배열 뷰는 플랫폼의 본디(native) 바이트 순서(byte-order, Endianness 참조)에 속합니다. `DataView`로 바이트 순서를 제어할 수 있습니다. 기본으로 big-endian이고 getter/setter 메서드로 little-endian으로 설정될 수 있습니다.

형식화 배열을 사용하는 웹 API
------------------

`FileReader.prototype.readAsArrayBuffer()`

`FileReader.prototype.readAsArrayBuffer()` 메서드는 지정된 `Blob` 또는 `File`의 콘텐츠를 읽기 시작합니다.

`XMLHttpRequest.prototype.send()`

`XMLHttpRequest` 인스턴스의 `send()` 메서드는 이제 형식화 배열 및 인수로 `ArrayBuffer` 객체를 지원합니다.

`ImageData.data`

`0`에서 `255`까지 정수값으로 RGBA 순 데이터를 포함하는 1차원 배열을 나타내는 `Uint8ClampedArray`입니다.

예
-

### 버퍼와 뷰 사용하기

우선, 여기서 16바이트 고정 길이로 버퍼를 만들어야 합니다:

```js
var buffer = new ArrayBuffer(16);
```

이 시점에서, 바이트가 모두 0으로 미리 초기화된 메모리 덩어리가 있습니다. 그렇지만 이거 가지고 할 수 있는 게 많지 않습니다. 실제 16바이트 길이인지 확인할 수 있고 대략 그런 정도입니다:

```js
if (buffer.byteLength === 16) {
  console.log("Yes, it's 16 bytes.");
} else {
  console.log("Oh no, it's the wrong size!");
}
```

정말 이 버퍼로 작업할 수 있기 전에, 뷰를 만들어야 합니다. 32비트 부호있는 정수 배열로 버퍼의 데이터를 다루는 뷰를 만듭시다:

```js
var int32View = new Int32Array(buffer);
```

이제 보통 배열처럼 배열 내 필드에 액세스할 수 있습니다:

```js
for (var i = 0; i < int32View.length; i++) {
  int32View[i] = i \* 2;
}
```

이는 배열의 4항목을 값 0, 2, 4 및 6으로 채웁니다 (4항목이 각각 4바이트에 총 16바이트가 됩니다).

### 같은 데이터에 여러 뷰

상황은 당신이 같은 데이터에 여러 뷰를 만들 수 있음을 고려하는 경우 정말 흥미로워지기 시작합니다. 예를 들어, 위 코드가 주어지면 다음과 같이 계속할 수 있습니다:

```js
var int16View = new Int16Array(buffer);

for (var i = 0; i < int16View.length; i++) {
  console.log("Entry " + i + ": " + int16View[i]);
}
```

여기서 우리는 기존 32비트 뷰와 같은 버퍼를 공유하는 16비트 정수 뷰를 만들고 16비트 정수로 버퍼 내 모든 값을 출력합니다. 이제 우리는 출력 0, 0, 2, 0, 4, 0, 6, 0을 얻습니다.

그렇지만 한 단계 더 앞으로 갈 수 있습니다. 다음을 생각해 보세요:

```js
int16View[0] = 32;
console.log("Entry 0 in the 32-bit array is now " + int32View[0]);
```

이로부터 출력은 "Entry 0 in the 32-bit array is now 32"입니다. 즉, 두 배열은 확실히 그저 같은 데이터 버퍼 상의 뷰입니다, 버퍼를 서로 다른 형식으로 다루는. 모든 뷰 유형으로 이를 할 수 있습니다.

### 복잡한 데이터 구조(체)와 작업하기

단일 버퍼를 서로 다른 형인 여러 뷰(버퍼 내 서로 다른 오프셋에서 시작하는)와 결합시켜, 여러 데이터 형을 포함하는 데이터 객체와 상호 작용할 수 있습니다. 예를 들어, 이는 WebGL, 데이터 파일 또는 js-ctypes를 쓰는 동안 사용해야 하는 C 구조체에서 복잡한 데이터 구조와 상호 작용케 합니다.

이 C 구조체를 생각해 보세요:

```cpp
struct someStruct {
  unsigned long id;
  char username[16];
  float amountDue;
};
```

이 같은 형식으로 데이터를 포함하는 버퍼에 액세스할 수 있습니다:

```js
var buffer = new ArrayBuffer(24);

// ... 버퍼 내의 데이터를 읽어들임 ...

var idView = new Uint32Array(buffer, 0, 1);
var usernameView = new Uint8Array(buffer, 4, 16);
var amountDueView = new Float32Array(buffer, 20, 1);
```

그런 뒤, 예를 들어 `amountDueView[0]`로 지불할 요금(amount due)을 액세스할 수 있습니다.

**참고:** **주의:** C 구조체에서 데이터 구조 정렬은 플랫폼에 의존합니다. 이러한 패딩(padding) 차이에 대해 조심하고 고려하세요.

### 보통 배열로 변환

형식화 배열을 처리한 뒤, 때때로 `Array` 프로토타입의 도움을 받기 위해 보통 배열로 다시 변환하는 게 유용합니다. 이는 `Array.from` 또는 `Array.from`이 지원되지 않는 경우 다음 코드를 사용하여 수행할 수 있습니다.

```js
var typedArray = new Uint8Array([1, 2, 3, 4]),
  normalArray = Array.prototype.slice.call(typedArray);
normalArray.length === 4;
normalArray.constructor === Array;
```

참조
--

* *Base64*로 인코딩된 문자열에서 `ArrayBuffer` 또는 형식화 배열 얻기 (en-US)
* `StringView` - 형식화 배열에 기반을 둔 문자열의 C-like 표현
* 형식화 배열로 빠른 Canvas 픽셀 조작
* 형식화 배열: 브라우저에서 이진 데이터
* Endianness


소개 - JavaScript

소개
==

* « 이전
* 다음 »

이 장에서는 JavaScript를 소개하고 몇 가지 기본 개념에 대해 설명합니다.

알고 있어야 하는 것
-----------

이 안내서는 여러분이 아래 기본 배경지식이 있다고 가정합니다.

* 인터넷과 월드 와이드 웹 (WWW)에 대한 일반적인 이해.
* HyperText Markup Language (HTML)에 대한 적절한 실무 지식.
* 약간의 프로그래밍 경험. 만약 프로그래밍이 처음이라면, JavaScript 메인 페이지에 링크된 자습서 중 하나를 공부해보세요.
JavaScript 정보를 찾을 수 있는 곳
------------------------

MDN에 있는 JavaScript 문서는 다음 세가지 파트로 되어있습니다.

* Web 개발 학습하기는 입문자를 위한 정보를 제공하며, 프로그래밍과 인터넷에 대한 기본 개념을 소개합니다.
* JavaScript 안내서 (이 안내서)는 JavaScript 언어와 객체에 대한 개요를 제공합니다.
* JavaScript 참고서 JavaScript에 관련된 자세한 참고 자료를 제공합니다.

JavaScript가 처음이라면, 학습터와 JavaScript 안내서부터 시작해 보세요. 기본 사항을 확실히 이해했다면 JavaScript 참고서에서 개별 객체 및 명령문에 대한 자세한 내용을 확인할 수 있습니다.

JavaScript는 무엇인가?
-----------------

JavaScript는 웹 페이지를 대화식(예: 복잡한 애니메이션, 클릭 가능한 버튼, 팝업 메뉴 등)으로 만드는 데 사용되는 크로스 플랫폼, 객체 지향 스크립팅 언어입니다. 또한 Node.js와 같이 파일을 다운로드하는 것보다 더 많은 기능(예: 여러 컴퓨터 간의 실시간 공동 작업)을 웹 사이트에 추가할 수 있는 JavaScript의 고급 서버 측 버전도 있습니다. 호스트 환경(예: 웹 브라우저) 내에서 JavaScript를 해당 환경의 객체에 연결하여 프로그래밍 방식으로 제어할 수 있습니다.

JavaScript는 `Array`, `Date`, 그리고 `Math`와 같은 객체에 대한 표준 라이브러리와 연산자, 제어 구조, 그리고 명령문과 같은 언어 요소의 집합이 있습니다. 코어 JavaScript는 추가 객체로 보완하여 다양한 목적으로 확장할 수 있습니다. 예를 들어 다음과 같습니다.

* 클라이언트 측 JavaScript는 브라우저와 문서 객체 모델(DOM)을 제어하는 객체를 제공하여 코어 언어를 확장합니다. 예를 들어, 클라이언트 측 확장을 사용하면 애플리케이션이 HTML 양식에 요소를 배치하고 마우스 클릭, 양식 입력, 그리고 페이지 탐색과 같은 사용자 이벤트에 응답할 수 있습니다.
* 서버 측 JavaScript는 서버에서 JavaScript를 실행하는 것과 관련된 객체를 제공하여 핵심 언어를 확장합니다. 예를 들어, 서버측 확장을 사용하면 애플리케이션이 데이터베이스와 통신하고, 애플리케이션의 한 호출에서 다른 애플리케이션으로 연속적인 정보를 제공하거나, 서버에서 파일을 조작할 수 있습니다.

이것은 브라우저에서 JavaScript가 웹 페이지 (DOM)의 모양을 바꿀 수 있음을 의미합니다. 또한 서버의 Node.js JavaScript는 브라우저에 작성된 코드의 사용자 정의 요청에 응답 할 수 있습니다.

JavaScript 와 Java
-----------------

JavaScript 와 Java는 여러 면에서 비슷하지만 어떤 면에서는 근본적으로 다릅니다. JavaScript 언어는 Java를 닮았지만 Java의 정적 형 지정과 강한 형 검사를 가지고있지 않습니다. JavaScript는 대부분의 Java 표현 구문, 명명 규칙 및 기본적인 흐름 제어 구조를 따르며 이것이 LiveScript에서 JavaScript로 이름이 변경된 이유입니다.

Java의 선언에 의해 생성되는 클래스의 컴파일-타임 시스템과는 달리, JavaScript는 숫자, 불리언, 그리고 문자열 값을 표현하는 적은 수의 자료 형을 기반으로 한 런타임 시스템을 지원합니다. JavaScript는 보다 일반적인 클래스 기반 객체 모델 대신에 프로토타입 기반 객체 모델을 갖습니다. 프로토타입 기반 모델은 동적 상속을 제공합니다. 즉, 상속된 대상은 각각의 객체에 따라 다양할 수 있습니다. JavaScript는 또한 어떤 특정한 선언을 요구하지 않는 함수도 지원합니다. 함수는 객체의 속성이나, 타입이 느슨하게 지정된 메서드가 될 수 있습니다.

JavaScript는 Java에 비해 매우 자유로운 형태의 언어입니다. 모든 변수, 클래스, 그리고 메서드를 선언할 필요는 없습니다. 메소드가 public, private, 또는 protected 인지 걱정할 필요가 없으며 인터페이스를 구현하지 않아도 됩니다. 변수, 매개변수, 그리고 함수의 반환 형은 명시적으로 지정되지 않습니다.

Java는 빠른 실행과 형 안전성을 위해 설계된 클래스 기반 프로그래밍 언어입니다. 형 안전성은, 예를 들어, 여러분이 Java 정수를 객체의 레퍼런스로 형변환 하거나 Java 바이트코드를 변경하여 private 메모리에 접근할 수 없음을 의미합니다. Java의 클래스 기반 모델은 프로그램이 오로지 클래스와 그 메서드로만 구성된다는 것을 뜻합니다. Java의 클래스 상속과 강한 형 지정은 보통 단단하게 결합된 객체 계층구조를 요구합니다. 이러한 요구는 Java 프로그래밍을 JavaScript 프로그래밍보다 더 복잡하게 만듭니다.

반면에, JavaScript는 HyperTalk 과 dBASE 같은 더 작고 동적인 형 지정이 가능한 언어들의 정신을 계승했습니다. 이러한 스크립팅 언어는 더 쉬운 구문과 특별한 내장 기능, 그리고 객체 생성을 위한 최소 요구사항으로 인해 훨씬 더 많은 사람들에게 프로그래밍 도구를 제공합니다.

| JavaScript | Java |
| --- | --- |
| 객체 지향. 객체의 형 간에 차이 없음. 프로토타입 메커니즘을 통한 상속, 그리고 속성과 메서드는 어떤 객체든 동적으로 추가될 수 있음. | 클래스 기반. 객체는 클래스 계층구조를 통한 모든 상속과 함께 클래스와 인스턴스로 나뉨. 클래스와 인스턴스는 동적으로 추가된 속성이나 메서드를 가질 수 없음. |
| 변수 자료형이 선언되지 않음(동적 형 지정, 느슨한 형 지정). | 변수 자료형은 반드시 선언되어야 함(정적 형 지정, 강한 형 지정). |
| 하드 디스크에 자동으로 작성 불가. | 하드 디스크에 자동으로 작성 가능. |

JavaScript와 ECMAScript 명세서
--------------------------

JavaScript는 JavaScript를 기반으로 표준화된 국제 프로그래밍 언어를 제공하기 위해 정보 및 통신 시스템 표준화를 위한 유럽 협회(이전에는 유럽 컴퓨터 제조업체 협회(European Computer Manufacturers Association)의 약자)인 Ecma International에서 표준화되었습니다. ECMAScript라고 하는 이 표준화된 JavaScript 버전은 표준을 지원하는 모든 애플리케이션에서 동일한 방식으로 작동합니다. 회사는 개방형 표준 언어를 사용하여 JavaScript 구현을 개발할 수 있습니다. ECMAScript 표준은 ECMA-262 명세에 문서화되어 있습니다.

ECMA-262 표준은 또한 IOS-16262로서 ISO (국제 표준화 기구)에 의해 승인되었습니다. Ecma International website 에서 그 명세를 찾을 수 있습니다. ECMAScript 명세는 World Wide Web Consortium (W3C) 나 WHATWG (Web Hypertext Application Technology Working Group)에 의해 표준화된 Document Object Model (DOM)을 설명하지 않습니다. DOM은 HTML 문서 객체가 스크립트에 노출되는 방식을 정의합니다. JavaScript로 프로그래밍할 때 사용되는 다양한 기술에 대한 더 나은 아이디어를 얻으려면, JavaScript 기술 개요 기사를 참고하세요.

### JavaScript 문서 vs ECMAScript 명세서

ECMAScript 명세는 ECMAScript 구현을 위한 요구 사항의 집합입니다. ECMAScript 구현 또는 엔진(예: Firefox의 SpiderMonkey 또는 Chrome의 V8)에서 표준 호환 언어 기능을 구현하려는 경우에 유용합니다.

ECMAScript 문서는 스크립트 프로그래머를 돕기 위한 것이 아닙니다. 스크립트를 작성할 때 정보를 보려면 JavaScript 문서를 사용하세요.

ECMAScript 명세는 JavaScript 프로그래머에게 익숙하지 않을 수 있는 용어와 문법을 사용합니다. 언어에 대한 설명은 ECMAScript에서 다를 수 있지만 언어 자체는 동일하게 유지됩니다. JavaScript는 ECMAScript 사양에 설명된 모든 기능을 지원합니다.

JavaScript 문서는 JavaScript 프로그래머에게 적합한 언어의 측면을 설명합니다.

JavaScript 시작하기
---------------

JavaScript 시작은 쉽습니다. 최신 웹 브라우저만 있으면 됩니다. 이 안내서는 현재 최신 버전의 Firefox에서만 사용할 수 있는 일부 JavaScript 기능이 포함되어 있으므로 최신 버전의 Firefox를 사용하는 것이 좋습니다.

Firefox에 내장된 웹 콘솔 도구는 JavaScript를 실험하는 데 유용합니다. 한 줄 입력 모드와 여러 줄 입력 모드의 두 가지 모드로 사용할 수 있습니다.

### 웹 콘솔에서 한 줄 입력하기

웹 콘솔은 현재 로드된 웹 페이지에 대한 정보를 표시하고, 현재 페이지에서 JavaScript 표현식을 실행하는 데 사용할 수 있는 JavaScript 인터프리터도 제공합니다.

웹 콘솔을 열기 위해서는(윈도우와 리눅스에서는 `Ctrl`+`Shift`+`I`, 맥에서는 `Cmd`-`Option`-`K`), Firefox에서 **기타 도구** 메뉴를 열고 "**웹 개발자 도구**"를 선택합니다.

브라우저 창 하단에 웹 콘솔이 나타날겁니다. 콘솔 하단에는 JavaScript를 입력하는 데 사용할 수 있는 입력 줄이 있으며 출력은 위 패널에서 나타납니다.

![하단에 웹 콘솔이 열려 있는 브라우저 창에는 두 줄의 입력 및 출력이 포함되어 있습니다. 그 아래에 텍스트를 입력할 수 있습니다.](/ko/docs/Web/JavaScript/Guide/Introduction/2019-04-04_00-15-29.png)

콘솔은 `eval`과 똑같은 방식으로 작동합니다. 입력한 마지막 표현식이 반환되죠. 간단하게 생각해서, 콘솔에 무엇인가 입력할 때마다 `eval` 주위에 `console.log`가 둘러싸여 있다고 생각할 수 있습니다.

```js
console.log(eval("3 + 5"));
```

### 웹 콘솔에서 여러 줄 입력하기

웹 콘솔의 한 줄 입력 모드는 JavaScript 표현식을 빠르게 테스트하는 데 적합합니다. 그리고 여러 줄을 실행할 수도 있지만 그리 편리하지 않습니다. 더 복잡한 JavaScript의 경우 여러 줄 입력 모드를 사용할 수 있습니다.

### Hello world

JavaScript 작성을 시작하려면 여러 줄 모드에서 웹 콘솔을 열고 첫 번째 "Hello world" JavaScript 코드를 작성해 보세요.

```js
(function () {
  "use strict";
  /\* 코드 시작 \*/
  function greetMe(yourName) {
    alert(`Hello ${yourName}`);
  }

  greetMe("World");
  /\* 코드 끝 \*/
})();
```

`Cmd`+`Enter` 또는 `Ctrl`+`Enter`(또는 실행 버튼 클릭)를 눌러 브라우저에서 펼쳐지는 것을 지켜보세요!

다음 페이지에서는 JavaScript 구문과 언어 특징을 배우기 때문에 보다 복잡한 애플리케이션을 작성할 수 있을겁니다.

그러나 지금은 코드 앞에 항상 `(function(){"use strict";`를 붙이고 마지막에 `})();`를 써야합니다. 엄격 모드와 IIFE 문서에서 이들이 무엇을 하는지 알아볼 수 있지만, 현재로서는 다음을 수행하는 것으로 생각하면 좋습니다.

1. 초보자를 실수하게 만드는 JavaScript 시맨틱을 방지합니다.
2. 콘솔에서 실행되는 코드 스니펫이 서로 상호 작용하지 않도록 방지합니다(예: 한 콘솔 실행에서 생성된 항목이 다른 콘솔 실행에 사용됨).
* « 이전
* 다음 »