JavaScript의 타입과 자료구조 - JavaScript

JavaScript의 타입과 자료구조
====================

모든 프로그래밍 언어에는 내장된 자료구조가 존재하지만, 보통 그 내용은 언어마다 다릅니다. 이 글에서는 JavaScript에서 사용할 수 있는 내장 자료구조와 그 속성에 대해 알아보겠습니다. 그러면 이 자료구조들을 다른 자료구조 개발에 사용할 수 있을 것입니다.

언어 개요는 일반적인 데이터 타입에 대한 유사한 정리된 내용을 제공하지만, 다른 언어와 더 많은 비교를 제공합니다.

동적 및 약타입
--------

JavaScript는 동적 타입이 있는 동적 언어입니다. JavaScript의 변수는 어떤 특정 타입과 연결되지 않으며, 모든 타입의 값으로 할당 (및 재할당) 가능합니다.

```js
let foo = 42; // foo는 이제 숫자입니다
foo = "bar"; // foo는 이제 문자열입니다
foo = true; // foo는 이제 불리언입니다
```

JavaScript는 또한 약타입 언어이기도 합니다. 즉, 작업에 타입 오류가 발생하는 대신, 일치하지 않는 타입이 포함된 경우 암시적 타입 변환이 가능합니다.

```js
const foo = 42; // foo는 숫자입니다.
const result = foo + "1"; // JavaScript는 foo를 문자열로 강제 변환하므로, 다른 피연산자와 연결할 수 있습니다.
console.log(result); // 421
```

 암시적 형변환은 매우 편리하지만, 개발자가 변환을 수행할 의도가 없거나, 다른 방향으로 변환하려는 경우(예: 숫자에서 문자열 대신, 문자열에서 숫자로 변환하는 것) 잠재적인 오류(footgun)가 될 수 있습니다.
 기호 및 BigInts의 경우, JavaScript는 의도적으로 특정 암시적 타입 변환을 허용하지 않습니다.

원시 값(Primitive values)
----------------------

Object를 제외한 모든 타입은 언어의 최하위 수준에서 직접 표현되는 불변 값을 정의합니다. 이러한 타입의 값을 '원시 값'이라고 합니다.

`null`을 제외한 모든 기본 타입은 `typeof` 연산자로 테스트할 수 있습니다. `typeof null`은 `"object"`를 반환하므로 `=== null`을 사용하여 `null`을 테스트해야 합니다.

`null` 및 `undefined`를 제외한, 모든 원시 타입에는 원시 값으로 작업하는 데 유용한 메서드를 제공하는 해당 객체 래퍼 타입이 있습니다. 예를 들어, `Number` 객체는 `toExponential()`와 같은 메서드를 제공합니다. 원시 값에서 속성에 접근하면, JavaScript는 값을 해당 래퍼 객체로 자동으로 감싸는 대신 객체의 속성에 접근합니다. 그러나 `null` 또는 `undefined`에서 속성에 접근하면, `TypeError` 예외가 발생하므로 선택적 체이닝 연산자를 도입해야 합니다.

| Type | `typeof` return value | Object wrapper |
| --- | --- | --- |
| Null 타입 | `"object"` | N/A |
| Undefined 타입 | `"undefined"` | N/A |
| Boolean 타입 | `"boolean"` | `Boolean` |
| Number 타입 | `"number"` | `Number` |
| BigInt 타입 | `"bigint"` | `BigInt` |
| String 타입 | `"string"` | `String` |
| Symbol 타입 | `"symbol"` | `Symbol` |

객체 래퍼 클래스의 참조 페이지에는 각 타입에 사용할 수 있는 메서드 및 속성에 대한 자세한 정보와, 원시 타입 자체의 의미 체계에 대한 자세한 설명이 포함되어 있습니다.

### Null 타입

Null 타입은 `null`이라는 오직 하나의 값만 가질 수 있습니다.

### Undefined 타입

Undefined 타입은 `undefined`이라는 오직 하나의 값만 가질 수 있습니다.

 개념적으로, `undefined`는 값이 없음을 의미하고, `null`은 객체가 없음을 의미합니다.
 (`typeof null === "object"`에 대한 변명이 될 수도 있습니다). 일반적으로 값이 없는 경우 언어의 기본값은 `undefined`입니다.

* 반환 값이 없는 `return`문(`return;`)은 암시적으로 `undefined`를 반환합니다.
* 존재하지 않는 객체 속성에 접근 (`obj.iDontExist`) 하면 `undefined`가 반환됩니다.
* 초기화(`let x;`)가 없는 변수 선언은 변수를 `undefined`로 암시적으로 초기화합니다.
* `Array.prototype.find()` 및 `Map.prototype.get()`와 같은 대부분의 메서드는, 요소를 찾을 수 없을 때 `undefined`를 반환합니다.

`null`은 언어의 핵심적인 부분에선 덜 자주 사용됩니다. 가장 중요한 위치는 prototype chain의 끝부분입니다. 이어서, `Object.getPrototypeOf()`, `Object.create()` 등 프로토타입과 상호 작용하는 메서드는 `undefined` 대신 `null`을 받거나 반환합니다.

`null`은 키워드 (en-US)이지만, `undefined`는 전역 속성인 일반적인 식별자 (en-US)입니다. 실제로는 `undefined`가 재정의되거나 가려져서는 안 되기 때문에 그 차이는 미미합니다.

### Boolean 타입

`Boolean` 타입은 논리 요소를 나타내며 `true`와 `false` 두 가지의 값을 가질 수 있습니다.

불리언 값은 일반적으로 삼항 연산자 , `if...else`, `while` 등을 포함한, 조건부 연산에 사용됩니다.

### Number 타입

`Number` 타입은 배정밀도 64비트 이진 형식 IEEE 754 값입니다. 2-1074 (`Number.MIN_VALUE`) 와 21024 (`Number.MAX_VALUE`) 사이의 양수 부동 소수점 뿐만 아니라, -2-1074 와 -21024 사이의 음수 부동 소수점 숫자도 저장할 수 있지만, -(253 − 1) (`Number.MIN_SAFE_INTEGER`) 와 253 − 1 (`Number.MAX_SAFE_INTEGER`) 범위의 정수만 안전하게 저장할 수 있습니다. 이 범위를 벗어나면, JavaScript는 더 이상 정수를 안전하게 표시할 수 없습니다. 대신 배정밀도 부동 소수점 근사값으로 표시됩니다. `Number.isSafeInteger()`를 사용하여 숫자가 안전한 정수 범위 내에 있는지 확인할 수 있습니다.

±(2-1074 to 21024) 범위를 벗어나는 값은 자동으로 변환됩니다.

* `Number.MAX_VALUE`보다 큰 양수값은 `+Infinity`로 변환됩니다.
* `Number.MIN_VALUE`보다 작은 양수값은 `+0`으로 변환됩니다.
* `Number.MAX_VALUE`보다 작은 음수값은 `-Infinity`로 변환됩니다.
* `Number.MIN_VALUE`보다 큰 음수값은 `-0`으로 변환됩니다.

`+Infinity` 및 `-Infinity`는 수학에서의 무한대와 유사하게 작동하지만, 약간의 차이가 있습니다. 자세한 내용은 `Number.POSITIVE_INFINITY` 및 `Number.NEGATIVE_INFINITY`를 참고하세요.

Number 타입에는 여러 표현이 있는 하나의 값만 있습니다. `0`은 `-0`과 `+0` 둘 다로 표현됩니다(여기서 `0`은 `+0`의 별칭입니다). 실제로는, 서로 다른 표현 간에 거의 차이가 없습니다. 예를 들어, `+0 === -0`은 `true`입니다. 그러나, 0으로 나누면 다음과 같이 알 수 있습니다.

```js
console.log(42 / +0); // Infinity
console.log(42 / -0); // -Infinity
```

`NaN` ("**N**ot **a** **N**umber")는 산술 연산의 결과를 숫자로 표현할 수 없을 때, 일반적으로 발생하는 특별한 종류의 숫자 값입니다. 또한, "NaN" 자기 자신과 같지 않은 JavaScript의 유일한 값이기도 합니다.

숫자는 개념적으로 "수학적인 값"이고 항상 암시적으로 부동 소수점으로 인코딩되지만, JavaScript는 비트 연산자를 제공합니다. 비트 연산자를 적용할 때 숫자는 먼저 32비트 정수로 변환됩니다.

**참고:** 비트 마스킹을 사용해서 하나의 숫자 안에 다수의 불리언 값을 나타낼 때 비트 연산자를 사용할 수 있긴 하지만 이건 보통 나쁜 방법으로 여겨집니다. JavaScript는 일련의 불리언 값들을 나타내는 방법을 (배열이나 불리언 속성 값을 할당한 객체로) 제공합니다. 비트 마스킹은 코드를 읽고, 이해하고, 유지하기 힘들게 만듭니다.

다만 로컬 저장소의 한정된 공간을 활용해야 한다거나, 네트워크의 비트 하나하나가 소중한 극한 상황처럼 제한된 환경에서는 이런 기술이 필요할 수도 있습니다. 비트 마스킹은 용량 최적화의 마지막 수단으로만 고려해야 합니다.

### BigInt 타입

`BigInt` 타입은 임의 정밀도로 정수를 나타낼 수 있는 JavaScript 숫자 원시 값입니다. BigInt로 Number의 안전한 정수 제한(`Number.MAX_SAFE_INTEGER`)을 넘어서는 큰 정수도 안전하게 저장하고 연산할 수 있습니다.

BigInt는 정수 끝에 `n`을 추가하거나 `BigInt()` 함수를 호출해 생성할 수 있습니다.

다음 예제는 `Number.MAX_SAFE_INTEGER`를 증가시키면, 예상된 값을 반환하는 것을 보여줍니다.

```js
// BigInt
const x = BigInt(Number.MAX\_SAFE\_INTEGER); // 9007199254740991n
x + 1n === x + 2n; // 9007199254740992n는 9007199254740993n과 같지 않아 false입니다.

// Number
Number.MAX\_SAFE\_INTEGER + 1 === Number.MAX\_SAFE\_INTEGER + 2; // 둘 다 9007199254740992 이기 때문에 true입니다.
```

`+`, `*`, `-`, `**`, `%` 연산자를 BigInt에서도 사용할 수 있습니다. 금지된 연산자는 `>>>` (en-US)뿐 입니다. BigInt는 Number와 엄격하게 같지는 (en-US) 않지만 느슨하게 유사합니다.

BigInt는 소수를 나타낼 수 없지만, 큰 정수를 더 정확하게 나타낼 수 있기 때문에, BigInt 값은 숫자보다 항상 더 정확하거나 덜 정확하지 않습니다. 어떤 타입도 다른 타입을 수반하지 않으며, 서로 대체할 수 없습니다. `TypeError`는 BigInt 값이 산술 표현식의 일반 숫자와 혼합되거나 서로 암시적으로 변환되는 경우 발생합니다.

### String 타입

`String` 타입은 텍스트 데이터를 나타내며, UTF-16 코드 단위 수를 나타내는 16비트 부호 없는 정수 값의 나열로 인코딩됩니다. String의 각 요소는 String 내부의 위치를 차지합니다. 첫 번째 요소는 인덱스 `0`에, 다음 요소는 인덱스 `1`에 있습니다. String의 길이는 UTF-16 코드 단위의 수이며, 실제 유니코드 문자 수와 일치하지 않을 수 있습니다. 자세한 내용은 `String` 페이지를 참조하세요.

JavaScript String은 변경할 수 없습니다. 즉, String이 생성되면 수정할 수 없습니다. String 메서드는 현재 String의 내용을 기반으로 새 String을 만듭니다. 예를 들면, 다음과 같습니다.

* `substring()`을 사용해 원래 String의 하위 String을 만들 수 있습니다.
* 연결 연산자(`+`) 또는 `concat()`를 사용하여 두 문자열을 연결합니다.

#### "문자열의 타입화"를 조심하라

문자열을 사용해 복잡한 데이터를 표현하는 것이 매력적으로 보일지도 모르고, 단기적으로는 다음과 같은 장점이 있습니다.

* 연결 연산자를 통해 복잡한 문자열을 쉽게 만들 수 있습니다.
* 문자열은 디버깅이 쉽습니다. (출력 내용이 항상 문자열의 값과 동일)
* 문자열은 많은 API(입력 칸 (en-US), 로컬 스토리지 값, `responseText`와 함께 사용하는 `XMLHttpRequest` 등등)의 공통 분모이며 문자열로만 작업하고 싶을 수 있습니다.

규칙을 통해, 어떤 자료구조라도 문자열로 표현할 수 있습니다. 그러나 그게 좋은 방법은 아닙니다. 예를 들어, 구분자를 사용하면 (물론 JavaScript 배열이 더 적합하겠지만) 문자열로 리스트를 흉내낼 수도 있을 것입니다. 그러나 구분자를 리스트의 요소로 사용하는 순간 리스트가 망가지고 맙니다. 이제 구분자를 구분하기 위해 이스케이프 문자를 선택하고, 등등... 이 모든 것이 각자의 규칙을 필요로 하고 불필요한 유지보수 부담이 발생합니다.

문자열은 텍스트 데이터에만 사용하세요. 복잡한 데이터를 표현해야 할 땐 문자열을 구문 분석하고 적합한 추상화를 사용하세요.

### Symbol 타입

`Symbol`은 **고유**하고 **변경 불가능한** 원시 값이며 객체의 속성(아래를 참고하세요) 키로 사용할 수 있습니다. 어떤 프로그래밍 언어들에선 "원자"라고 부르기도 합니다. 기호의 목적은 다른 코드의 키와 충돌하지 않도록 보장되는 고유한 속성 키를 만드는 것입니다.

객체
--

컴퓨터 과학에서의 객체란 식별자로 참조할 수 있는 메모리 상의 값을 말합니다. JavaScript에서 객체는 유일한 변경 가능한 값입니다. Functions는 사실 callable 이라는 추가 기능이 있는 객체이기도 합니다.

### 속성

JavaScript에서의 객체는 속성의 컬렉션으로 볼 수 있습니다. 객체 리터럴 구문을 사용해 제한적으로 속성을 초기화할 수의 있고, 그 후에 속성을 추가하거나 제거할 수도 있습니다. 객체 속성은 키-값 쌍과 동일합니다. 속성 키는 strings타입 또는 symbols타입이 될 수 있습니다. 속성 값으로는 다른 객체를 포함해 모든 타입을 사용할 수 있으므로 복잡한 자료구조의 구축이 가능합니다.

객체 속성에는 데이터 속성과 접근자 속성 두 종류가 있습니다. 각각의 속성에는 다시 '특성'(attribute)들이 존재합니다. 특성은 JavaScript 엔진 내부에서는 접근되지만, `Object.defineProperty()`를 통해 설정하거나, `Object.getOwnPropertyDescriptor()` 를 통해 읽을 수 있습니다.

`Object.defineProperty()`에서 더 알아보세요.

#### 데이터 속성

데이터 속성은 키를 값과 연결하며, 다음과 같은 특성을 가집니다.

* `value`
    + : 속성의 get 접근으로 검색된 값입니다. 모든 JavaScript의 값이 볼 수 있습니다.
* `writable`
    + : 할당으로 속성을 변경할 수 있는지 여부를 나타내는 불리언 값입니다.
* `enumerable`
    + : A boolean value indicating if the property can be enumerated by a `for...in` loop. See also Enumerability and ownership of properties (en-US) for how enumerability interacts with other functions and syntaxes.
    + : 속성을 `for...in` 루프로 열거할 수 있는지 여부를 나타내는 불리언 값입니다. 열거 가능성이 다른 함수 및 구문과 상호 작용하는 방식에 대해서는 속성 열거 가능성 및 소유권 (en-US)을 참조하세요.
* `configurable`
    + : 속성을 삭제할 수 있는지, 접근자 속성으로 변경할 수 있는지, 속성을 변경할 수 있는지를 나타내는 불리언 값입니다.

#### 접근자 속성

접근자 속성은 키를 두 개의 접근자 함수(`get`, `set`) 중 하나와 연결하여 값을 가져오거나 저장합니다.

**참고:** 접근자 '메서드'가 아니라 접근자 '속성'임을 인지하는 것이 중요합니다. 함수를 값으로 사용하여 JavaScript 객체에 클래스처럼 접근자를 부여할 수 있지만, 그렇다고 그 객체가 클래스로 바뀌는 것은 아닙니다.

접근자 속성은 다음과 같은 특성을 가집니다.

`get`

값에 대한 get 접근이 수행될 따마다 속성 값을 검색하기 위해 비어 있는 인수 목록으로 호출되는 함수입니다. getters를 참고하세요. `undefined`일 수 있습니다.

`set`

할당된 값을 포함하는 인수로 호출되는 함수입니다. 지정된 속성을 변경하려고 시도할 때마다 실행됩니다. setters도 참고하세요. `undefined`일 수 있습니다.

`enumerable`

속성을 `for...in` 루프로 열거할 수 있는지 여부를 나타내는 불리언 값입니다. 열거 가능성이 다른 함수 및 구문과 상호 작용하는 방식에 대해서는 속성 열거 가능성 및 소유권 (en-US)을 참조하세요.

`configurable`

속성을 삭제할 수 있는지, 데이터 속성으로 변경할 수 있는지, 속성을 변경할 수 있는지를 나타내는 불리언 값입니다.

객체의 prototype은 다른 객체 또는 `null`을 가리킵니다. 이는 개념적으로 객체의 숨겨진 속성이며, 일반적으로 `[[Prototype]]`으로 표시됩니다. 객체의 `[[Prototype]]`속성은 객체 자체에서도 접근할 수 있습니다.

객체는 임시 키-값 쌍이므로, 종종 맵으로 사용됩니다. 그러나 인체 공학, 보안 및 성능 문제가 있을 수 있습니다. 대신 임의의 데이터를 저장하려면, `Map`을 사용하세요. `Map` 참조에는 키-값 연결을 저장하기 위한 일반 객체와 Map 간의 장단점에 대한 자세한 설명이 포함되어 있습니다.

### 날짜

날짜와 시간을 나타낼 때의 가장 좋은 선택은 JavaScript 내장 `Date` 유틸리티를 사용하는 것입니다.

### 인덱스 컬렉션: 배열과 형식화 배열

배열은 정수 키를 가진 속성과 `length` 속성 사이에 특별한 연관을 지어놓은 일반 객체입니다.

이에 더해, 배열은 배열을 조작할 수 있는 몇 가지 편리한 메서드를 제공하는 `Array.prototype`에서 상속됩니다. 예를 들어, `indexOf()`는 배열에서 값을 탐색하고, `push()`는 배열에 요소를 추가합니다. 따라서 배열은 정렬된 목록을 나타내는 완벽한 후보가 됩니다.

형식화 배열(Typed Arrays)은 안쪽의 이진 데이터 버퍼에 대해 배열과 같은 뷰를 제공하고, 배열과 의미 체계가 유사한 많은 메서드를 제공합니다. "(형식화 배열)Typed Array"은 `Int8Array`, `Float32Array` 등을 비롯한 다양한 데이터 구조를 가리키는 포괄적인 용어입니다. 자세한 내용은 typed array을 참고하세요. Typed Array는 종종 `ArrayBuffer` 및 `DataView`와 함께 사용됩니다.

### 키 컬렉션: Maps, Sets, WeakMaps, WeakSets

키 컬렉션 자료구조는 객체 참조를 키로 가집니다. `Set` (en-US)과 `WeakSet`은 고유한 값의 모음을 나타내고, `Map`과 `WeakMap`은 객체와 값을 연결 짓는 쌍들의 모음을 나타냅니다.

`Map`과 `Set`을 직접 구현할 수 있습니다. 그러나 객체를 직접 비교(`<`, '작음' 비교와 같이)할 방법은 없고, 엔진도 객체에 대한 해시 함수를 노출하지 않기 때문에, 조회 성능이 필연적으로 선형입니다. (`WeakMap`을 포함해) 네이티브 구현은 상수 시간에 대한 로그함수의 조회 성능을 가질 수 있습니다.

보통 DOM 노드에 데이터를 연결할 땐 해당 객체에 직접 속성을 추가하거나 `data-*` 특성을 사용하겠지만, 동일한 컨텍스트에서 이렇게 추가한 데이터를 모든 스크립트에서 다 사용할 수 있다는 문제가 있습니다. `Map`과 `WeakMap`을 사용하면 비공개 데이터를 객체에 쉽게 바인딩 할 수 있습니다.

`WeakMap` 및 `WeakSet`은 가비지 컬렉션이 가능한 객체 또는 등록되지 않은 기호만 키로 허용하며, 키가 컬렉션에 남아있어도 가비지 컬렉션할 수 있습니다. 특히 메모리 사용량 최적화에 사용됩니다.

### 구조화된 자료: JSON

JSON(**J**ava**S**cript **O**bject **N**otation)은 경량 데이터 교환 형식으로, JavaScript에서 파생됐지만 많은 프로그래밍 언어에서 사용하고 있습니다. JSON은 다양한 환경과 언어 간에 전송할 수 있는 범용 데이터 구조를 구성합니다. 자세한 내용은 `JSON`를 참조하세요.

### 표준 라이브러리의 더 많은 객체

JavaScript는 내장 객체로 구성된 표준 라이브러리를 포함합니다. 내장 객체에 대해 자세히 알아보려면 참고서를 읽어보세요.

타입 강제 변환
--------

위에서 언급했듯이, JavaScript는 약타입 언어입니다. 즉, 다른 타입이 예상되는 하나의 타입의 값을 자주 사용할 수 있으며, 언어에서 이를 적합한 타입으로 변환해줍니다. 이를 위해, JavaScript는 몇 가지 강제 변환 규칙을 정의합니다.

### 원시 타입 강제 변환

원시 타입 강제 변환 프로세스는 원시 값이 예상되는 경우에 사용되지만, 실제 타입이 무엇이어야 하는지에 대한 강력한 선호도는 없습니다. 일반적으로 string, number 또는 BigInt이 동등하게 허용되는 경우입니다. 예를 들면 아래와 같습니다.

* `Date()` 생성자는 `Date` 인스턴스가 아닌 하나의 인수를 받는 경우, String은 날짜 String을 나타내는 반면, 숫자는 타임스탬프를 나타냅니다.
* `+` 연산자, 하나의 피연산자가 String이면 String 연결이 수행됩니다.
* `==` 연산자, 피연산자 중 하나가 원시 타입이고 다른 피연산자는 객체인 경우, 객체는 선호 타입이 없는 원시 값으로 변환됩니다.

이 작업은 값이 이미 원시 타입인 경우, 변환을 수행하지 않습니다. 객체는 `[@@toPrimitive]()` (힌트로 `"default"` 사용), `valueOf()`, `toString()` 메서드를 차례로 호출하여 원시 타입으로 변환됩니다. 원시 타입 변환은 `toString()` 이전에 `valueOf()`를 호출하는데, 이는 숫자 강제 변환의 동작과 비슷하지만, string 강제 변환과는 다릅니다.

`[@@toPrimitive]()` 메서드가 있는 경우, 원시 타입을 반환해야 합니다. 객체를 반환하면 `TypeError`가 발생합니다. `valueOf()` 및 `toString()`의 경우, 하나가 객체를 반환하면 반환 값은 무시되고 다른 하나의 반환 값이 대신 사용됩니다. 둘 다 존재하지 않거나, 원시 타입을 반환하지 않으면 `TypeError`가 발생합니다. 다음 코드를 예로 들 수 있습니다.

```js
console.log({} + []); // "[object Object]"
```

`{}` 또는 `[]`에는 `[@@toPrimitive]()` 메서드가 없습니다. `{}` 및 `[]` 모두 객체 자체를 반환하는 `Object.prototype.valueOf`에서 `valueOf()`를 상속합니다. 반환 값은 객체이므로 무시됩니다. 따라서 `toString()`이 대신 호출됩니다. `{}.toString()`은 `"[object Object]"`를 반환하는 반면, `[].toString()`는 `""`를 반환하므로, 결과는 연결된 값인 `"[object Object]"`입니다.

`[@@toPrimitive]()` 메서드는 원시 타입으로 변환할 때 항상 우선합니다. 원시 타입 변환은 일반적으로 `valueOf()`가 우선적으로 호출되기 때문에, 숫자 강제 변환과 같이 동작합니다. 그러나 사용자 지정 `[@@toPrimitive]()` 메서드가 있는 객체는 모든 원시 타입을 반환하도록 선택할 수 있습니다. `Date` 및 `Symbol` 객체는 `[@@toPrimitive]()` 메서드를 재정의하는 유일한 내장 객체입니다. `Date.prototype[@@toPrimitive]()`는 `"default"` 힌트를 `"string"`인 것처럼 취급하는 반면, `Symbol.prototype[@@toPrimitive]()`는 힌트를 무시하고 항상 기호(symbol)을 반환합니다.

### 숫자 강제 변환

Number 및 BigInt의 두 가지 숫자 타입이 있습니다. 때때로 언어는 특별히 숫자 또는 BigInt(예: 인덱스가 숫자여야 하는 `Array.prototype.slice()`)를 기대합니다. 다른 경우에는, 둘 중 하나를 허용하고 피연산자의 타입에 따라 다른 작업을 수행할 수 있습니다. 다른 타입의 암시적 변환을 허용하지 않는 엄격한 강제 변환 프로세스는 숫자 강제 변환 및 BigInt 강제 변환을 참조하세요.

숫자 강제 변환은 BigInt가 `TypeError`를 발생시키는 대신 있는 그대로 반환된다는 점을 제외하면 수 강제 변환(number coercion)하고 거의 동일합니다. 숫자 강제 변환은 Number와 BigInt 모두에 대해 오버로딩되기 때문에, 모든 산술 연산자에서 사용됩니다. 유일한 예외는 항상 숫자 강제 변환을 수행하는 단항 더하기입니다.

### 기타 강제 변환

Null, Undefined 및 Symbol을 제외한 모든 데이터 타입에는 각각의 강제 변환 프로세스가 있습니다. 자세한 내용은 string 강제 변환, 불리언(boolean) 강제 변환 및 객체 강제 변환에서 확인하세요.

눈치채셨겠지만, 객체를 원시 타입으로 변환할 수 있는 세 가지 경로가 있습니다.

* 원시 타입 강제 변환: `[@@toPrimitive]("default")` → `valueOf()` → `toString()`
* 숫자 강제 변환, number coercion, BigInt coercion: `[@@toPrimitive]("number")` → `valueOf()` → `toString()`
* 문자열 강제 변환: `[@@toPrimitive]("string")` → `toString()` → `valueOf()`

모든 경우에, `[@@toPrimitive]()`이 있으면 호출 가능하고, 원시 타입을 반환해야 하며, `valueOf` 또는 `toString`은 호출 가능하지 않거나 객체를 반환하는 경우 무시됩니다. 프로세스가 끝나고, 성공하면 결과가 원시 타입임을 보장합니다. 결과 원시 타입은 컨텍스트에 따라 추가 강제 적용을 받습니다.

같이 보기
-----

* Oleksii Trekhleb의 JavaScript 데이터 구조 및 알고리즘
* Nicholas Zakas의 JavaScript 공통 데이터 구조 및 알고리즘 모음


문 및 선언 - JavaScript

문 및 선언
======

JavaScript 응용 프로그램은 적절한 구문을 갖는 문으로 구성됩니다. 한 문이 여러 줄에 걸칠 수 있습니다. 여러 문은 각 문이 세미콜론으로 구분된 경우 한 줄에 나올 수 있습니다. 이는 키워드 하나가 아니라, 키워드 그룹입니다.

항목별 문 및 선언
----------

알파벳순 목록은 왼쪽 사이드바를 보세요.

### 흐름 제어

`Block`

블록문은 0개 이상의 문을 묶을 때 쓰입니다. 블록은 중괄호 한 쌍으로 구분됩니다.

`break`

현재 루프, `switch` 또는 `label` 문을 종료하고 프로그램 제어를 종료된 문의 다음 문으로 넘겨줍니다.

`continue`

현재 또는 레이블 달린 루프의 현재 반복 중인 문의 실행을 종료하고 루프의 실행은 다음 반복으로 이어집니다.

`empty`

empty 문은 내용이 없는 빈 문을 제공하기 위해 사용됩니다, 비록 JavaScript 구문이 문을 기대할 것이지만.

`if...else`

지정된 조건이 true면 문을 실행. 조건이 false인 경우, 다른 문이 실행될 수 있습니다.

`switch` (en-US)

식의 값이 case 절과 일치하는지 식을 평가하고 case 절과 관련된 문을 실행합니다.

`throw`

사용자 정의 예외가 발생합니다.

`try...catch` (en-US)

시도(try)할 문 블록을 표시하고 예외가 발생되어야 하는 응답을 지정합니다.

### 선언

`var`

변수를 선언합니다, 변수를 값으로 초기화할 수 있습니다.

`let`

블록 범위 지역 변수를 선언합니다, 변수를 값으로 초기화할 수 있습니다.

`const`

읽기 전용 유명(named) 상수를 선언합니다.

### 함수 및 클래스

`function`

지정된 매개변수를 갖는 함수를 선언합니다.

`function*`

반복기 (en-US)를 더 쉽게 작성할 수 있게 하는 생성기 함수.

`return`

함수에 의해 반환되는 값을 지정합니다.

`class`

클래스를 선언합니다.

### 반복

`do...while`

테스트 조건이 거짓으로 평가될 때까지 지정된 문을 실행하는 루프를 만듭니다. 조건은 문을 실행한 후 평가됩니다, 그 결과 지정된 문은 적어도 한 번 실행됩니다.

`for`

괄호로 묶이고 세미콜론으로 구분된 선택사항 식 셋으로 구성된 루프를 만듭니다, 루프에서 실행되는 문이 뒤따릅니다.

`for each...in`
지원이 중단되었습니다

비표준

객체의 모든 속성값에 대해 지정된 변수를 반복합니다. 각 개별 속성에 대해, 지정된 문이 실행됩니다.

`for...in`

임의의 순서로 객체의 열거 속성을 반복합니다. 각 개별 속성에 대해, 문은 실행될 수 있습니다.

`for...of`

반복 가능한 객체 (배열, 배열 같은 객체, 반복기 및 생성기 포함) 를 반복합니다, 각 개별 속성값에 대해 실행되는 문을 가진 사용자 정의 반복 후크를 호출하는.

`while`

테스트 조건이 true로 평가되는 한 지정된 문을 실행하는 루프를 만듭니다. 조건은 문을 실행하기 전에 평가됩니다.

### 기타

`debugger`

이용 가능한 디버깅 기능을 호출합니다. 이용 가능한 기능이 없는 경우, 이 문은 아무 효과가 없습니다.

`export`

외부 모듈, 다른 스크립트에 가져올(import) 수 있도록 함수를 내보내(export)는데 사용됩니다.

`import`

외부 모듈, 다른 스크립트에서 내보낸 함수를 가져오는데 사용됩니다.

`label`

`break` 또는 `continue` 문을 사용하여 참조할 수 있는 식별자 있는 문을 제공합니다.

`with` (en-US)
지원이 중단되었습니다

문의 스코프 체인을 확장합니다.

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # sec-async-function-definitions |
| ECMAScript Language Specification # sec-async-generator-function-definitions |
| ECMAScript Language Specification # sec-block |
| ECMAScript Language Specification # sec-break-statement |
| ECMAScript Language Specification # sec-class-definitions |
| ECMAScript Language Specification # sec-let-and-const-declarations |
| ECMAScript Language Specification # sec-continue-statement |
| ECMAScript Language Specification # sec-debugger-statement |
| ECMAScript Language Specification # sec-do-while-statement |
| ECMAScript Language Specification # sec-empty-statement |
| ECMAScript Language Specification # sec-exports |
| ECMAScript Language Specification # sec-for-statement |
| ECMAScript Language Specification # sec-for-in-and-for-of-statements |
| ECMAScript Language Specification # sec-function-definitions |
| ECMAScript Language Specification # sec-generator-function-definitions |
| ECMAScript Language Specification # sec-if-statement |
| ECMAScript Language Specification # sec-imports |
| ECMAScript Language Specification # sec-labelled-statements |
| ECMAScript Language Specification # sec-return-statement |
| ECMAScript Language Specification # sec-switch-statement |
| ECMAScript Language Specification # sec-throw-statement |
| ECMAScript Language Specification # sec-try-statement |
| ECMAScript Language Specification # sec-variable-statement |
| ECMAScript Language Specification # sec-while-statement |
| ECMAScript Language Specification # sec-with-statement |

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

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

같이 보기
-----

* 연산자


표준 내장 객체 - JavaScript

표준 내장 객체
========

이 장은 JavaScript의 모든 표준 내장 객체와 그 메서드 및 속성을 나열합니다.

표준 내장 객체와 **전역 객체**를 헷갈리지 않도록 주의하세요. 표준 내장 객체는 **전역 범위의 여러 객체**를 일컫습니다. 전역 객체는 엄격 모드를 사용하지 않을 땐 전역 범위에서 `this`, 지원하는 환경에선 `globalThis`를 사용해 접근할 수 있는 객체입니다. 사실 전역 범위는 **전역 객체와 전역 객체가 상속한 속성**으로 이루어집니다.

전역 범위의 나머지 객체는 사용자 스크립트가 생성하거나, 호스트 응용 프로그램이 제공합니다. 브라우저 맥락에서 사용 가능한 호스트 객체는 API 참고서에서 읽을 수 있습니다. DOM (en-US) 및 코어 JavaScript의 차이에 관한 자세한 정보는 JavaScript 기술 개요를 참고하세요.

항목별 표준 객체
---------

### 값 속성

아래 전역 속성은 간단한 값을 반환하며 속성이나 메서드를 가지고 있지 않습니다.

* `Infinity`
* `NaN`
* `undefined`
* `globalThis`
### 함수 속성

객체에 붙지 않고 전역으로 호출하는 함수로, 반환 값을 호출자에게 바로 반환합니다.

* `eval()`
* `isFinite()`
* `isNaN()`
* `parseFloat()`
* `parseInt()`
* `encodeURI()`
* `encodeURIComponent()`
* `decodeURI()`
* `decodeURIComponent()`
* **Deprecated**
    + `escape()` (en-US)
    지원이 중단되었습니다
    + `unescape()` (en-US)
    지원이 중단되었습니다
### 기초 객체

다른 모든 객체의 기반이 되는 기초이자 기본 객체입니다. 일반 객체, 함수, 오류를 나타내는 객체를 포함합니다.

* `Object`
* `Function`
* `Boolean`
* `Symbol`

#### 오류 객체

오류 객체는 기초 객체의 특별한 유형으로, 기본적인 `Error` 객체와 함께 특정 용도에 최적화된 오류 형태도 포함합니다.

* `Error`
* `AggregateError`
* `EvalError`
* `InternalError`
비표준
* `RangeError`
* `ReferenceError`
* `SyntaxError`
* `TypeError`
* `URIError`
### 숫자 및 날짜

숫자, 날짜, 수학 계산을 나타내는 기본 객체입니다.

* `Number`
* `BigInt`
* `Math`
* `Date`
### 텍스트 처리

문자열을 나타내는 객체로 문자열을 조작할 방법도 제공합니다.

* `String`
* `RegExp`
### 인덱스 콜렉션

인덱스 값으로 정렬된 데이터의 콜렉션을 나타냅니다. 배열(형식배열 포함)과 배열형 객체를 포함합니다.

* `Array`
* `Int8Array`
* `Uint8Array`
* `Uint8ClampedArray`
* `Int16Array`
* `Uint16Array`
* `Int32Array`
* `Uint32Array`
* `Float32Array`
* `Float64Array`
* `BigInt64Array`
* `BigUint64Array`
### 키 콜렉션

키를 사용하는 콜렉션을 나타냅니다. `Map`, `Set` (en-US) 등 순회 가능한 콜렉션은 요소를 삽입 순서대로 순회할 수 있습니다.

* `Map`
* `Set` (en-US)
* `WeakMap`
* `WeakSet`
### 구조화된 데이터

구조화된 데이터 버퍼 및 JavaScript Object Notation(JSON)을 사용하여 작성한 데이터를 나타내고 상호작용합니다.

* `ArrayBuffer`
* `SharedArrayBuffer`
* `Atomics`
* `DataView`
* `JSON`
### 제어 추상화 객체

제어 추상화는 코드 구조화에 도움을 줍니다. 특히, 비동기 코드를 (예를 들어) 깊게 중첩된 콜백 함수 없이 작성할 수 있습니다.

* `Promise`
* `Generator`
* `GeneratorFunction`
* `AsyncFunction`
* `AsyncGenerator` (en-US)
* `AsyncGeneratorFunction` (en-US)
### 리플렉션

* `Reflect`
* `Proxy`
### 국제화

ECMAScript 코어에 추가된 언어 구분 기능입니다.

* `Intl` (en-US)
* `Intl.Collator` (en-US)
* `Intl.DateTimeFormat`
* `Intl.ListFormat` (en-US)
* `Intl.NumberFormat`
* `Intl.PluralRules` (en-US)
* `Intl.RelativeTimeFormat` (en-US)
* `Intl.Locale` (en-US)


Trailing commas - JavaScript

Trailing commas
===============

**Trailing commas** ("final commas"라고도 불립니다)는 새로운 엘리먼트나 매개변수, 속성을 JavaScript 코드에 추가할 때 유용합니다. 새로운 속성을 추가할 때, 마지막 줄에 trailing comma가 있다면 그 줄을 수정 없이 그대로 복사해 쓸 수 있습니다. 이외에도 버전 관리 이력이 간단해지고 코드 편집이 더 편해진다는 장점이 있습니다.

JavaScript는 초기부터 배열 리터럴에 trailing comma를 허용했으며, ECMAScript 5부터는 객체 리터럴, ECMAScript 2017부터는 함수의 매개변수에도 허용하기 시작했습니다.

그러나 JSON에서는 trailing comma를 허용하지 않습니다.

리터럴에서의 trailing comma
---------------------

### 배열

JavaScript는 배열에 나타나는 trailing comma를 무시합니다.

```js
var arr = [1, 2, 3];

arr; // [1, 2, 3]
arr.length; // 3
```

trailing comma가 여러 개 있을 경우 빈 슬롯("구멍")이 생깁니다. 구멍이 있는 배열을 성기다(sparse)고 합니다(조밀한(dense) 배열에는 구멍이 없습니다). `Array.prototype.forEach()`나 `Array.prototype.map()`을 이용해 배열을 순회할 때는 빈 슬롯을 무시합니다.

```js
var arr = [1, 2, 3, , ,];
arr.length; // 5
```

### 객체

ECMAScript 5부터는 객체 리터럴에도 trailing comma를 사용할 수 있습니다.

```js
var object = {
  foo: "bar",
  baz: "qwerty",
  age: 42,
};
```

함수에서의 trailing comma
--------------------

ECMAScript 2017에서는 함수의 매개변수 목록에 trailing comma를 허용합니다.

### 매개변수 정의

아래의 두 함수 정의는 모두 유효하며, 서로 같습니다. Trailing comma는 함수 정의의 `length` 속성이나 `arguments` 객체에 영향을 주지 않습니다.

```js
function f(p) {}
function f(p,) {}

(p) => {};
(p,) => {};
```

Trailing comma는 클래스나 객체의 메소드 정의에도 사용할 수 있습니다.

```js
class C {
  one(a,) {},
  two(a, b,) {},
}

var obj = {
  one(a,) {},
  two(a, b,) {},
};
```

### 함수 호출

아래의 두 함수 호출은 모두 유효하며, 서로 같습니다.

```js
f(p);
f(p,);

Math.max(10, 20);
Math.max(10, 20,);
```

### 잘못된 trailing comma

함수의 매개변수 정의나 호출에 쉼표만 있을 경우 `SyntaxError`가 발생합니다. 또한, rest 매개변수를 사용할 때는 trailing comma를 사용할 수 없습니다.

```js
function f(,) {} // SyntaxError: missing formal parameter
(,) => {};       // SyntaxError: expected expression, got ','
f(,)             // SyntaxError: expected expression, got ','

function f(...p,) {} // SyntaxError: parameter after rest parameter
(...p,) => {}        // SyntaxError: expected closing parenthesis, got ','
```

구조 분해 할당에서의 trailing comma
--------------------------

구조 분해 할당의 좌변에도 trailing comma를 사용할 수 있습니다.

```js
// Trailing comma가 있는 배열 구조 분해
[a, b,] = [1, 2];

// Trailing comma가 있는 객체 구조 분해
var o = {
  p: 42,
  q: true,
};
var {p, q,} = o;
```

Rest 원소가 있을 경우 역시 `SyntaxError`가 발생합니다.

```js
var [a, ...b,] = [1, 2, 3];
// SyntaxError: rest element may not have a trailing comma
```

JSON에서의 trailing comma
----------------------

객체 안에서의 trailing comma는 ECMAScript 5에 와서야 추가되었습니다. JSON은 ES5 이전의 JavaScript 문법을 기초로 하므로 **JSON에서는 trailing comma를 사용할 수 없습니다**.

아래의 두 줄 모두 `SyntaxError`를 발생합니다.

```js
JSON.parse("[1, 2, 3, 4, ]");
JSON.parse('{"foo" : 1, }');
// SyntaxError JSON.parse: unexpected character
// at line 1 column 14 of the JSON data
```

JSON을 올바르게 파싱하려면 trailing comma를 제거해야 합니다.

```js
JSON.parse("[1, 2, 3, 4 ]");
JSON.parse('{"foo" : 1 }');
```

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # prod-Elision |
| ECMAScript Language Specification # prod-ObjectLiteral |
| ECMAScript Language Specification # prod-ArrayLiteral |
| ECMAScript Language Specification # prod-Arguments |
| ECMAScript Language Specification # prod-FormalParameters |
| ECMAScript Language Specification # prod-CoverParenthesizedExpressionAndArrowParameterList |
| ECMAScript Language Specification # prod-NamedImports |
| ECMAScript Language Specification # prod-NamedExports |
| ECMAScript Language Specification # prod-QuantifierPrefix |
| ECMAScript Language Specification # prod-annexB-InvalidBracedQuantifier |

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

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

같이 보기
-----

* Initial ECMAScript proposal: trailing function commas by Jeff Morrison


함수 - JavaScript

함수
==

보통 함수란 자신의 외부(재귀 함수의 경우 스스로) 코드가 호출할 수 있는 "하위 프로그램"입니다. 프로그램과 마찬가지로, 함수 역시 명령문의 시퀀스로 구성된 함수 본문을 가집니다. 함수에 값을 전달하면, 함수는 값을 반환할 것입니다.

JavaScript에서 함수는 다른 함수로 전달되거나 반환받을 수 있고, 변수와 속성을 할당받을 수도 있기 때문에 일급 객체에 해당합니다. 또한 다른 객체와 마찬가지로 속성과 메서드를 가질 수 있습니다. 다른 객체와 구별되는 점은 함수를 호출할 수 있다는 점입니다.

JavaScript 함수 안내서에서 더 많은 예제와 설명을 확인하세요.

설명
--

함수 값은 일반적으로 `함수`의 인스턴스입니다. `함수` 객체의 속성 및 메서드에 대한 자세한 내용은 `Function`을 참조하세요. 호출 가능한 값으로 인해 `typeof`가 `"객체"` 대신 `"함수"`를 반환하게 됩니다.

**참고:** 모든 호출 가능한 값이 `instanceof Function`인 것은 아닙니다. 예를 들어, `Function.prototype` 객체는 호출 가능하지만 `Function`의 인스턴스는 아닙니다. 함수의 프로토타입 체인을 수동으로 설정하여 함수가 더 이상 `Function.prototype`에서 상속되지 않도록 할 수도 있습니다. 그러나 이러한 경우는 극히 드뭅니다.

### 반환 값

함수 실행이 `return` 문에서 끝나지 않거나 `return` 키워드 뒤에 표현식이 없는 경우 반환 값은 `undefined`가 됩니다. `return`문을 사용하면 함수에서 임의의 값을 반환할 수 있습니다. 하나의 함수 호출은 하나의 값만 반환할 수 있지만, 객체 또는 배열을 반환하고 그 결과를 구조 분해하여 여러 값을 반환하는 효과를 나타낼 수 있습니다.

**참고:** `new`로 호출되는 생성자에는 반환값을 결정하는 다른 로직이 있습니다.

### 인수 전달

매개변수와 전달인자의 의미는 약간 다르지만 MDN 웹 문서에서는 종종 같은 의미로 사용합니다. 간단한 예시입니다.

```js
function formatNumber(num) {
  return num.toFixed(2);
}

formatNumber(2);
```

이 예제에서 `num` 변수는 함수의 매개변수(parameter)라고 불리며, 괄호로 묶인 함수 정의 목록에 선언되어 있습니다. 런타임 유효성 검사 코드를 작성하지 않고는 JavaScript에서 시행할 수 없지만 `num` 매개변수에는 숫자가 들어갈 것입니다. `formatNumber(2)` 호출에서 숫자 `2`는 함수의 인수(argument)입니다. 즉, 함수 호출에서 함수에 실제로 전달되는 값입니다. 인수 값은 함수 내에서 해당 매개변수 이름 또는 `arguments` 객체를 통해 접근할 수 있습니다.

인자는 항상 값에 의한 호출이 이루어지며 절대 참조에 의한 호출이 되지 않습니다. 즉, 함수가 매개변수를 재할당해도 그 값은 함수 외부에서 변경되지 않습니다. 더 정확히 말하면, 객체 인수는 공유에 의한 호출이므로 객체의 속성이 변경되면 변경 사항이 함수 외부에 영향을 미칩니다. 예시를 들어보겠습니다.

```js
function updateBrand(obj) {
  // 객체 값의 변화는 함수 외부에서 볼 수 있습니다.
  obj.brand = "쌍용";
  // 매개 변수를 재할당해도
  // 함수 외부의 변수 값에는 영향을 미치지 않습니다.
  obj = null;
}

const car = {
  brand: "현대",
  model: "엑셀",
  year: 1994,
};

console.log(car.brand); // 현대

// 객체 참조를 함수에 전달합니다.
updateBrand(car);

// updateBrand의 호출로 car 객체의 값이 변합니다.
console.log(car.brand); // 쌍용
```

`this` 키워드는 함수가 접근하는 객체를 참조하며, 현재 실행 중인 함수를 참조하는 것이 아니므로 함수 내에서도 함수 값을 이름으로 참조해야 합니다.

### 함수 정의하기

크게 보면 JavaScript에는 네 가지 종류의 함수가 있습니다.

* 일반 함수: 무엇이든 반환할 수 있으며, 호출 후 항상 완료까지 실행됩니다.
* Generator 함수: `Generator` 객체를 반환하며, `yield` 연산자를 사용하여 일시 중지 및 재개할 수 있습니다.
* 비동기 함수: `Promise`를 반환하며, `await` 연산자를 사용하여 일시 중지 및 재개할 수 있습니다.
* 비동기 Generator 함수: `AsyncGenerator` (en-US) 객체를 반환하며, `await` 및 `yield` 연산자를 모두 사용할 수 있습니다.

모든 종류의 함수에 대해 세 가지 방법으로 정의할 수 있습니다.

선언

`함수 선언`, `function*`, `async function`, `async function*` (en-US)

표현식

`함수 표현식`, `function*`, `async function 표현식`, `async function*`

생성자

`Function()` (en-US), `GeneratorFunction()` (en-US), `AsyncFunction()` (en-US), `AsyncGeneratorFunction()` (en-US)

또한 화살표 함수와 메서드를 정의하는 특수 구문이 있어 보다 정확한 의미로 사용할 수 있습니다. Classes는 `new` 없이 호출하면 에러가 발생하기 때문에 개념적으로는 함수가 아니지만 `Function.prototype`에서 상속되며 `typeof MyClass === "function"`을 갖습니다.

```js
// 생성자
const multiply = new Function("x", "y", "return x \* y");

// 선언
function multiply(x, y) {
  return x \* y;
} // No need for semicolon here

// 표현식; 변수에 할당되는 익명 함수입니다.
const multiply = function (x, y) {
  return x \* y;
};
// 표현식; 고유한 이름을 가집니다.
const multiply = function funcName(x, y) {
  return x \* y;
};

// 화살표 함수
const multiply = (x, y) => x \* y;

// 메서드
const obj = {
  multiply(x, y) {
    return x \* y;
  },
};
```

모든 구문은 거의 동일한 작업을 수행하지만 몇 가지 미묘한 동작 차이가 있습니다.

* `Function()` 생성자, `function` 표현식, `function` 선언 구문은 본격적인 함수 객체를 생성하며, 이 객체는 `new`로 구성할 수 있습니다. 그러나 화살표 함수와 메서드는 구성할 수 없습니다. 비동기 함수, Generator 함수 및 비동기 Generator 함수는 구문에 관계없이 구성할 수 없습니다.
* `function` 선언은 함수 호이스팅과 같은 함수를 생성합니다. 다른 구문은 함수를 띄우지 않으며 함수 값은 정의 뒤에만 표시됩니다.
* 화살표 함수와 `Function()` 생성자는 항상 익명 함수를 생성하므로 재귀적으로 자신을 쉽게 호출할 수 없습니다. 화살표 함수를 재귀적으로 호출하는 한 가지 방법은 변수에 할당하는 것입니다.
* 화살표 함수 구문에는 `arguments` 또는 `this`에 대한 접근 권한이 없습니다.
* `Function()` 생성자는 지역 변수에 접근할 수 없으며 전역 범위에만 접근할 수 있습니다.
* `Function()` 생성자는 런타임 컴파일을 유발하며 다른 구문보다 속도가 느린 경우가 많습니다.

`function` 표현식의 경우 함수 이름과 함수가 할당되는 변수 사이에 구분이 있습니다. 함수 이름은 변경할 수 없지만 함수가 할당된 변수는 재할당할 수 있습니다. 함수 이름은 함수가 할당된 변수와 다를 수 있으며, 서로 관련이 없습니다. 함수의 이름은 함수 내에서만 사용할 수 있습니다. 함수 외부에서 사용하려고 하면 오류가 발생합니다(또는 동일한 이름이 다른 곳에서 선언된 경우 다른 값을 가져옵니다). 예시를 봅시다.

```js
const y = function x() {};
console.log(x); // 참조 에러: x가 정의되지 않았습니다.
```

반면에 함수가 할당되는 변수는 함수가 선언된 범위를 포함하도록 보장되는 범위에 의해서만 제한됩니다.

함수 선언은 또한 함수 이름과 같은 이름의 변수를 생성합니다. 따라서 함수 표현식으로 정의된 함수와 달리 함수 선언으로 정의된 함수는 자체의 범위뿐만 아니라 정의된 범위에서 그 이름으로 접근할 수 있습니다.

`new Function`으로 정의된 함수는 소스가 동적으로 조직되며, 직렬화할 때 관찰할 수 있습니다. `console.log(new Function().toString())`은 다음과 같습니다.

```js
function anonymous(
) {

}
```

이것은 함수를 컴파일하는 데 사용되는 실제 소스입니다. `Function()` 생성자는 `anonymous`라는 이름의 함수를 생성하지만, 이 이름은 본문의 범위에 추가되지 않습니다. 본문은 전역 변수에만 접근할 수 있습니다. 예를 들어 다음과 같은 경우 오류가 발생합니다.

```js
new Function("alert(anonymous);")();
```

함수 표현식이나 함수 선언에 의해 정의된 함수는 현재 범위를 상속합니다. 즉, 함수는 클로저를 형성합니다. 반면에 `Function` 생성자에 의해 정의된 함수는 모든 함수가 상속하는 전역 범위 외에는 어떤 범위도 상속하지 않습니다.

```js
// p는 전역 변수입니다.
globalThis.p = 5;
function myFunc() {
  // p는 지역 변수입니다.
  const p = 9;

  function decl() {
    console.log(p);
  }
  const expr = function () {
    console.log(p);
  };
  const cons = new Function("\tconsole.log(p);");

  decl();
  expr();
  cons();
}
myFunc();

// Logs:
// 9 ('decl' 함수 선언 (현재 범위))
// 9 ('expr' 함수 표현식 (현재 범위))
// 5 ('cons' 함수 생성자 (전역 범위))
```

함수 표현식과 함수 선언으로 정의된 함수는 한 번만 구문 분석되지만, `Function` 생성자로 정의된 함수는 생성자가 호출될 때마다 전달된 문자열을 매번 구문 분석합니다. 함수 표현식은 매번 클로저를 형성하지만 함수 내부는 다시 구문을 분석하지 않으므로 함수 표현식이 `new Function(...)`보다 여전히 빠릅니다. 따라서 일반적으로 `Function` 생성자는 가능한 한 피해야 합니다.

함수 선언을 표현식 구문에 작성할 때 의도치 않게 함수 표현식으로 바뀔 수 있습니다.

```js
// 함수 선언입니다.
function foo() {
  console.log("FOO!");
}

doSomething(
  // 인수로 전달된 함수 표현식입니다.
  function foo() {
    console.log("FOO!");
  },
);
```

반면에 함수 표현식은 함수 선언으로 바뀔 수도 있습니다. expression statement (en-US)은 `function` 또는 `async function` 키워드로 시작할 수 없으며, 이는 IIFEs(즉시 호출된 함수 표현식)를 구현할 때 흔히 범하는 실수입니다.

```js
function () { // SyntaxError: Function statements require a function name
  console.log("FOO!");
}();

function foo() {
  console.log("FOO!");
}(); // SyntaxError: Unexpected token ')'
```

대신 표현식 구문을 다른 것으로 시작하여 `function` 키워드가 함수 표현식을 명확하게 시작하도록 합니다. 일반적인 옵션으로는 그룹 연산자와 `void` 사용이 있습니다.

```js
(function () {
  console.log("FOO!");
})();

void function () {
  console.log("FOO!");
}();
```

### 함수 매개변수

함수의 매개변수는 함수 내에서 접근할 수 있는 간단한 식별자입니다.

```js
function myFunc(a, b, c) {
  // You can access the values of a, b, and c here
}
```

세 가지의 특별한 매개변수 구문이 있습니다.

* 기본값 매개변수를 사용하면 값이 전달되지 않거나 `정의되지 않은` 경우 공식 매개변수를 기본값으로 초기화할 수 있습니다.
* 나머지 매개변수를 사용하면 무한한 수의 인수를 배열로 표현할 수 있습니다.
* 구조 분해 할당을 사용하면 배열의 요소 또는 객체의 속성를 별개의 변수로 분해할 수 있습니다.

```js
function myFunc({ a, b }, c = 1, ...rest) {
  // 여기서 a, b, c와 나머지 값에 접근할 수 있습니다.
}
```

위의 매개변수 구문 중 하나를 사용할 경우 몇 가지 결과가 발생합니다.

* 함수 내부에 `"use strict"`를 적용할 수 없습니다. 이로 인해 syntax error가 발생합니다.
* 함수가 strict mode에 있지 않더라도, `arguments` 객체는 명명된 매개변수와 동기화를 중지하고 `arguments.callee` 접근 시 오류를 발생시킵니다.
### arguments 객체

`arguments` 객체를 사용하여 함수 내에서 함수의 인수를 참조할 수 있습니다.

`arguments`

현재 실행 중인 함수에 전달된 인수가 포함된 배열형 객체입니다.

`arguments.callee`

현재 실행 중인 함수입니다.

`arguments.length`

함수에 전달한 인수의 수입니다.

### Getter와 setter 함수

새로운 속성 추가를 지원하는 표준 내장 객체 또는 사용자 정의 객체에서 접근자의 속성을 정의할 수 있습니다. 객체 초기자 및 classes 내에서 특수 구문을 사용하여 접근자 속성의 getter와 setter를 정의할 수 있습니다.

get

객체의 속성에 접근하면 호출할 함수를 바인딩합니다.

set

객체의 속성에 할당을 시도하면 호출할 함수를 바인딩합니다.

이 구문은 메서드가 아닌 객체 속성을 생성한다는 점에 유의하세요. Getter 및 setter 함수 자체는 `Object.getOwnPropertyDescriptor()`와 같은 리플렉티브 API를 통해서만 접근할 수 있습니다.

블록 레벨 함수
--------

엄격 모드에서는 블록 내의 함수 범위가 해당 블록으로 제한됩니다. ES2015 이전에는 엄격 모드에서 블록 수준 함수가 금지되었습니다.

```js
"use strict";

function f() {
  return 1;
}

{
  function f() {
    return 2;
  }
}

f() === 1; // true

// 엄격 모드가 아닐 경우 f() === 2
```

### 비엄격 모드의 블록 레벨 함수

한 마디로, **하지 마세요**.

비엄격 모드에서의 블록 내 함수 선언은 이상하게 동작합니다. 예시를 봅시다.

```js
if (shouldDefineZero) {
  function zero() {
    // 위험: 호환성 위험
    console.log("zero입니다.");
  }
}
```

엄격 모드에서 이 의미는 잘 지정되어 있습니다. `0`은 `if` 블록의 해당 범위 내에서만 존재합니다. `shouldDefineZero`가 거짓이면 블록이 실행되지 않으므로 `zero`를 정의해서는 안 됩니다. 이전에는 이 값이 지정되지 않았기 때문에 브라우저마다 비엄격 모드에서 다르게 구현했습니다. 자세한 내용은 `함수` 선언을 참조하세요.

조건부로 함수를 정의하는 더 안전한 방법은 변수에 함수 표현식을 할당하는 것입니다.

```js
// var를 사용하면 전역 변수로 사용할 수 있습니다.
// 최상위 함수 선언에 더 가까운 동작을 제공합니다.
var zero;
if (shouldDefineZero) {
  zero = function () {
    console.log("zero입니다.");
  };
}
```

예제
--

### 형식이 지정된 숫자 반환

숫자에 선행 0을 추가해 형식화된 표현으로 문자열을 반환하는 함수입니다.

```js
// 이 함수는 선행 0으로 패딩된 문자열을 반환합니다.
function padZeros(num, totalLen) {
  let numStr = num.toString(); // 반환 값을 문자열로 초기화
  const numZeros = totalLen - numStr.length; // 필요한 0의 수 계산
  for (let i = 1; i <= numZeros; i++) {
    numStr = `0${numStr}`;
  }
  return numStr;
}
```

다음 명령문에서 `padZeros` 함수를 호출합니다.

```js
let result;
result = padZeros(42, 4); // "0042" 반환
result = padZeros(42, 2); // "42" 반환
result = padZeros(5, 4); // "0005" 반환
```

### 함수 존재 여부 판단

`typeof` 연산자를 사용하여 함수가 있는지 확인할 수 있습니다. 다음 예제에서는 `window` 객체에 함수인 `noFunc`라는 속성이 있는지 확인하기 위한 테스트가 수행됩니다. 속성이 있다면 사용되며, 그렇지 않으면 다른 조치가 취해집니다.

```js
if (typeof window.noFunc === "function") {
  // noFunc() 사용
} else {
  // 다른 동작 수행
}
```

`if` 테스트에서는 `noFunc`에 대한 참조가 사용되며, 함수 이름 뒤에 대괄호 `()`가 없으므로 실제 함수가 호출되지 않습니다.

명세
--

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

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

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

같이 보기
-----

* 함수
* Classes
* `function`
* `함수` 표현식
* `Function`


Iteration protocols - JavaScript

Iteration protocols
===================

**순회 프로토콜**은 새로운 내장 객체 또는 구문이 아닌 프로토콜입니다. 이러한 프로토콜은 몇 가지 규칙에 따라 모든 객체에서 구현될 수 있습니다.

프로토콜은 순회 가능 프로토콜과 반복자 프로토콜로 두 가지가 있습니다.

순회 가능 프로토콜
----------

**순회 가능 프로토콜**을 사용하면 JavaScript 객체를 `for...of` 구조에서 반복되는 값과 같은 순회 동작을 정의하거나 사용자 지정할 수 있습니다. `Object`와는 달리 `Array` 또는 `Map`과 같은 일부 내장 유형은 기본 순회 동작이 있는 내장 순회 가능 항목입니다.

**순회 가능**이 되기위해 객체는 반드시 `@@iterator` 메서드를 구현해야 합니다. 즉, 객체(또는 프로토타입 체인의 객체 중 하나)에 상수 `Symbol.iterator`를 통해 이용할 수 있는 `@@iterator` 키가 있는 속성이 있어야 합니다.

`[Symbol.iterator]`

반복자 프로토콜을 준수하는 객체를 반환하는 인수가 없는 함수.

객체를 순회해야 할 때마다(예: `for...of` 루프 시작 시) `@@iterator` 메서드는 인수 전달 없이 호출되고, 반환된 **반복자**는 반복할 값을 가져오는 데 사용됩니다.

이 인수가 없는 함수는, 순회 가능 객체의 메서드로 호출됩니다. 따라서 함수 내에서 `this` 키워드를 사용하여 순회 가능 객체의 속성에 접근하고 순회 중에 제공할 항목을 결정할 수 있습니다.

이 함수는 평범한 함수이거나 제너레이터 함수일 수 있고, 호출 시 반복자 객체가 반환됩니다. 제너레이터 함수 내에서 각 항목은 `yield`를 사용하여 제공될 수 있습니다.

반복자 프로토콜
--------

**반복자 프로토콜**은 유한하거나 무한한 일련의 값을 생성하는 표준 방법을 정의하고, 모든 값이 생성되었을 때 잠재적으로 반환 값을 정의합니다.

객체는 다음 의미 체계를 사용하여 `next()` 메서드를 구현할 때 반복자가 됩니다.

`next()`

0개 또는 1개의 인수를 허용하고 `IteratorResult` 인터페이스(아래 참조)를 준수하는 객체를 반환하는 함수입니다. 내장 언어 기능(`for...of` 등)이 반복자를 사용할 때 객체가 아닌 값(`false` 또는 `undefined` 등)이 반환되면 `TypeError` (`"iterator.next() returned a non-object value"`)가 발생합니다.

모든 반복자 프로토콜 메서드(`next()`, `return()`, 그리고 `throw()`)는 `IteratorResult` 인터페이스를 구현하는 객체를 반환해야 합니다. 다음 속성이 반드시 있어야 합니다.

`done` Optional

불리언 값으로, 반복자가 시퀀스에서 다음 값을 생성할 수 있는 경우엔 `false`입니다. (이는 `done` 속성을 지정하지 않는 것과 같습니다.)

반복자가 시퀀스를 완료한 경우에 이 값은 `true`입니다. 이때 `value`는 반복자의 반환 값을 선택적으로 지정합니다.

`value` Optional

반복자가 반환하는 모든 JavaScript 값입니다. `done`이 `true`이면 생략할 수 있습니다.

실제로 두 속성이 모두 엄격하게 요구되진 않습니다. 속성이 없는 객체가 반환되면 사실상 `{ done: false, value: undefined }`와 동일합니다.

반복자가 `done: true`로 결과를 반환하면 `next()`에 대한 모든 후속 호출도 `done: true`를 반환할 것으로 예상되지만 이는 언어 수준에서 강제되지 않습니다.

`next` 메서드는 메서드 본문에서 사용할 수 있는 값을 받을 수 있습니다. 내장 언어 기능은 어떠한 값도 전달하지 않습니다. 제너레이터의 `next` 메서드로 전달된 값은 해당 `yield` 표현식의 값이 됩니다.

반복자는 선택적으로 **`return(value)`**와 **`throw(exception)`** 메서드를 구현할 수 있습니다. 이 메서드는 호출될 때 호출자가 순회를 완료했으며, 필요한 정리(예: 데이터베이스 연결 닫기)를 수행할 수 있음을 반복자에게 알립니다.

`return(value)` Optional

0개 또는 1개의 인수를 허용하고 `IteratorResult` 인터페이스를 준수하는 객체를 반환하는 함수입니다. 일반적으로 `value`는 전달된 `vlaue`와 같고 `done`은 `true`입니다. 이 메서드를 호출하면 반복자에게 호출자가 더 이상 `next()`를 호출을 할 의도가 없으며, 정리 작업을 수행할 수 있음을 알립니다.

`throw(exception)` Optional

0개 또는 1개의 인수를 허용하고 `IteratorResult` 인터페이스를 준수하는 객체를 반환하는 함수입니다. 일반적으로 `done`은 `true`입니다. 이 메서드를 호출하면 반복자에게 호출자가 오류 조건을 감지했음을 알리며, `exception`은 일반적으로 `Error` 인스턴스입니다.

**참고:** 특정 객체가 반복자 프로토콜을 구현하는지 여부를 반사적으로(즉, 실제로 `next()`를 호출하고 반환된 결과를 확인하지 않고는) 알 수 없습니다.

반복자를 순회 가능으로 만드는 것은 매우 쉽습니다. `this`를 반환하는 `[@@iterator]()` 메서드를 구현하기만 하면 됩니다.

```js
// 반복자 프로토콜과 순회 가능을 모두 만족
const myIterator = {
  next() {
    // ...
  },
  [Symbol.iterator]() {
    return this;
  },
};
```

이러한 객체를 순회 가능 반복자라고 합니다. 이렇게 하면 순회 가능을 기대하는 다양한 구문에서 반복자를 사용할 수 있습니다. 따라서 순회 가능을 구현하지 않고 반복자 프로토콜을 구현하는 것은 거의 유용하지 않습니다. (실제로 거의 모든 구문과 API는 반복자가 아니라 순회 가능을 기대합니다.) 제너레이터 객체가 그 예입니다.

```js
const aGeneratorObject = (function\* () {
  yield 1;
  yield 2;
  yield 3;
})();

console.log(typeof aGeneratorObject.next);
// "function" — next 메서드(올바른 결과를 반환)가 있으므로 반복자입니다.

console.log(typeof aGeneratorObject[Symbol.iterator]);
// "function" — @@iterator 메서드(올바른 반복자를 반환)가 있으므로 순회 가능입니다.

console.log(aGeneratorObject[Symbol.iterator]() === aGeneratorObject);
// true — @@iterator 메서드는 자신(반복자)을 반환하므로 순회 가능 반복자입니다.
```

모든 내장 반복자는 `this`를 반환하는 `[@@iterator]()` 메서드를 구현하는 `Iterator.prototype` (en-US)에서 상속되었기 때문에 내장 반복자도 순회 가능입니다.

그러나 가능하다면 `iterable[Symbol.iterator]`가 `Set.prototype[@@iterator]()`처럼 항상 처음부터 시작하는 별개의 반복자를 반환하는 것이 좋습니다.

비동기 반복자와 비동기 순회 가능 프로토콜
-----------------------

**비동기 반복자**와 **비동기 순회 가능** 프로토콜 이라는 비동기 순회에 사용되는 또 다른 프로토콜 쌍이 있습니다. 순회 가능과 반복자 프로토콜과 비교했을 때 매우 유사한 인터페이스를 가지고 있고, 반복자 메서드 호출의 각 반환 값이 프로미스로 래핑된다는 점만 다릅니다.

객체는 다음 메서드를 구현할 때 비동기 순회 가능 프로토콜을 구현합니다.

`[Symbol.asyncIterator]` (en-US)

비동기 반복자 프로토콜을 준수하는 객체를 반환하는 인수가 없는 함수입니다.

객체는 다음 메서드를 구현할 때 비동기 반복자 프로토콜을 구현합니다.

`next()`

0개 또는 1개의 인수를 허용하고 프로미스를 반환하는 함수입니다. 프로미스는 `IteratorResult` 인터페이스를 준수하는 객체로 이행되며, 속성은 동기 반복자와 동일한 의미 체계를 갖습니다.

`return(value)` Optional

0개 또는 1개의 인수를 허용하고 프로미스를 반환하는 함수입니다. 프로미스는 `IteratorResult` 인터페이스를 준수하는 객체로 이행되며, 속성은 동기 반복자와 동일한 의미 체계를 갖습니다.

`throw(exception)` Optional

0개 또는 1개의 인수를 허용하고 프로미스를 반환하는 함수입니다. 프로미스는 `IteratorResult` 인터페이스를 준수하는 객체로 이행되며, 속성은 동기 반복자와 동일한 의미 체계를 갖습니다.

언어와 순회 프로토콜 간의 상호 작용
--------------------

언어는 순회 가능과 반복자를 생성하거나 소비하는 API를 지정합니다.

### 내장 순회 가능

`String`, `Array`, `TypedArray`, `Map`, `Set` (en-US), 그리고 `Intl.Segmenter.prototype.segment()` (en-US)에서 반환된 `Segments` (en-US)는 각각의 `prototype` 객체가 `@@iterator` 메서드를 구현하기 때문에 모두 내장 순회 가능입니다. 또한 `인수` 객체와 `NodeList`와 같은 일부 DOM 컬렉션 유형도 순회 가능입니다. `ReadableStream`은 이 문서를 작성할 당시의 유일한 내장 비동기 순회 가능입니다.

제너레이터 함수는 순회 가능 반복자인 제너레이터 객체를 반환합니다. 비동기 제너레이터 함수 (en-US)는 비동기 순회 가능 반복자인 비동기 제너레이터 객체 (en-US)를 반환합니다.

내장 순회 가능에서 반환된 반복자는 실제로 모두 앞서 언급한 `[Symbol.iterator]() { return this; }` 메서드를 사용하여 순회 가능 반복자로 만드는 공통 클래스(현재 노출되어있지 않음)를 상속받습니다. 앞으로 이러한 내장 반복자는 `next()` 메서드 외에 추가적으로 반복자 프로토콜에서 필요한 도우미 메서드를 가지고 있을 수 있습니다. 그래픽 콘솔에 로그하여 반복자의 프로토타입 체인을 검사해볼 수 있습니다.
```

console.log([][Symbol.iterator]());

Array Iterator {}
  [[Prototype]]: Array Iterator     ==> 모든 배열 반복자가 공유하는 프로토타입입니다.
    next: ƒ next()
    Symbol(Symbol.toStringTag): "Array Iterator"
    [[Prototype]]: Object           ==> 모든 내장 반복자가 공유하는 프로토타입입니다.
      Symbol(Symbol.iterator): ƒ [Symbol.iterator]()
      [[Prototype]]: Object         ==> Object.prototype 입니다.
```

### 순회 가능을 허용하는 내장 API

순회 가능을 허용하는 많은 API가 있습니다. 몇 가지 예는 다음과 같습니다.

* `Map()`
* `WeakMap()` (en-US)
* `Set()` (en-US)
* `WeakSet()` (en-US)
* `Promise.all()`
* `Promise.allSettled()`
* `Promise.race()`
* `Promise.any()` (en-US)
* `Array.from()`

```js
const myObj = {};

new WeakSet(
  (function\* () {
    yield {};
    yield myObj;
    yield {};
  })(),
).has(myObj); // true
```

### 순회 가능을 기대하는 구문

`for...of` 루프, 배열 및 매개변수 전개, `yield*`, 그리고 배열 구조 분해와 같은 일부 명령문과 표현식에는 순회 가능이 필요합니다.

```js
for (const value of ["a", "b", "c"]) {
  console.log(value);
}
// "a"
// "b"
// "c"

console.log([..."abc"]); // ["a", "b", "c"]

function\* gen() {
  yield\* ["a", "b", "c"];
}

console.log(gen().next()); // { value: "a", done: false }

[a, b, c] = new Set(["a", "b", "c"]);
console.log(a); // "a"
```

내장 구문이 반복자를 순회하고 마지막 결과의 `done`이 `false`(즉, 반복자가 더 많은 값을 생성할 수 있음)이지만 더 이상 값이 필요하지 않은 경우 `return` 메서드가 있는경우, 해당 메서드가 호출됩니다. 예를 들어 `break` 또는 `return`이 `for...of` 루프에서 발생하거나 모든 식별자가 배열 구조 분해에 이미 바인딩된 경우에 이러한 상황이 발생할 수 있습니다.

```js
const obj = {
  [Symbol.iterator]() {
    let i = 0;
    return {
      next() {
        i++;
        console.log("Returning", i);
        if (i === 3) return { done: true, value: i };
        return { done: false, value: i };
      },
      return() {
        console.log("Closing");
        return { done: true };
      },
    };
  },
};

const [b] = obj;
// Returning 1
// Closing

const [a, b, c] = obj;
// Returning 1
// Returning 2
// Returning 3
// 이미 끝에 도달했기 때문에(마지막 호출이 `done: true`를 반환)
// `return`이 호출되지 않습니다.

for (const b of obj) {
  break;
}
// Returning 1
// Closing
```

비동기 제너레이터 함수 (en-US) (동기 제너레이터 함수는 아님)의 `for await...of` 루프와 `yield*`는 비동기 순회 가능과 상호 작용하는 유일한 방법입니다. `for...of`, 배열 전개 등을 동기 순회 가능도 아닌 비동기 순회 가능과 사용하면(즉, `[@@asyncIterator]()`는 있지만 `[@@iterator]()`는 없음) TypeError(x is not iterable.)가 발생합니다.

### 잘못 구성된 순회 가능

순회 가능의 `@@iterator` 메서드가 반복자 객체를 반환하지 않으면 잘못 구성된 순회 가능으로 간주됩니다.

이렇게 사용하면 런타임 오류 또는 버그가 발생할 수 있습니다.

```js
const nonWellFormedIterable = {};
nonWellFormedIterable[Symbol.iterator] = () => 1;
[...nonWellFormedIterable]; // TypeError: [Symbol.iterator]() returned a non-object value
```

예제
--

### 사용자 정의 순회 가능

여러분은 다음과 같이 여러분만의 순회 가능을 만들 수 있습니다.

```js
const myIterable = {
  \*[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3;
  },
};

console.log([...myIterable]); // [1, 2, 3]
```

### 간단한 반복자

반복자는 본래 stateful입니다. 위의 예와 같이 제너레이터 함수로 정의하지 않으면, 여러분은 상태를 클로저에 캡슐화하고 싶을 것입니다.

```js
function makeIterator(array) {
  let nextIndex = 0;
  return {
    next() {
      return nextIndex < array.length
        ? {
            value: array[nextIndex++],
            done: false,
          }
        : {
            done: true,
          };
    },
  };
}

const it = makeIterator(["yo", "ya"]);

console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done); // true
```

### 무한 반복자

```js
function idMaker() {
  let index = 0;
  return {
    next() {
      return {
        value: index++,
        done: false,
      };
    },
  };
}

const it = idMaker();

console.log(it.next().value); // 0
console.log(it.next().value); // 1
console.log(it.next().value); // 2
// ...
```

### 제너레이터로 반복자 정의하기

```js
function\* makeSimpleGenerator(array) {
  let nextIndex = 0;
  while (nextIndex < array.length) {
    yield array[nextIndex++];
  }
}

const gen = makeSimpleGenerator(["yo", "ya"]);

console.log(gen.next().value); // 'yo'
console.log(gen.next().value); // 'ya'
console.log(gen.next().done); // true

function\* idMaker() {
  let index = 0;
  while (true) {
    yield index++;
  }
}

const it = idMaker();

console.log(it.next().value); // 0
console.log(it.next().value); // 1
console.log(it.next().value); // 2
// ...
```

### 클래스로 반복자 정의하기

상태 캡슐화는 프라이빗 속성으로도 수행할 수 있습니다.

```js
class SimpleClass {
  #data;

  constructor(data) {
    this.#data = data;
  }

  [Symbol.iterator]() {
    // 각 반복자에 대해 새 색인을 사용하세요.
    // 이렇게 하면 break 사용 또는 동일한 순회 가능의 중첩 루프와 같은
    // 사소한 상황에서 순회 가능에 대한 여러 반복이 안전해집니다.
    let index = 0;

    return {
      // 참고: 화살표 함수를 사용하면 `this`가 `next()` 대신
      // `[@@iterator]()` 중 하나를 가리킬 수 있습니다.
      next: () => {
        if (index < this.#data.length) {
          return { value: this.#data[index++], done: false };
        } else {
          return { done: true };
        }
      },
    };
  }
}

const simple = new SimpleClass([1, 2, 3, 4, 5]);

for (const val of simple) {
  console.log(val); // 1 2 3 4 5
}
```

### 내장 순회 가능 덮어쓰기

예를 들어 `String`은 내장 순회 가능 객체입니다.

```js
const someString = "hi";
console.log(typeof someString[Symbol.iterator]); // "function"
```

`String`의 기본 반복자 (en-US)는 다음과 같이 문자열의 코드 포인트를 하나씩 반환합니다.

```js
const iterator = someString[Symbol.iterator]();
console.log(`${iterator}`); // "[object String Iterator]"

console.log(iterator.next()); // { value: "h", done: false }
console.log(iterator.next()); // { value: "i", done: false }
console.log(iterator.next()); // { value: undefined, done: true }
```

여러분은 여러분만의 `@@iterator`를 제공하여 순회 동작을 재정의할 수 있습니다.

```js
// auto-boxing을 피하기 위해 명시적으로 String 객체를 구성해야 합니다.
const someString = new String("hi");

someString[Symbol.iterator] = function () {
  return {
    // 단일 요소(문자열 "bye")를 반환하는 반복자 객체
    next() {
      return this._first
        ? { value: "bye", done: (this._first = false) }
        : { done: true };
    },
    \_first: true,
  };
};
```

`@@iterator` 재정의가 순회 프로토콜을 사용하는 내장 생성 동작에 어떤 영향을 미치는지 확인해보세요.

```js
console.log([...someString]); // ["bye"]
console.log(`${someString}`); // "hi"
```

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # sec-iteration |

같이 보기
-----

* 반복자와 제너레이터
* `function*`
* `Symbol.iterator`
* `Iterator` (en-US)


Strict mode - JavaScript

Strict mode
===========

>
> **Callout:** 가끔 엄격하지 않은 기본값을 " **느슨한 모드**(sloppy mode)"라고 부르기도 합니다. 공식적인 용어는 아니지만 혹시 모르니 알아두세요.
>
>
>

ECMAScript 5 에서 소개된 JavaScript 의 엄격모드는 JavaScript 의 제한된 버전을 선택하여 암묵적인 "**느슨한 모드**(sloppy mode)" 를 해제하기 위한 방법입니다. 엄격 모드는 단지 부분적인 것이 아니며, 이것은 *고의적으로* 일반 코드와 다른 시멘틱을 가지고 있습니다. 엄격모드를 지원하지 않는 브라우저에서는 엄격 모드의 코드가 다른 방식으로 동작할 것입니다, 그 때문에 엄격 모드가 적절하게 적용된 피쳐 테스트 없이 엄격 모드에 의존하면 안됩니다. 엄격 모드의 코드와 비-엄격 모드의 코드는 공존할 수 있으며, 때문에 스크립트의 엄격 모드를 취사 선택하는 것이 점진적으로 가능하게 되었습니다.

엄격 모드는 평범한 JavaScript 시멘틱스에 몇가지 변경이 일어나게 합니다.

1. 기존에는 조용히 무시되던 에러들을 throwing합니다.
2. JavaScript 엔진의 최적화 작업을 어렵게 만드는 실수들을 바로잡습니다. 가끔씩 엄격 모드의 코드는 비-엄격 모드의 동일한 코드보다 더 빨리 작동하도록 만들어집니다.
3. 엄격 모드는 ECMAScript의 차기 버전들에서 정의 될 문법을 금지합니다.

코드를 JavaScript의 변형이 제한된 환경에서 동작하도록 하고 싶다면, 엄격 모드로의 변환(transitioning to strict mode)을 참고하세요.

엄격모드 적용하기
---------

엄격모드는 *전체 스크립트* 또는 *부분 함수*에 적용가능합니다. 단, `{}` 괄호로 묶여진 블럭문에는 적용되지 않습니다. 컨텍스트와 같은곳에 적용을 시도하면 동작하지 않습니다. `eval` 코드, `Function` 코드, 이벤트 핸들러 속성, `WindowTimers.setTimeout()` 과 연관된 함수들에 전달된 문자열이 전체 스크립트이며 여기에서 엄격모드가 예상대로 동작합니다.

### 스크립트 엄격 모드

엄격모드를 전체 스크립트에 적용하기 위해, 정확한 구문 `"use strict";`(또는 `'use strict';`) 을 다른 구문 작성 전에 삽입합니다.

```js
// 전체 스크립트 엄격 모드 구문
"use strict";
var v = "Hi! I'm a strict mode script!";
```

이 구문은 이미 유명한 웹사이트에서 문제를 일으킨 전적이 있습니다. 상충되지 않는 스크립트들 끼리 맹목적인 연결이 불가능하기 때문입니다. 엄격 모드의 스크립트와 비-엄격 모드의 스크립트의 연결은 심사숙고 하시기를 바랍니다. 이렇게 되면 전체 연결은 엄격으로 보입니다! 엄격 모드에 다른 엄격모드 들을 결합하는 것은 괜찮습니다. 그리고, 비-엄격 스크립트 사이의 결합도 괜찮습니다. 분명한건, 스크립트를 결합하는 것이 절대 이상적인 것이 아니라는 것이지만, 그래야 한다면 함수를 기준으로 엄격모드 사용을 고려하시기 바랍니다.

또한 함수 내부의 전체 스크립트 내용에 접근할 수 있으며, 엄격모드를 사용하는 외부 함수를 가질 수 있습니다. 이는 결합 문제를 없애주기도 하지만, 이것이 스코프 바깥에 위치한 어떤 전역 변수든 확실하게 밖으로 추출할 수 있음을 의미합니다 .

### 함수에 strict mode 적용

마찬가지로, 함수에 strict mode를 적용하기 위해, 함수 본문 처음에 다음의 구문을 넣습니다. `"use strict";` (또는 `'use strict';`).

```js
function strict() {
  // 함수-레벨 strict mode 문법
  "use strict";
  function nested() {
    return "And so am I!";
  }
  return "Hi! I'm a strict mode function! " + nested();
}
function notStrict() {
  return "I'm not strict.";
}
```

### 모듈에 strict mode 적용

ECMAScript 2015 는 JavaScript 모듈을 소개했습니다. 따라서, 이는 엄격 모드를 적용할 수 있는 3번 째 방법입니다. JavaScript 모듈의 전체 컨텐츠는 엄격 모드 시작을 위한 구문 없이도 자동으로 엄격모드입니다.

```js
function strict() {
  // 모듈이기때문에 기본적으로 엄격합니다
}
export default strict;
```

엄격한 모드 변경
---------

 엄격한 모드는 구문과 런타임 동작을 모두 변경합니다.
 일반적으로 이러한 유형의 변화가 발생합니다: 변환 실수를 오류로 해석하거나(문법 오류 또는 런타임에 오류 발생), 특정 이름의 특정 용도에 대한 특정 변수를 계산하는 방법을 단순화하며, `eval` 과 `arguments` 를 단순화하고,"안전한 "자바 스크립트를 작성하도록 돕고, 미래 ECMAScript의 진화에 대비합니다.

### 실수를 에러로 바꾸는 것

엄격한 모드는 일부 이전에 허용되었던 실수를 오류로 바꿔 놓습니다. 자바 스크립트는 초보 개발자에게 쉬운 것이 되도록 설계되었으며, 때로는 오류를 일으킬만한 동작을 에러없이 시행합니다. 때때로 이것은 즉각적인 문제를 해결하지만, 때때로 이것은 더 심각한 문제를 만들어 냅니다. 엄격한 모드는 이러한 실수를 오류로 처리해서 그것을 발견하고 즉시 고칠 수 있도록 합니다.

첫째로, 엄격모드는 실수로 글로벌 변수를 생성하는 것을 불가능하게 만듭니다. 일반적인 JavaScript에서 변수를 잘못 입력하면 전역 객체에 대한 새 속성이 만들어지고 그대로 "동작" (미래의 오류가 발생할 수 있음: modern 자바 스크립트처럼) 합니다. 전역 변수를 생성하는 할당은 엄격 모드에선 오류를 발생시킵니다.

```js
"use strict";
// 전역 변수 mistypedVariable 이 존재한다고 가정
mistypedVaraible = 17; // 변수의 오타때문에 이 라인에서 ReferenceError 를 발생시킴
```

둘째로, 엄격모드는 예외를 발생시키는 실패를 조용히 넘어가는 대신 작업을 만듭니다. 예를 들어, `NaN` 은 쓸 수 없는 전역 변수입니다. `NaN` 에 할당하는 일반적인 코드는 아무 것도 하지 않습니다. 개발자도 아무런 실패 피드백을 받지 않습니다. 엄격 모드에서 `NaN` 에 할당하는 것은 예외를 발생시킵니다. 일반 코드에서 조용히 넘어가는 모든 실패에 대해 (쓸 수 없는 전역 또는 프로퍼티에 할당, getter-only 프로퍼티에 할당, 확장 불가 객체에 새 프로퍼티 할당) 엄격 모드에서는 예외를 발생시킵니다.

```js
"use strict";

// 쓸 수 없는 프로퍼티에 할당
var undefined = 5; // TypeError 발생
var Infinity = 5; // TypeError 발생

// 쓸 수 없는 프로퍼티에 할당
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // TypeError 발생

// getter-only 프로퍼티에 할당
var obj2 = {
  get x() {
    return 17;
  },
};
obj2.x = 5; // TypeError 발생

// 확장 불가 객체에 새 프로퍼티 할당
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // TypeError 발생
```

셋째로, 엄격 모드는 삭제할 수 없는 프로퍼티를 삭제하려할 때 예외를 발생시킵니다(시도가 어떤 효과도 없을 때).

```js
"use strict";
delete Object.prototype; // TypeError 발생
```

넷째로, Gecko 34 이전의 엄격모드는 객체 리터럴의 모든 프로퍼티의 이름이 유니크해도록 요구합니다. 일반 코드는 프로퍼티의 값이 나중에 정해진 프로퍼티 이름으로 중복할 것입니다. 하지만 마지막 인스턴스 만 변경했기 때문에 코드를 수정하여 마지막 인스턴스를 변경하는 것 이외의 속성 값을 변경하면 복제는 버그의 벡터가됩니다. 엄격모드에서는 프로퍼티 이름을 중복하는 것은 구문 에러입니다.

>
> **Note:** ECMAScript 2015부터는 에러가 아닙니다. (Firefox bug 1041128).
>
>
>

```js
"use strict";
var o = { p: 1, p: 2 }; // !!! 구문 에러
```

다섯째로, 엄격모드는 유니크한 함수 파라미터 이름을 요구합니다. 일반 코드에서는 마지막으로 중복된 인수가 이전에 지정된 인수를 숨깁니다. 이러한 이전의 인수들은 `arguments[i]` 를 통해 여전히 남아 있을 수 있으므로, 완전히 접근 불가한 것이 아닙니다. 여전히, 이런 숨김 처리는 이치에 맞지 않으며 원했던 것이 아닐 수 있습니다(예를 들면 오타를 숨길 수도 있습니다). 따라서 엄격 모드에서는 중복 인수명은 구문 에러입니다.

```js
function sum(a, a, c) {
  // !!! 구문 에러
  "use strict";
  return a + b + c; // 코드가 실행되면 잘못된 것임
}
```

여섯째로, ECMAScript 5 에서의 엄격 모드는 8진 구문을 금지합니다. 8진 구문은 ES5의 문법이 아니지만, 모든 브라우저에서 앞에 0을 붙여 지원됩니다(`0644 === 420` 와 `"\045" === "%"`). ECMAScript 2015 에서는 접두사 "`0o`"를 붙여 8진수를 지원합니다.

```js
var a = 0o10; // ES6: 8진수
```

초보 개발자들은 가끔 앞에 붙은 0 이 무의미하다고 생각하여, 이를 정렬용으로 사용합니다 — 하지만 이는 숫자의 의미를 바꿔버립니다! 이 8진수 문법은 거의 무용하며 잘못 사용될 수 있으므로 엄격모드에서 이 구문은 에러입니다.

```js
"use strict";
var sum =
  015 + // !!! 구문 에러
  197 +
  142;
```

일곱째로, ECMAScript 6 의 엄격모드는 primitive 값에 프로퍼티를 설정하는 것을 금지합니다. 엄격모드가 아닐 때에는 프로퍼티 설정이 간단하게 무시되지만(no-op), 엄격모드에서는 `TypeError` 를 발생시킵니다.

```js
(function () {
  "use strict";

  false.true = ""; // TypeError
  (14).sailing = "home"; // TypeError
  "with".you = "far away"; // TypeError
})();
```

### 변수 사용 단순화

엄격모드는 코드상의 변수 이름을 특정 변수 정의로 매핑하는 방법을 단순화합니다. 많은 컴파일러 최적화는 변수 X 가 어떤 위치에 저장되어 있는지를 말해주는 능력에 의존하고 있습니다. 이는 JavaScript 코드를 완전히 최적화하는데 중요합니다. JavaScript는 때때로 이름을 코드상의 변수 정의로 기본 매핑하는 것을 런타임때까지 실행이 불가하게합니다. 엄격모드는 이것이 발생하는 대부분의 경우를 제거하여 컴파일러가 엄격모드 코드를 더 잘 최적화 할 수 있게합니다.

첫째로, 엄격모드는 `with` 를 사용하지 못하게합니다. `with` 사용의 문제는 런타임중에 블록안의 모든 이름이 전달된 객체의 프로퍼티나 인근 (또는 심지어 전역) 스코프 내의 변수로 매핑될 수도 있다는 것입니다. 이는 사전에 아는 것이 불가합니다. 엄격 모드는 `with` 를 구문 에러로 만들어, `with` 의 이름이 런타임에 알 수 없는 위치를 참조하지 않도록합니다.

```js
"use strict";
var x = 17;
with (obj) {
  // !!! 구문 에러
  // 엄격모드가 아니라면, 이는 var x 가 되어야 하나요,
  // obj.x 가 되어야 하나요?
  // 일반적으로는 코드를 실행하지 않고 이를 말하는 것은 불가하므로,
  // 이름을 최적화 할 수 없습니다.
  x;
}
```

이름이 짧은 변수에 객체를 할당한 후, 변수에 해당하는 프로퍼티에 접근하는 간단한 대안은 `with` 를 대체할 준비가 되었습니다.

둘째로, 엄격모드 코드의 `eval` 은 새로운 변수를 주위 스코프에 추가하지 않습니다. 일반적인 코드에서 `eval("var x;")` 는 변수 `x` 를 주위 함수나 전역 스코프에 추가합니다. 이는, 일반적으로 `eval` 호출을 포함하는 함수에서 인수나 지역 변수를 참조하지 않는 모든 이름은 런타임에 특정 정의에 반드시 매핑되어야 함을 의미합니다(`eval` 이 외부 변수를 숨기는 새로운 변수를 추가했기 때문입니다). 엄격모드에서 `eval` 은 evaluated 된 코드에서만 변수를 생성하므로, 외부 변수나 일부 로컬 변수에 참조하는지에 영향을 주지 않습니다.

```js
var x = 17;
var evalX = eval("'use strict'; var x = 42; x");
console.assert(x === 17);
console.assert(evalX === 42);
```

이와 관련해서, `eval` 함수가 엄격모드 코드 내에서 `eval(...)` 형태의 표현으로 적용되었다면, 코드는 엄격모드 코드로 evaluated 됩니다. 코드는 명시적으로 엄격모드를 적용할 수 있지만, 필수적인 것은 아닙니다.

```js
function strict1(str) {
  "use strict";
  return eval(str); // str 은 엄격모드 코드로 다뤄짐
}
function strict2(f, str) {
  "use strict";
  return f(str); // eval(...) 이 아님:
  // str 은 엄격모드를 적용한 경우에만 엄격함
}
function nonstrict(str) {
  return eval(str); // str 은 엄격모드를 적용한 경우에만 엄격함
}

strict1("'엄격모드 코드!'");
strict1("'use strict'; '엄격모드 코드!'");
strict2(eval, "'느슨한 코드.'");
strict2(eval, "'use strict'; '엄격모드 코드!'");
nonstrict("'느슨한 코드.'");
nonstrict("'use strict'; '엄격모드 코드!'");
```

따라서 엄격모드 `eval` 코드 내의 이름은 엄격모드 코드 내의 이름이 `eval` 의 결과로 evaluated 되지 않은 것과 동일하게 동작합니다.

셋째로, 엄격모드는 일반 이름을 제거하는 것을 금지합니다. 엄격 모드에서 `delete name` 은 구문 에러입니다.

```js
"use strict";

var x;
delete x; // !!! 구문 에러

eval("var y; delete y;"); // !!! syntax error
```

### `eval` 과 `arguments` 를 더 간단하게 하기

엄격모드는 `arguments` 와 `eval` 을 덜 기괴하고 마법적으로 만듭니다. 둘은 일반 코드에서 상당히 많은 마법적인 동작들을 갖고 있습니다: 바인딩을 추가하거나 삭제하고 바인딩 값을 변경하기위한 `eval`, 명명된 인수를 앨리어스하는 인덱싱된 프로퍼티 `arguments`. 엄격모드는 ECMAScript 의 미래 버전까지는 모든 수정이 이루지지는 않겠지만 `eval` 과 `arguments` 를 키워드로 다루기 위한 훌륭한 큰 걸음을 내딛었습니다.

첫째로, 변수명 eval 과 arguments 는 언어 문법에 바운드되거나 할당될 수 없습니다. 다음 시도들은 모두 구문 에러입니다.

```js
"use strict";
eval = 17;
arguments++;
++eval;
var obj = { set p(arguments) {} };
var eval;
try {
} catch (arguments) {}
function x(eval) {}
function arguments() {}
var y = function eval() {};
var f = new Function("arguments", "'use strict'; return 17;");
```

둘째로, 엄격모드 코드는 `arguments` 객체가 생성한 프로퍼티를 앨리어스하지 않습니다. 함수의 첫 번째 인수가 `arg` 인 일반 코드에서는 `arg` 를 설정하는 것은 `arguments[0]` 를 설정하기도 하며, 그 반대도 그렇습니다(인수가 제공되지 않거나, `arguments[0]` 이 삭제된 경우는 제외). 엄격모드 함수의 `arguments` 객체는 함수가 호출될 때 원본 인수들을 저장합니다. `arguments[i]` 는 명명된 인수에 해당하는 값을 추적하지 않으며, 명명된 인수도 `arguments[i]` 에 해당하는 값을 추적하지 않습니다.

```js
function f(a) {
  "use strict";
  a = 42;
  return [a, arguments[0]];
}
var pair = f(17);
console.assert(pair[0] === 42);
console.assert(pair[1] === 17);
```

셋째로, `arguments.callee` 는 더 이상 지원되지 않습니다. 일반 코드의 `arguments.callee` 는 바깥 함수를 참조합니다. 이런 유즈 케이스는 중요하지 않습니다. 간단히 바깥 함수의 이름을 사용하면됩니다. 더욱이, `arguments.callee` 는 인라인 함수와 같은 최적화를 상당히 방해하므로, `arguments.callee` 가 접근하는 함수는 인라인이 아닌 함수를 참조하도록 제공해야 했습니다. 엄격모드 함수의 `arguments.callee` 는 삭제할 수 없는 프로퍼티이며, 설정이나 반환할때 에러를 발생합니다.

```js
"use strict";
var f = function () {
  return arguments.callee;
};
f(); // TypeError
```

### JavaScript "보안"

엄격모드는 "보안된" JavaScript를 작성하기 쉽게 해줍니다. 일부 웹사이트들은 사용자가 다른 사용자들을 대신하여 웹사이트에서 실행시키는 JavaScript를 작성하는 방법을 제공합니다. 브라우저에서 JavaScript는 사용자의 개인정보에 접근할수 있기 때문에, JavaScript는 금지된 기능에 대한 검열을 하기위해 반드시 실행전에 부분적으로 변경되어야 합니다. JavaScript의 유연성으로 인해 많은 런타임 체크없이 이것을 수행하는것은 사실상 불가능합니다. 특정 언어의 기능들이 너무 광범위하여 런타임 검사 수행은 상당한 성능비용이 생깁니다. 엄격모드의 작은 수정과 사용자가 제출한 JavaScript가 엄격모드가 되면 특정 방식으로 호출되므로 런타임 검사의 필요성이 크게 줄어 듭니다.

첫째, 엄격모드에서는 `this` 로 함수에 전달된 값은 강제로 객체가 되지 않습니다 (a.k.a. "boxed"). 보통 함수의 경우, `this` 는 언제나 객체입니다: 객체값 `this` 와 함께 호출된 경우 제공된 객체이거나 ; 부울값, 문자 또는 숫자 `this` 로 호출된 경우 그 값은 Boxed 입니다; 또는 `undefined` 또는 `null` `this` 로 호출되면 전역객체입니다. (특정된 `this` 명세를 위해서는 `call`, `apply`, 또는 `bind` 를 사용하십시요) 자동 박싱은 성능 비용뿐 아니라 전역 객체가 브라우저에 노출되는것은 보안상 위험합니다. 전역객체들은 JavaScript 환경의 "보안" 기능에 접근하는것을 제공하기때문에 제한되어야 합니다. 따라서 엄격모드의 함수는, 정의된 `this` 는 박스드 객체가 되지 않으며, 정의되지 않은경우 `this` 는 `undefined` 가 됩니다:

```js
"use strict";
function fun() {
  return this;
}
console.assert(fun() === undefined);
console.assert(fun.call(2) === 2);
console.assert(fun.apply(null) === null);
console.assert(fun.call(undefined) === undefined);
console.assert(fun.bind(true)() === true);
```

즉, 브라우저에서 엄격모드의 함수내 에서는 더 이상 `window` 객체를 `this` 를 통해 참조할 수 없습니다.

둘째로, 엄격모드에서는 ECMAScript의 일반적으로 구현된 확장을 통해 JavaScript 스택을 "걷는"것이 불가능합니다. 이러한 일반적인 확장 코드는, 함수 `fun` 이 호출되는 중간에, `fun.caller` 는 가장 최근에 `fun` 을 호출한 함수이고 `fun.arguments` 는 `fun`을 호출하기 위한 인수입니다. "권한있는"함수와 (잠재적으로 보안되지 않은) 인수에 접근을 허용하기때문에 두가지 확장 모두 JavaScript의 "보안" 문제가 됩니다. `fun` 이 엄격모드인경우, both `fun.caller` 와 `fun.arguments` 모두 설정 또는 검색될때 삭제 불가능한 속성이 됩니다.

```js
function restricted() {
  "use strict";
  restricted.caller; // throws a TypeError
  restricted.arguments; // throws a TypeError
}
function privilegedInvoker() {
  return restricted();
}
privilegedInvoker();
```

셋째, 엄격모드의 `인수` 는 더이상 해당 함수의 호출 변수에 대한 접근을 제공하지 않습니다. 일부 이전 ECMAScript에서 `arguments.caller` 해당 함수에 별명이 지정된 객체였습니다. 이것은 함수의 추상화를 통해 권한이 있는 값을 숨길수 있는 기능을 차단하여 보안의 위협이 됩니다; 이것은 또한 대부분의 최적화를 배제시킵니다. 이러한 이유로 최신 브라우저들은 이를 구현하지 않습니다. 하지만 이것들의 이전 기능들 때문에, 엄격모드함수에서 `arguments.caller` 설정이나 검색시 삭제 불가능한 요소가 됩니다:

```js
"use strict";
function fun(a, b) {
  "use strict";
  var v = 12;
  return arguments.caller; //TypeError 가 발생.
}
fun(1, 2); // doesn't expose v (or a or b)
```

### 미래의 ECMAScript 버전을 위한 준비

새롭게 선보일 ECMAScript 버전은 새로운 구문을 소개할 것이고, ECMAScript5에서의 엄격 모드는 변환을 쉽게 하기 위해 몇 가지의 제한을 적용할 것으로 예상되고 있습니다. 만약 이 변화들이 엄격 모드에서의 제한을 기반으로 한다면, 더 바꾸기 쉬워질 것입니다.

첫번째로, 엄격 모드에서의 식별자 후보들은 예약어가 됩니다. 이 예약어들은 `implements`, `interface`, `let`, `package`, `private`, `protected`, `public`, `static`, `yield`입니다. 그럼, 엄격 모드에서는 이 예약어와 똑같은 이름을 사용하거나, 변수명 또는 아규먼트명으로도 사용할 수 없습니다.

```js
function package(protected) {
  // !!!
  "use strict";
  var implements; // !!!

  // !!!
  interface: while (true) {
    break interface; // !!!
  }

  function private() {} // !!!
}
function fun(static) {
  "use strict";
} // !!!
```

Mozilla의 특별 지시 두 가지 : 먼저, 코드가 JavaScript 1.7 또는 그보다 높고 (예를 들어, 크롬 코드 또는 `<script type="">` 를 바로 사용할 때) 엄격 모드의 코드라면, `let` 와 `yield`는 처음 소개되었을 때의 그 기능을 가진다. 그러나 웹에서의 엄격 모드 코드는, `<script src="">`나 `<script>...</script>`로 로딩되지, `let`/`yield`를 식별자로 사용할 수가 없을 것이다. 그리고 나서는, ES5 가 `class`, `enum`, `export`, `extends`, `import`, and `super` 와 같은 예약어들을 무조건 리저브함에도 불구하고, 먼저 Firefox 5 Mozilla 는 그것들을 엄격 모드에서만 리저브한다.

다음은, 엄격 모드는 스크립트나 함수의 탑 레벨이 아닌 곳에서의 함수 내용 정의를 제한합니다. (strict mode prohibits function statements not at the top level of a script or function). 브라우저에서 일반적인 코드는 함수 내용 정의가 "어디에서든" 허용됩니다. *이것은 ES5의 부분이 아닙니다!(심지어 ES3도 아니다.)* 이건 다른 브라우저에서 공존할 수 없는 시멘틱의 확장입니다. 앞으로의 ECMAScript 에디션은 바라건대, 스크립트나 함수의 탑 레벨이 아닌 곳에서의 함수 내용 정의를 위해, 새로운 시멘틱을 명시할 것입니다. 엄격 모드에서 이러한 함수 정의를 금지하는 것(Prohibiting such function statements in strict mode)은 앞으로 출시될 ECMAScript의 사양을 위한 "준비"입니다. :

```js
"use strict";
if (true) {
  function f() {} // !!! syntax error
  f();
}

for (var i = 0; i < 5; i++) {
  function f2() {} // !!! syntax error
  f2();
}

function baz() {
  // kosher
  function eit() {} // also kosher
}
```

이 규제는 엄밀히 말하면 엄격 모드가 아닌데, 저런 함수 표현식들은 기본 ECMAScript5의 확장이기 때문입니다. 그러나 이것이 ECMAScript 협회가 권장하는 방식이며, 브라우저들이 이를 지원할 것입니다.

브라우저에서의 엄격 모드
-------------

현재 주류의 브라우저들은 엄격 모드를 지원하고 있습니다. 하지만, 아직도 현실에서 사용되는 수 많은 브라우저의 버전들은 엄격 모드를 부분적으로만 지원하거나(Browser versions used in the wild that only have partial support for strict mode), 아예 지원을 하지 않고 있기 때문에, 맹목적으로 여기에 의지할 수는 없습니다. (예를 들면, Internet Explorer 10 버전 이하!) *엄격 모드는 시멘틱을 바꿉니다.* 이 변화들에 의지하는 것은 실수와 엄격 모드를 지원하지 않는 브라우저의 에러를 야기할 것입니다. 엄격 모드를 사용하는 데에 주의하는 것을 익히세요, 그리고 피쳐 테스트로 엄격 모드를 사용하기에 적절한 부분인지 확인하고 보완하세요. 마지막으로, *엄격 모드를 지원하는 브라우저와 그렇지 않은 브라우저에서 작성한 코드의 테스트를 확실히 하도록 하세요.*

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification  |

함께 보기
-----

* Where's Walden? » New ES5 strict mode support: now with poison pills!
* Where's Walden? » New ES5 strict mode requirement: function statements not at top level of a program or function are prohibited
* Where's Walden? » New ES5 strict mode support: new vars created by strict mode eval code are local to that code only
* JavaScript "use strict" tutorial for beginners.
* John Resig - ECMAScript 5 Strict Mode, JSON, and More
* ECMA-262-5 in detail. Chapter 2. Strict Mode.
* Strict mode compatibility table
* Transitioning to strict mode


Classes - JavaScript

Classes
=======

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
Class는 객체를 생성하기 위한 템플릿입니다. 클래스는 데이터와 이를 조작하는 코드를 하나로 추상화합니다. JavaScript에서 클래스는 프로토타입을 이용해서 만들어졌지만 ES5의 클래스 의미와는 다른 문법과 의미를 가집니다.

Class 정의
--------

Class는 사실 "특별한 함수"입니다. 함수를 함수 표현식과 함수 선언으로 정의할 수 있듯이 class 문법도 class 표현식 and class 선언 두 가지 방법을 제공합니다.

### Class 선언

Class를 정의하는 한 가지 방법은 **class 선언**을 이용하는 것입니다. class를 선언하기 위해서는 클래스의 이름(여기서 "Rectangle")과 함께 `class` 키워드를 사용해야 합니다.

```js
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
```

#### Hoisting

**함수 선언**과 **클래스 선언**의 중요한 차이점은 함수의 경우 정의하기 하기 전에 호출할 수 있지만, 클래스는 반드시 정의한 뒤에 사용할 수 있다는 점입니다. 다음 코드는 `ReferenceError`를 던질 것입니다.

```js
const p = new Rectangle(); // ReferenceError

class Rectangle {}
```

예외가 발생하는 이유는 클래스가 호이스팅될 때 초기화는 되지 않기 때문입니다.

### Class 표현식

**Class 표현식**은 class를 정의하는 또 다른 방법입니다. Class 표현식은 이름을 가질 수도 있고, 갖지 않을 수도 있습니다. 이름을 가진 class 표현식의 이름은 클래스 body의 local scope에 한해 유효합니다. (하지만, 클래스의 (인스턴스 이름이 아닌) `name` 속성을 통해 찾을 수 있습니다).

```js
// unnamed
let Rectangle = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Rectangle.name);
// 출력: "Rectangle"

// named
let Rectangle = class Rectangle2 {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Rectangle.name);
// 출력: "Rectangle2"
```

**참고:** 클래스 **표현식**에는 Class 선언 섹션에 설명된 것과 동일한 호이스팅 제한이 적용됩니다.

Class body 와 메서드 정의
-------------------

Class body는 중괄호 `{}` 로 묶여 있는 안쪽 부분입니다. 이곳은 여러분이 메서드나 constructor와 같은 class 멤버를 정의할 곳입니다.

### Strict mode

클래스의 본문(body)은 strict mode에서 실행됩니다. 즉, 여기에 적힌 코드는 성능 향상을 위해 더 엄격한 문법이 적용됩니다. 그렇지 않으면, 조용히 오류가 발생할 수 있습니다. 특정 키워드는 미래의 ECMAScript 버전용으로 예약됩니다.

### Constructor (생성자)

constructor 메서드는 `class` 로 생성된 객체를 생성하고 초기화하기 위한 특수한 메서드입니다. "constructor" 라는 이름을 가진 특수한 메서드는 클래스 안에 한 개만 존재할 수 있습니다. 만약 클래스에 여러 개의 `constructor` 메서드가 존재하면 `SyntaxError` 가 발생할 것입니다.

constructor는 부모 클래스의 constructor를 호출하기 위해 `super` 키워드를 사용할 수 있습니다.

### 프로토타입 메서드

메서드 정의도 참조해보세요.

```js
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  get area() {
    return this.calcArea();
  }
  // 메서드
  calcArea() {
    return this.height \* this.width;
  }
}

const square = new Rectangle(10, 10);

console.log(square.area); // 100
```

### 정적 메서드와 속성

static 키워드는 클래스를 위한 정적(static) 메서드를 정의합니다. 정적 메서드는 클래스의 인스턴스화(instantiating) 없이 호출되며, 클래스의 인스턴스에서는 호출할 수 없습니다. 정적 메서드는 어플리케이션(application)을 위한 유틸리티(utility) 함수를 생성하는 데 주로 사용됩니다. 반면, 정적 속성은 캐시, 고정 환경설정 또는 인스턴스 간에 복제할 필요가 없는 기타 데이터에 유용합니다.

```js
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static displayName = "Point";
  static distance(a, b) {
    const dx = a.x - b.x;
    const dy = a.y - b.y;

    return Math.hypot(dx, dy);
  }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
p1.displayName; // undefined
p1.distance; // undefined
p2.displayName; // undefined
p2.distance; // undefined

console.log(Point.displayName); // "Point"
console.log(Point.distance(p1, p2)); // 7.0710678118654755
```

### 프로토타입 및 정적 메서드를 사용한 `this` 바인딩

메서드를 변수에 할당 한 다음 호출하는 것과 같이, 정적 메서드나 프로토타입 메서드가 `this` 값 없이 호출될 때, `this` 값은 메서드 안에서 `undefined`가 됩니다. 이 동작은 `"use strict"` 명령어 없이도 같은 방식으로 동작하는데, `class` 문법 안에 있는 코드는 항상 strict mode 로 실행되기 때문입니다.

```js
class Animal {
  speak() {
    return this;
  }
  static eat() {
    return this;
  }
}

let obj = new Animal();
obj.speak(); // the Animal object
let speak = obj.speak;
speak(); // undefined

Animal.eat(); // class Animal
let eat = Animal.eat;
eat(); // undefined
```

위에 작성된 코드를 전통적 방식의 함수기반의 non–strict mode 구문으로 재작성하면, `this` 메서드 호출은 기본적으로 전역 객체인 초기 `this` 값에 자동으로 바인딩 됩니다. Strict mode에서는 자동 바인딩이 발생하지 않습니다; `this` 값은 전달된 대로 유지됩니다.

```js
function Animal() {}

Animal.prototype.speak = function () {
  return this;
};

Animal.eat = function () {
  return this;
};

let obj = new Animal();
let speak = obj.speak;
speak(); // global object (in non–strict mode)

let eat = Animal.eat;
eat(); // global object (in non-strict mode)
```

### 인스턴스 속성

인스턴스 속성은 반드시 클래스 메서드 내에 정의되어야 합니다:

```js
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
```

정적 (클래스사이드) 속성과 프로토타입 데이터 속성은 반드시 클래스 선언부 바깥쪽에서 정의되어야 합니다.

```js
Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;
```

### Field 선언

>
> **Warning:** public과 private 필드 선언은 JavaScript 표준화 위원회에 실험적 기능 (stage 3) TC39 로 제안되어있습니다. 현재 이를 지원하는 브라우져는 제한적인 상태입니다만, Babel 과 같은 build 시스템을 사용한다면 이 기능을 사용해볼 수 있습니다.
>
>
>

#### Public 필드 선언

JavaScript의 필드 선언 문법을 사용해서 위의 예제는 아래와 같이 다시 쓰여질 수 있습니다.

```js
class Rectangle {
  height = 0;
  width;
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
```

필드를 먼저 선언함으로서 클래스 정의는 self-documenting에 가까워졌고 필드는 언제나 존재하는 상태가 됩니다.

위의 예에서 봤듯이 필드 선언은 기본 값과 같이 선언될 수도 있습니다.

자세한 내용은 public class fields (en-US)를 참조하세요.

#### Private 필드 선언

private 필드를 사용하면 아래와 같이 예제를 개선할 수 있습니다.

```js
class Rectangle {
  #height = 0;
  #width;
  constructor(height, width) {
    this.#height = height;
    this.#width = width;
  }
}
```

클래스의 바깥에서 private 필드를 접근하려고 하면 에러가 발생합니다. private필드는 클래스 내부에서만 읽고 쓰기가 가능합니다. 클래스 외부에서 보이지 않도록 정의하였으므로 클래스가 버젼업 되면서 내부 구현이 바뀌더라도 클래스 사용자 입장에서는 이에 아무런 영항을 받지 않도록 할 수 있습니다.

>
> **Note:** Private 필드는 사용전에 선언되어야 합니다.
>
>
>

일반적인 프로퍼티와는 다르게 private 필드는 값을 할당하면서 만들어질 수 없습니다.

자세한 내용은 private class fields를 참조하세요.

`extends`를 통한 클래스 상속(sub classing)
----------------------------------

`extends` 키워드는 *클래스 선언*이나 *클래스 표현식*에서 다른 클래스의 자식 클래스를 생성하기 위해 사용됩니다.

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

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); // super class 생성자를 호출하여 name 매개변수 전달
  }

  speak() {
    console.log(`${this.name} barks.`);
  }
}

let d = new Dog("Mitzie");
d.speak(); // Mitzie barks.
```

subclass에 constructor가 있다면, "this"를 사용하기 전에 가장 먼저 super()를 호출해야 합니다.

또한 es5에서 사용되던 전통적인 함수 기반의 클래스를 통하여 확장할 수도 있습니다.

```js
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function () {
  console.log(`${this.name} makes a noise.`);
};

class Dog extends Animal {
  speak() {
    console.log(`${this.name} barks.`);
  }
}

let d = new Dog("Mitzie");
d.speak(); // Mitzie barks.

// 유사한 메서드의 경우, 자식의 메서드가 부모의 메서드보다 우선합니다
```

클래스는 생성자가 없는 객체(non-constructible)을 확장할 수 없습니다. 만약 기존의 생성자가 없는 객체을 확장하고 싶다면, 이 메서드를 사용하세요. `Object.setPrototypeOf()` (en-US):

```js
const Animal = {
  speak() {
    console.log(`${this.name} makes a noise.`);
  },
};

class Dog {
  constructor(name) {
    this.name = name;
  }
}

// 이 작업을 수행하지 않으면 speak를 호출할 때 TypeError가 발생합니다
Object.setPrototypeOf(Dog.prototype, Animal);

let d = new Dog("Mitzie");
d.speak(); // Mitzie makes a noise.
```

Species
-------

배열을 상속 받은 MyArray 클래스에서 `Array` Object를 반환하고 싶을 수도 있을 것입니다. 그럴때 Species 패턴은 기본 생성자를 덮어쓰도록 해줍니다.

예를 들어, `map()`과 같은 기본 생성자를 반환하는 메서드를 사용할 때 이 메서드가 MyArray 객체 대신 `Array` 객체가 반환하도록 하고 싶을 것입니다. `Symbol.species` (en-US) 심볼은 이러한 것을 가능하게 해줍니다:

```js
class MyArray extends Array {
  // 부모 Array 생성자로 species 덮어쓰기
  static get [Symbol.species]() {
    return Array;
  }
}
var a = new MyArray(1, 2, 3);
var mapped = a.map((x) => x \* x);

console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
```

`super` 를 통한 상위 클래스 호출
----------------------

`super` 키워드는 객체의 부모가 가지고 있는 메서드를 호출하기 위해 사용됩니다. 이는 프로토타입 기반 상속보다 좋은 점 중 하나입니다.

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

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Lion extends Cat {
  speak() {
    super.speak();
    console.log(`${this.name} roars.`);
  }
}

let l = new Lion("Fuzzy");
l.speak();
// Fuzzy makes a noise.
// Fuzzy roars.
```

Mix-ins
-------

추상 서브 클래스 또는 믹스-인은 클래스를 위한 템플릿입니다. ECMAScript 클래스는 하나의 단일 슈퍼클래스만을 가질 수 있으며, 예를 들어 툴링 클래스로부터의 다중 상속은 불가능합니다. 기능은 반드시 슈퍼클래스에서 제공되어야 합니다.

슈퍼클래스를 인자로 받고 이 슈퍼클래스를 확장하는 서브클래스를 생성하여 반환하는 함수를 사용하여 ECMAScript에서 믹스-인을 구현할 수 있습니다:

```js
var calculatorMixin = (Base) =>
  class extends Base {
    calc() {}
  };

var randomizerMixin = (Base) =>
  class extends Base {
    randomize() {}
  };
```

위 믹스-인을 사용하는 클래스는 다음과 같이 작성할 수 있습니다:

```js
class Foo {}
class Bar extends calculatorMixin(randomizerMixin(Foo)) {}
```

클래스 재정의
-------

클래스는 재정의될 수 없습니다. 재정의를 시도하면 `SyntaxError` 가 발생합니다.

이를 실험해보고 싶으면 FireFox Web Console (**Tools** > **Web Developer** > **Web Console**) 에서 같은 이름으로 클래스를 두번 정의하려고 해보세요. 다음과 같은 오류를 보게 될 겁니다. `SyntaxError: redeclaration of let ClassName;`. (See further discussion of this issue in Firefox bug 1428672.) Doing something similar in Chrome Developer Tools gives you a message like `Uncaught SyntaxError: Identifier 'ClassName' has already been declared at <anonymous>:1:1`.

명세
--

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

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

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

참조
--

* 함수
* class 선언
* class 식
* Public class fields (en-US)
* Private class fields
* `super`
* 블로그 게시물: "ES6 In Depth: Classes"
* Fields and public/private class properties proposal (stage 3)


식 및 연산자 - JavaScript

식 및 연산자
=======

이 장은 JavaScript의 모든 연산자, 식 및 키워드를 나열합니다.

항목별 식 및 연산자
-----------

알파벳순 목록은 왼쪽 사이드바를 보세요.

### 기본 식

기본 키워드 및 JavaScript의 일반 식.

`this`

`this` 키워드는 실행 문맥의 특별한 속성을 가리킵니다.

`function`

`function` 키워드는 함수를 정의합니다.

`class`

`class` 키워드는 클래스를 정의합니다.

`function*`

`function*` 키워드는 생성기 함수 식을 정의합니다.

`yield`

생성기 함수를 일시정지 및 재개합니다.

`yield*`

다른 생성기 함수 또는 순회가능 객체로 위임합니다.

`async function`

`async function`은 비동기 함수 표현식을 정의합니다.

`await`

비동기 함수를 일시 중지했다가 다시 시작하고 promise의 resolution/rejection을 기다립니다.

`[]`

배열 초기자 및 리터럴 구문.

`{}`

객체 초기자 및 리터럴 구문.

`/ab+c/i`

정규식 리터럴 구문.

`( )`

그룹 연산자.

### 좌변 식

좌변값은 할당 대상입니다.

Property accessors

 속성 접근자는 객체의 속성 또는 메서드에 대한 접근 방법을 제공합니다.
 (`object.property`, `object["property"]`)

`new`

`new` 연산자는 생성자의 인스턴스를 만듭니다.

`new.target`

생성자 문맥에서, `new.target`은 `new`에 의해 호출된 생성자를 말합니다.

`super`

`super` 키워드는 부모 생성자를 호출합니다.

`...obj`

전개 연산자는 (함수 호출 시) 매개변수 여럿이나, (배열 리터럴에서) 다수의 요소를 필요로 하는 곳에서 표현식을 확장합니다.

### 증가 및 감소

접두/접미 증감 연산자입니다.

`A++`

접미 증가 연산자.

`A--`

접미 감소 연산자.

`++A`

접두 증가 연산자.

`--A`

접두 감소 연산자.

### 단항 연산자

단항 연산은 피연산자가 하나뿐인 연산입니다.

`delete` (en-US)

`delete` 연산자는 객체에서 속성을 지웁니다.

`void`

`void` 연산자는 식의 반환값을 버립니다.

`typeof`

`typeof` 연산자는 주어진 객체의 형을 판별합니다.

`+`

단항 더하기 연산자는 피연산자를 숫자로 변환합니다.

`-`

단항 부정 연산자는 피연산자를 숫자로 변환한 뒤 부호를 바꿉니다.

`~`

비트 NOT 연산자.

`!`

논리 NOT 연산자.

### 산술 연산자

산술 연산자는 피연산자로 숫자 값(리터럴이나 변수)을 취하고 숫자 값 하나를 반환합니다.

`+`

더하기 연산자.

`-`

빼기 연산자.

`/`

나누기 연산자.

`*`

곱하기 연산자.

`%`

나머지 연산자.

`**`

거듭제곱 연산자.

### 관계 연산자

비교 연산자는 피연산자를 비교하고, 비교가 참인지 여부를 나타내는 `Boolean` 값을 반환합니다.

`in`

`in` 연산자는 객체에 주어진 속성이 있는지를 결정합니다.

`instanceof`

`instanceof` 연산자는 객체가 다른 객체의 인스턴스인지 판별합니다.

`<` (en-US)

작음 연산자.

`>` (en-US)

큼 연산자.

`<=` (en-US)

작거나 같음 연산자.

`>=` (en-US)

크거나 같음 연산자.

**참고: =>** 는 연산자가 아니고, 화살표 함수의 표기법입니다.

### 같음 연산자

같음 연산자의 평가 결과는 항상 `Boolean` 형으로 비교가 참인지 나타냅니다.

`==`

동등 연산자.

`!=`

부등 연산자.

`===` (en-US)

일치 연산자.

`!==` (en-US)

불일치 연산자.

### 비트 시프트 연산자

피연산자의 모든 비트를 시프트하는 연산.

`<<`

비트 좌로 시프트 연산자.

`>>` (en-US)

비트 우로 시프트 연산자.

`>>>` (en-US)

비트 부호 없는 우로 시프트 연산자.

### 이진 비트 연산자

비트 연산자는 피연산자를 32비트 집합(0과 1)으로 다루고 표준 JavaScript 숫자 값을 반환합니다.

`&`

비트 AND.

`|` (en-US)

비트 OR.

`^` (en-US)

비트 XOR.

### 이진 논리 연산자

논리 연산자는 보통 사용될 때 불리언(논리) 값으로 사용되고, 불리언 값을 반환합니다.

`&&`

논리 AND.

`||`

논리 OR.

`??`

Nullish 통합 연산자.

### 조건부(삼항) 연산자

`(condition ? ifTrue : ifFalse)`

조건부 연산자는 조건의 논리값에 따라 두 값 중 하나를 반환합니다.

### 선택적 연결 연산자

`?.`

선택적 연결 연산자는 참조가 nullish (`null` 또는 `undefined`) 인 경우 오류를 발생시키는 대신 `undefined`를 반환합니다.

### 할당 연산자

할당 연산자는 값을 그 우변 피연산자의 값에 따라 좌변 피연산자에 할당합니다.

`=`

할당 연산자.

`*=`

곱셈 할당.

`**=`

거듭제곱 할당.

`/=`

나눗셈 할당.

`%=`

나머지 할당.

`+=`

덧셈 할당.

`-=`

뺄셈 할당

`<<=`

좌로 이동 할당.

`>>=` (en-US)

우로 이동 할당.

`>>>=`

부호 없는 우로 이동 할당.

`&=`

비트 AND 할당.

`^=` (en-US)

비트 XOR 할당.

`|=` (en-US)

비트 OR 할당.

`&&=` (en-US)

논리적 AND 할당.

`||=` (en-US)

논리적 OR 할당.

`??=` (en-US)

논리적 nullish 할당.

`[a, b] = [1, 2]`
`{a, b} = {a:1, b:2}`

구조 분해 할당은 배열 또는 객체의 속성을 배열 또는 객체 리터럴과 비슷해 보이는 구문을 사용하여 변수에 할당할 수 있게 합니다.

### 쉼표 연산자

`,`

쉼표 연산자는 여러 식을 단문으로 평가되게 하고 마지막 식의 결과를 반환합니다.

명세
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-addition-operator-plus |
| ECMAScript Language Specification # sec-assignment-operators |
| ECMAScript Language Specification # sec-async-function-definitions |
| ECMAScript Language Specification # sec-async-generator-function-definitions |
| ECMAScript Language Specification # prod-BitwiseANDExpression |
| ECMAScript Language Specification # sec-bitwise-not-operator |
| ECMAScript Language Specification # prod-BitwiseORExpression |
| ECMAScript Language Specification # prod-BitwiseXORExpression |
| ECMAScript Language Specification # sec-class-definitions |
| ECMAScript Language Specification # sec-comma-operator |
| ECMAScript Language Specification # sec-conditional-operator |
| ECMAScript Language Specification # sec-postfix-decrement-operator |
| ECMAScript Language Specification # sec-delete-operator |
| ECMAScript Language Specification # sec-destructuring-assignment |
| ECMAScript Language Specification # sec-destructuring-binding-patterns |
| ECMAScript Language Specification # sec-multiplicative-operators |
| ECMAScript Language Specification # sec-equality-operators |
| ECMAScript Language Specification # sec-exp-operator |
| ECMAScript Language Specification # sec-function-definitions |
| ECMAScript Language Specification # sec-generator-function-definitions |
| ECMAScript Language Specification # sec-relational-operators |
| ECMAScript Language Specification # sec-grouping-operator |
| ECMAScript Language Specification # sec-import-calls |
| ECMAScript Language Specification # prod-ImportMeta |
| HTML Standard # hostgetimportmetaproperties |
| ECMAScript Language Specification # sec-postfix-increment-operator |
| ECMAScript Language Specification # sec-left-shift-operator |
| ECMAScript Language Specification # prod-LogicalANDExpression |
| ECMAScript Language Specification # sec-logical-not-operator |
| ECMAScript Language Specification # prod-LogicalORExpression |
| ECMAScript Language Specification # sec-new-operator |
| ECMAScript Language Specification # sec-built-in-function-objects |
| ECMAScript Language Specification # sec-null-value |
| ECMAScript Language Specification # prod-CoalesceExpression |
| ECMAScript Language Specification # sec-object-initializer |
| ECMAScript Language Specification # prod-OptionalExpression |
| ECMAScript Language Specification # sec-property-accessors |
| ECMAScript Language Specification # sec-signed-right-shift-operator |
| ECMAScript Language Specification # prod-SpreadElement |
| ECMAScript Language Specification # prod-ArgumentList |
| ECMAScript Language Specification # prod-PropertyDefinition |
| ECMAScript Language Specification # sec-subtraction-operator-minus |
| ECMAScript Language Specification # sec-super-keyword |
| ECMAScript Language Specification # sec-this-keyword |
| ECMAScript Language Specification # sec-typeof-operator |
| ECMAScript Language Specification # sec-unary-minus-operator |
| ECMAScript Language Specification # sec-unary-plus-operator |
| ECMAScript Language Specification # sec-unsigned-right-shift-operator |
| ECMAScript Language Specification # sec-void-operator |
| ECMAScript Language Specification # prod-YieldExpression |
| ECMAScript Language Specification # sec-generator-function-definitions-runtime-semantics-evaluation |

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

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

같이 보기
-----

* 연산자 우선순위


Template literals - JavaScript

Template literals
=================

템플릿 리터럴은 내장된 표현식을 허용하는 문자열 리터럴입니다. 여러 줄로 이뤄진 문자열과 문자 보간기능을 사용할 수 있습니다. 이전 버전의 ES2015사양 명세에서는 "template strings" (템플릿 문자열) 라고 불려 왔습니다.

Syntax
------
```

    `string text`

    `string text line 1
     string text line 2`

    `string text ${expression} string text`

    tag `string text ${expression} string text`
```

Description
-----------

템플릿 리터럴은 이중 따옴표 나 작은 따옴표 대신 백틱(` `) (grave accent) 을 이용합니다. 템플릿 리터럴은 또한 플레이스 홀더를 이용하여 표현식을 넣을 수 있는데, 이는 $와 중괄호( `$ {expression}` ) 로 표기할 수 있습니다. 플레이스 홀더 안에서의 표현식과 그 사이의 텍스트는 함께 함수로 전달됩니다. 기본 함수는 단순히 해당 부분을 단일 문자열로 연결시켜 줍니다. 템플릿 리터럴 앞에 어떠한 표현식이 있다면(여기에서는 태그), 템플릿 리터럴은 "태그가 지정된 템플릿"이라고 불리게 됩니다. 이 때, 태그 표현식 (주로 함수)이 처리된 템플릿 리터럴과 함께 호출되면, 출력하기 전에 조작할 수 있습니다. 템플릿 리터럴 안에서 백틱 문자를 사용하려면 백틱 앞에 백슬러쉬(\)를 넣으십시오.

```js
`\`` === "`"; // --> true
```

### Multi-line strings

source 내에 삽입되는 newline characters(\n)은 template literal의 일부가 됩니다.

일반 string 들을 사용하여, multi-line strings 들을 얻기 위해서는 아래와 같은 문법을 사용해야 할 것입니다.

```js
console.log("string text line 1\n" + "string text line 2");
// "string text line 1
// string text line 2"
```

같은 효과를 template literal을 통해 얻기 위해서는, 아래와 같이 적을 수 있습니다.

```js
console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"
```

### Expression interpolation(표현식 삽입법)

표현식(expression)을 일반 문자열(normal strings)에 삽입하기 위해서, 당신은 다음의 문법을 사용할 수 있을 것입니다.

```js
var a = 5;
var b = 10;
console.log("Fifteen is " + (a + b) + " and\nnot " + (2 \* a + b) + ".");
// "Fifteen is 15 and
// not 20."
```

template literals을 이용하면, 이를 더욱 읽기 쉽도록 다음과 같은 문법 설탕(syntactic sugar) 을 활용할 수 있습니다.

```js
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and
not ${2 \* a + b}.`);
// "Fifteen is 15 and
// not 20."
```

### Nesting templates

특정한 경우 템플릿을 중첩하는 것이 구성 가능한 문자열을 읽는 읽기 가장 쉬운 방법입니다. 백 스페이스 템플릿 내에서 템플릿 내의 자리 표시자`${}`에 내부 백틱을 사용하는 것이 쉽습니다. 예를 들어, 조건 a가 참이면:이 템플릿을 문자 그대로 반환합니다.

In ES5:

```js
var classes = "header";
classes += isLargeScreen()
  ? ""
  : item.isCollapsed
    ? " icon-expander"
    : " icon-collapser";
```

ES2015에서 중첩(nesting)없이 템플릿 리터럴 사용한 경우:

```js
const classes = `header ${
 isLargeScreen() ? "" : item.isCollapsed ? "icon-expander" : "icon-collapser"
}`;
```

ES2015에서 중첩된(nested) 템플릿 리터럴을 사용한 경우:

```js
const classes = `header ${
 isLargeScreen() ? "" : `icon-${item.isCollapsed ? "expander" : "collapser"}`
}`;
```

### Tagged templates

template literals 의 더욱 발전된 한 형태는 *tagged* templates 입니다. 태그를 사용하면 템플릿 리터럴을 함수로 파싱 할 수 있습니다. 태그 함수의 첫 번째 인수는 문자열 값의 배열을 포함합니다. 나머지 인수는 표현식과 관련됩니다. 결국 함수는 조작 된 문자열을 반환 할 수 있습니다 (또는 다음 예제에서 설명하는 것과 완전히 다른 결과를 반환 할 수 있습니다). function 이름은 원하는 어떤 것이든 가능합니다.

```js
var person = "Mike";
var age = 28;

function myTag(strings, personExp, ageExp) {
  var str0 = strings[0]; // "that "
  var str1 = strings[1]; // " is a "

  // 사실 이 예제의 string에서 표현식이 두 개 삽입되었으므로
  // ${age} 뒤에는 ''인 string이 존재하여
  // 기술적으로 strings 배열의 크기는 3이 됩니다.
  // 하지만 빈 string이므로 무시하겠습니다.
  // var str2 = strings[2];

  var ageStr;
  if (ageExp > 99) {
    ageStr = "centenarian";
  } else {
    ageStr = "youngster";
  }

  // 심지어 이 함수내에서도 template literal을 반환할 수 있습니다.
  return str0 + personExp + str1 + ageStr;
}

var output = myTag`that ${person} is a ${age}`;

console.log(output);
// that Mike is a youngster
```

다음 예시에서 보여지듯이, Tag function 들은 string 을 반환할 필요는 없습니다.

```js
function template(strings, ...keys) {
  return function (...values) {
    var dict = values[values.length - 1] || {};
    var result = [strings[0]];
    keys.forEach(function (key, i) {
      var value = Number.isInteger(key) ? values[key] : dict[key];
      result.push(value, strings[i + 1]);
    });
    return result.join("");
  };
}

var t1Closure = template`${0}${1}${0}!`;
t1Closure("Y", "A"); // "YAY!"
var t2Closure = template`${0} ${"foo"}!`;
t2Closure("Hello", { foo: "World" }); // "Hello World!"
```

### Raw strings

태그 지정된 템플릿의 첫 번째 함수 인수에서 사용할 수있는 특별한 `raw` property을 사용하면 escape sequences 처리하지 않고 원시 문자열을 입력 한대로 액세스 할 수 있습니다.

```js
function tag(strings) {
  console.log(strings.raw[0]);
}

tag`string text line 1 \n string text line 2`;
// logs "string text line 1 \n string text line 2" ,
// including the two characters '\' and 'n'
```

추가로, default template function 과 string 병합으로 생성될 것 같은 raw string 을 생성하기 위한 `String.raw()` method가 존재합니다.

```js
var str = String.raw`Hi\n${2 + 3}!`;
// "Hi\n5!"

str.length;
// 6

str.split("").join(",");
// "H,i,\,n,5,!"
```

### Tagged templates and escape sequences

#### ES2016 behavior

ECMAScript 2016에서 tagged templates은 다음 escape sequences의 규칙을 따릅니다.

* Unicode escapes started by "\u", for example `\u00A9`
* Unicode code point escapes indicated by "\u{}", for example `\u{2F804}`
* Hexadecimal escapes started by "\x", for example `\xA9`
* Octal literal escapes started by "\" and (a) digit(s), for example `\251`

이는 다음과 같은 tagged template이 문제가 된다는 것을 의미하는데, ECMAScript문법에 따라, parser는 유효한 유니 코드 탈출 시퀀스가 있는지 확인하지만 형식이 잘못되었기 때문에 오류가 발생합니다.
```

    latex`\unicode`
    // Throws in older ECMAScript versions (ES2016 and earlier)
    // SyntaxError: malformed Unicode character escape sequence
```

#### ES2018 revision of illegal escape sequences

Tagged templates은 다른 escapes sequences가 일반적으로 사용되는 언어 (예 : DSLs 또는 LaTeX)의 임베딩을 허용해야합니다. ECMAScript proposal Template Literal Revision (4 단계, ECMAScript 2018 표준에 통합됨)은 tagged templates에서 ECMAScript escape sequences의 구문 제한을 제거합니다.

그러나 illegal escape sequences는 여전히 "cooked"라고 표현되어야합니다. "cooked"배열의 `undefined` 요소로 나타납니다 :

```js
function latex(str) {
  return { cooked: str[0], raw: str.raw[0] };
}

latex`\unicode`;

// { cooked: undefined, raw: "\\unicode" }
```

escape sequence 제한은 *tagged* templates에만 적용되며 *untagged* template literals에는 적용되지 않습니다.

>
> **Warning:** let bad = `bad escape sequence: \unicode`;
>
>
>

명세서
---

| Specification |
| --- |
| ECMAScript Language Specification # sec-template-literals |

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

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

See also
--------

* `String`
* `String.raw()`
* Lexical grammar (en-US)
* Template-like strings in ES3 compatible syntax
* "ES6 in Depth: Template strings" on hacks.mozilla.org


ReferenceError: invalid assignment left-hand side - JavaScript

ReferenceError: invalid assignment left-hand side
=================================================

메시지
---
```

    ReferenceError: invalid assignment left-hand side
```

에러 타입
-----

`ReferenceError`.

무엇이 잘못되었을까?
-----------

예상치 못한 할당이 일어났습니다. 이것은 할당 연산자(assignment operator (en-US))와 비교 연산자(comparison operator (en-US)) 간의 불일치로 인한 것일 겁니다. 예를 들면, "`=`" 부호는 값을 변수에 할당합니다. "`==`" 나 "`===`"는 값을 비교하는 연산을 합니다.

예
-

```js
if (Math.PI = 3 || Math.PI = 4) {
  console.log('no way!');
}
// ReferenceError: invalid assignment left-hand side

var str = 'Hello, '
+= 'is it me '
+= 'you\'re looking for?';
// ReferenceError: invalid assignment left-hand side
```

`if` 구문에서, 비교 연산자 ("==")로 비교하려 할 때, 문자열의 연속적인 결합의 경우에는, 플러스("+") 연산자가 필요합니다.

```js
if (Math.PI == 3 || Math.PI == 4) {
  console.log("no way!");
}

var str = "Hello, " + "from the " + "other side!";
```

참조
--

* Assignment operators (en-US)
* Comparison operators (en-US)


SyntaxError: missing : after property id - JavaScript

SyntaxError: missing : after property id
========================================

메세지
---
```

    SyntaxError: Expected ':' (Edge)
    SyntaxError: missing : after property id (Firefox)
```

에러 타입
-----

`SyntaxError`무엇이 문제일까?
---------

객체 초기자 구문으로 객체를 만들 때 콜론(`:`)은 객체의 속성을 키와 값으로 분리합니다.

```js
var obj = { propertyKey: "value" };
```

예제
--

### 콜론 vs. 등호

객체 초기자 구문에는 등호를 사용할 수 없으므로 아래 예제는 실패합니다.

```js
var obj = { propertyKey = 'value' };
// SyntaxError: missing : after property id
```

콜론을 사용하거나 객체를 생성한 뒤에 대괄호를 사용하여 새로운 속성을 할당하는 것이 바릅니다.

```js
var obj = { propertyKey: "value" };

// 또는

var obj = {};
obj["propertyKey"] = "value";
```

### 빈 속성

아래와 같이 빈 속성을 만들 수 없습니다:

```js
var obj = { propertyKey; };
// SyntaxError: missing : after property id
```

만약 값 없이 속성을 정의해야 한다면 값으로 `null`을 지정할 수 있습니다.

```js
var obj = { propertyKey: null };
```

### 계산된 속성

식으로 속성의 키를 만드는 경우 대괄호를 사용해야 합니다. 그렇지 않으면 속성 이름에 계산된 값을 사용할 수 없습니다:

```js
var obj = { 'b'+'ar': 'foo' };
// SyntaxError: missing : after property id
```

식에 대괄호를 넣으세요 `[]`:

```js
var obj = { ["b" + "ar"]: "foo" };
```

같이 보기
-----

* 객체 초기자


RangeError: repeat count must be non-negative - JavaScript

RangeError: repeat count must be non-negative
=============================================

메시지
---
```

    RangeError: repeat count must be non-negative (Firefox)
    RangeError: Invalid count value (Chrome)
```

에러 형식
-----

`RangeError`무엇이 잘못되었을까?
-----------

`String.prototype.repeat()` 메소드가 사용되었습니다. 이 메소드는 문자열이 반복되는 수를 예측하는 카운트 파라메터를 가지고 있었습니다. 이 파라메터는 0보다 크고, 양의 `Infinity` 보다는 작으며, 음수는 될수 없습니다. 이 범위는 이렇게 표현 될 수 있습니다. : [0, +∞)

예
-

### 허용되지 않는 경우

```js
"abc".repeat(-1); // RangeError
```

### 허용되는 경우

```js
"abc".repeat(0); // ''
"abc".repeat(1); // 'abc'
"abc".repeat(2); // 'abcabc'
"abc".repeat(3.5); // 'abcabcabc' (수는 정수로 변환될 것입니다.)
```

참조
--

* `String.prototype.repeat()`


TypeError: Reduce of empty array with no initial value - JavaScript

TypeError: Reduce of empty array with no initial value
======================================================

Message
-------
```

    TypeError: 초기값이 없는 빈 배열에 대해 reduce를 실행
```

Error type
----------

`TypeError`What went wrong?
----------------

JavaScript에는 reduce 함수가 여럿 있습니다.

* `Array.prototype.reduce()`, `Array.prototype.reduceRight()` and
* `TypedArray.prototype.reduce()` (en-US), `TypedArray.prototype.reduceRight()` (en-US)).

위의 함수들을 사용할 때 `initialValue`를 지정할 수 있습니다(`callback`을 처음 호출할 때 첫 번째 인자로 사용됨). 초기값을 제공하지 않으면 `Array` 또는 `TypedArray`의 첫 번째 원소를 초기값으로 사용합니다. 빈 배열을 제공해서 초기값을 반환할 수 없는 경우에 이 에러가 발생합니다.

Examples
--------

### Invalid cases

reduce 함수를 filter (`Array.prototype.filter()`, `TypedArray.prototype.filter()` (en-US))와 조합해서 사용할 때 이 에러가 자주 발생합니다. filter가 리스트의 모든 원소를 삭제하면 초기값으로 사용할 값이 없어집니다.

```js
var ints = [0, -1, -2, -3, -4, -5];
ints
  .filter((x) => x > 0) // 모든 원소를 삭제
  .reduce((x, y) => x + y); // 초기값으로 사용할 원소가 없음
```

비슷한 경우로, selector 안에 오타가 있거나 list의 원소 수가 비정상일 때에도 같은 에러가 발생할 수 있습니다.

```js
var names = document.getElementsByClassName("names");
var name_list = Array.prototype.reduce.call(
  names,
  (acc, name) => acc + ", " + name,
);
```

### Valid cases

이 문제를 해결할 수 있는 방법은 두 가지입니다.

첫 번째는 `initialValue`로 operator의 중립 원소를 제공하는 방법입니다. 예를 들어 덧셈에는 0을, 곱셈에는 1을, 문자열 결합에는 빈 문자열을 지정할 수 있습니다.

```js
var ints = [0, -1, -2, -3, -4, -5];
ints
  .filter((x) => x > 0) // 모든 원소 삭제함
  .reduce((x, y) => x + y, 0); // 덧셈에 대한 중립 원소를 초기값으로 지정
```

두 번째는 `reduce`를 호출하기 전이나 callback 내부에서 잘못된 초기값을 더하기 전에 빈 인자 문제를 처리하는 방법입니다.

```js
var names = document.getElementsByClassName("names");

var name_list1 = "";
if (names1.length >= 1)
  name_list1 = Array.prototype.reduce.call(
    names,
    (acc, name) => acc + ", " + name,
  );
// name\_list1 == "" when names is empty.

var name_list2 = Array.prototype.reduce.call(
  names,
  (acc, name) => {
    if (acc == "")
      // initial value
      return name;
    return acc + ", " + name;
  },
  "",
);
// name\_list2 == "" when names is empty.
```

See also
--------

* `Array.prototype.reduce()`
* `Array.prototype.reduceRight()`
* `TypedArray.prototype.reduce()` (en-US)
* `TypedArray.prototype.reduceRight()` (en-US)
* `Array`
* `TypedArray`
* `Array.prototype.filter()`
* `TypedArray.prototype.filter()` (en-US)


TypeError: "x" is not a constructor - JavaScript

TypeError: "x" is not a constructor
===================================

메세지
---
```

    TypeError: "x" is not a constructor
    TypeError: Math is not a constructor
    TypeError: JSON is not a constructor
    TypeError: Symbol is not a constructor
    TypeError: Reflect is not a constructor
    TypeError: Intl is not a constructor
    TypeError: SIMD is not a constructor
    TypeError: Atomics is not a constructor
```

오류 유형
-----

`TypeError`뭐가 잘못된 거죠?
----------

객체 혹은 변수를 생성자로 사용하려고 했습니다, 하지만 객체(혹은 변수)가 생성자가 아닙니다. 생성자가 무엇인지에 대한 자세한 정보는 constructor 혹은 `new` operator 를 참조하시기 바랍니다.

`String` 혹은 `Array`와 같이 `new`,를 사용하여 생성할 수 있는 전역 객체들이 있습니다. 하지만 일부 전역 객체들은 그렇지 않고 속성과 메서드가 정적입니다. 다음의 JavaScript 표준 내장 객체들은 생성자가 아닙니다: `Math`, `JSON`, `Symbol`, `Reflect`, `Intl` (en-US), `SIMD`, `Atomics`.

Generator functions 또한 생성자로 사용될 수 없습니다.

예시
--

### 유효하지 않은 경우

```js
var Car = 1;
new Car();
// TypeError: Car is not a constructor

new Math();
// TypeError: Math is not a constructor

new Symbol();
// TypeError: Symbol is not a constructor

function\* f() {}
var obj = new f();
// TypeError: f is not a constructor
```

### car 생성자

자동차(car) 객체를 만들고자 한다고 가정합니다. 이 객체의 타입을 `car`라 하고 make, model, and year 세 개의 프로퍼티를 갖습니다. 이를 위해 다음과 같은 함수를 작성할 것입니다:

```js
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
```

이제 다음과 같이 `mycar` 라 불리는 객체를 생성할 수 있습니다:

```js
var mycar = new Car("Eagle", "Talon TSi", 1993);
```

### 프라미스 이용

즉시 실행되는 프라미스를 반환하는 경우에는 \*새로운 Promise(...)\*를 생성할 필요가 없습니다.

아래는 올바른 방법이 아닙니다(프라미스 생성자가 제대로 호출되고 있지 않습니다). `TypeError: this is not a constructor` 예외를 던지게 됩니다:

```js
return new Promise.resolve(true);
```

대신, Promise.resolve() 혹은 Promise.reject() 정적 메서드를 사용하십시오:

```js
// This is legal, but unnecessarily long:
return new Promise((resolve, reject) => {
  resolve(true);
});

// Instead, return the static method:
return Promise.resolve(true);
return Promise.reject(false);
```

같이 보기
-----

* constructor
* `new` operator


SyntaxError: Malformed formal parameter - JavaScript

SyntaxError: Malformed formal parameter
=======================================

Message
-------
```

    SyntaxError: malformed formal parameter (Firefox)
```

Error type
----------

`SyntaxError`무엇이 잘못 되었을까요?
-------------

코드에는 최소한 두 개의 인수가 전달 된 `Function()` 생성자가 있습니다. 마지막 인수는 작성중인 새 함수의 소스코드 입니다. 나머지는 모두 새 함수의 인수 목록을 구성합니다.

인수 목록이 어딘가 잘못되었습니다. 아마도 실수로 인수 이름으로 if 또는 var와 같은 키워드를 선택했거나 인수 목록에 갈곳 잃은 구두점이 있을 수 있습니다. 또는 실수로 숫자나 개체와 같은 잘못된 값을 전달한 것일 수 있습니다.

그래, 내 문제가 해결됐어. 근데 왜 말 안해줬어?
----------------------------

틀림 없이 오류 메세지의 표현은 다소 이상한 부분이 있습니다. "공식 매개 변수"는 "함수 인수"를 말하는 좋은 방법입니다. 우리는 "잘못된 형식의 단어를 사용했다"라고 표현 합니다.

Examples
--------

### Invalid cases

```js
var f = Function("x y", "return x + y;");
// SyntaxError (missing a comma)

var f = Function("x,", "return x;");
// SyntaxError (extraneous comma)

var f = Function(37, "alert('OK')");
// SyntaxError (numbers can't be argument names)
```

### Valid cases

```js
var f = Function("x, y", "return x + y;"); // correctly punctuated

var f = Function("x", "return x;");

// if you can, avoid using Function - this is much faster
var f = function (x) {
  return x;
};
```

See also
--------

* `Function()`
* About functions
* *Frankenstein* by Mary Wollstonecraft Shelley, full e-text ("Cursed (although I curse myself) be the hands that formed you! You have made me wretched beyond expression. You have left me no power to consider whether I am just to you or not. Begone! Relieve me from the sight of your detested form.")


SyntaxError: missing variable name - JavaScript

SyntaxError: missing variable name
==================================

메시지
---
```

    SyntaxError: missing variable name (Firefox)
    SyntaxError: Unexpected token = (Chrome)
```

에러 타입
-----

`SyntaxError`무엇이 잘 못 되었을까?
-------------

변수에 이름이 없습니다. 이것은 코드 내의 구문 에러 때문일 수도 있습니다. 어쩌면 콤마를 잘 못 된 곳에 찍었거나, 변수명을 지을 때 애를 먹었을 수도 있습니다. 그럴 수도 있죠! 작명은 너무 어려우니까요.

예제
--

### 이름을 잃은 변수

```js
var = "foo";
```

좋은 이름을 떠올리기 어려웠을 거예요. 우리 모두 겪는 일이죠.

```js
var ohGodWhy = "foo";
```

### 예약어는 변수명이 될 수 없어요

예약어로 지정된 이름들이 변수로 쓰여 있습니다. 이것들은 사용할 수 없어요. 미안합니다. :(

```js
var debugger = "whoop";
// SyntaxError: missing variable name
```

### 여러 변수를 선언하기

여러 변수를 한 번에 선언할 때에는 콤마에 주의를 기울여야 합니다. 쓸 데없는 콤마를 더 찍지는 않았는지? 무심코 세미콜론 대신 콤마를 찍지는 않았는지?

```js
var x, y = "foo",
var x, = "foo"

var first = document.getElementById('one'),
var second = document.getElementById('two'),

// SyntaxError: missing variable name
```

올바르게 수정한 버전:

```js
var x,
  y = "foo";
var x = "foo";

var first = document.getElementById("one");
var second = document.getElementById("two");
```

### 배열

JavaScript 의 `Array` 리터럴은 대괄호로 감싸주어야 합니다. 이건 동작하지 않아요.

```js
var arr = 1,2,3,4,5;
// SyntaxError: missing variable name
```

이렇게 해야 맞습니다:

```js
var arr = [1, 2, 3, 4, 5];
```

더 보기
----

* Good variable names
* `var`
* Variable declarations in the JavaScript Guide


SyntaxError: "x" is a reserved identifier - JavaScript

SyntaxError: "x" is a reserved identifier
=========================================

메세지
---
```

    SyntaxError: The use of a future reserved word for an identifier is invalid (Edge)
    SyntaxError: "x" is a reserved identifier (Firefox)
    SyntaxError: Unexpected reserved word (Chrome)
```

에러 타입
-----

`SyntaxError`무엇이 잘못되었을까?
-----------

예약어 (en-US)가 식별자로 쓰인 경우 발생하는 에러입니다. 이 키워드는 엄격(Strict) 모드와 느슨한(Sloppy) 모드에서 모두 예약어로 취급됩니다.

* `enum`

다음은 엄격 모드의 코드에서만 예약어로 취급됩니다:

* `implements`
* `interface`
* `let`
* `package`
* `private`
* `protected`
* `public`
* `static`
예제
--

### 엄격 모드와 엄격하지 않은 모드에서의 예약어

`enum` 식별자는 일반적으로 예약되어 있습니다.

```js
var enum = { RED: 0, GREEN: 1, BLUE: 2 };
// SyntaxError: enum is a reserved identifier
```

엄격 모드의 코드에선 더 많은 식별자들이 예약되어 있습니다.

```js
"use strict";
var package = ["potatoes", "rice", "fries"];
// SyntaxError: package is a reserved identifier
```

이 변수들의 이름을 변경해야 합니다.

```js
var colorEnum = { RED: 0, GREEN: 1, BLUE: 2 };
var list = ["potatoes", "rice", "fries"];
```

### 오래된 브라우저의 업데이트

새로운 구문을 사용하기 위해서는 최근 버전의 브라우저로 업데이트 해야 합니다. 예를 들어, 오래된 브라우저를 사용하고 있다면 `let` 또는 `class` 구현할 수 없습니다.

```js
"use strict";
class DocArchiver {}

// SyntaxError: class is a reserved identifier
// (오래된 버전의 브라우저에서만 에러가 발생합니다. 예) Firefox 44 이하)
```

같이 보기
-----

* Good variable names


ReferenceError: deprecated caller or arguments usage - JavaScript

ReferenceError: deprecated caller or arguments usage
====================================================

메시지
---
```

  Warning: ReferenceError: deprecated caller usage (Firefox)
  Warning: ReferenceError: deprecated arguments usage (Firefox)
  TypeError: 'callee' and 'caller' cannot be accessed in strict mode. (Safari)
```

에러 형식
-----

엄격 모드에서만 `ReferenceError` 경고가 발생합니다. JavaScript 실행이 중단되지는 않을 것입니다.

무엇이 잘못되었을까?
-----------

엄격모드에서, `Function.caller` (en-US) 나 `Function.arguments` 속성이 사용되었고, 그러지 말아야 했습니다. 이 속성들은 사라지게 되었는데, 함수 호출자를 흘려보내거나, 비 표준이었으며, 최적화 하기 어렵고, 잠재적으로 퍼포먼스에 무리를 주었기 때문입니다.

예
-

### `function.caller` or `arguments.callee.caller`

`Function.caller` (en-US) 와 `arguments.callee.caller` 는 사라지게 되었습니다. (자세한 정보는 레퍼런스 문서를 확인해 보세요.)

```js
"use strict";

function myFunc() {
  if (myFunc.caller == null) {
    return "The function was called from the top!";
  } else {
    return "This function's caller was " + myFunc.caller;
  }
}

myFunc();
// Warning: ReferenceError: deprecated caller usage
// "The function was called from the top!"
```

### `Function.arguments`

`Function.arguments` 는 사라졌습니다. (자세한 정보는 레퍼런스 문서를 확인해 주세요.)

```js
"use strict";

function f(n) {
  g(n - 1);
}

function g(n) {
  console.log("before: " + g.arguments[0]);
  if (n > 0) {
    f(n);
  }
  console.log("after: " + g.arguments[0]);
}

f(2);

console.log("returned: " + g.arguments);
// Warning: ReferenceError: deprecated arguments usage
```

참조
--

* Deprecated and obsolete features (en-US)
* Strict mode
* `Function.arguments`
* `Function.caller` (en-US) and `arguments.callee.caller`


SyntaxError: missing ] after element list - JavaScript

SyntaxError: missing ] after element list
=========================================

메세지
---
```

    SyntaxError: missing ] after element list
```

에러 타입
-----

`SyntaxError`.

무엇이 잘못되었을까?
-----------

배열 초기자 구문에 오류가 있습니다. 닫는 대괄호("`]`") 또는 콤마("`,`")가 빠진 것 같습니다.

예제
--

### 완성되지 않은 배열 초기자

```js
var list = [1, 2,

var instruments = [
  'Ukulele',
  'Guitar',
  'Piano'
};

var data = [{foo: 'bar'} {bar: 'foo'}];
```

바르게 고치면:

```js
var list = [1, 2];

var instruments = ["Ukulele", "Guitar", "Piano"];

var data = [{ foo: "bar" }, { bar: "foo" }];
```

같이 보기
-----

* `Array`


SyntaxError: "use strict" not allowed in function with non-simple parameters - JavaScript

SyntaxError: "use strict" not allowed in function with non-simple parameters
============================================================================

Message
-------
```

    Firefox:
    SyntaxError: "use strict" not allowed in function with default parameter
    SyntaxError: "use strict" not allowed in function with rest parameter
    SyntaxError: "use strict" not allowed in function with destructuring parameter

    Chrome:
    SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list
```

Error type
----------

`SyntaxError`.

무엇이 잘못 되었을까요?
-------------

`"use strict"` 지시문은 다음 매개변수 중 한 개가 있는 함수의 맨 위에 작성됩니다:

* Default parameters
* Rest parameters
* Destructuring parameters

`"use strict"` 지시문은 ECMAScript 동작에 따라 이러한 함수의 맨 위에 허용되지 않습니다.

Examples
--------

### 기능 명세서

다음은 함수 `sum` 에는 기본 매개 변수 `a=1` 및 `b=2`가 있는 경우입니다:

```js
function sum(a = 1, b = 2) {
  // SyntaxError: "use strict" not allowed in function with default parameter
  'use strict';
  return a + b;
}
```

함수가 strict mode 모드에 있어야 하고 전체 스크립트 또는 포함된 함수가 strict mode에 있어도 괜찮으면 함수 외부에서 `"use strict"` 지시문을 이동할 수 있습니다:

```js
"use strict";
function sum(a = 1, b = 2) {
  return a + b;
}
```

### 함수 표현식

함수 표현식은 또 다른 해결방법을 사용할 수 있습니다:

```js
var sum = function sum([a, b]) {
  // SyntaxError: "use strict" not allowed in function with destructuring parameter
  'use strict';
  return a + b;
};
```

이것은 다음 표현식으로 변환 될 수 있습니다:

```js
var sum = (function () {
  "use strict";
  return function sum([a, b]) {
    return a + b;
  };
})();
```

### 화살표 함수

화살표 함수가 `this`에 접근해야 하는 경우에는, 둘러싼 함수로 화살표 함수를 사용할 수 있습니다:

```js
var callback = (...args) => {
  // SyntaxError: "use strict" not allowed in function with rest parameter
  'use strict';
  return this.run(args);
};
```

이것은 다음 표현식과 같이 변환될 수 있습니다:

```js
var callback = (() => {
  "use strict";
  return (...args) => {
    return this.run(args);
  };
})();
```

같이 보기
-----

* Strict mode
* function statement
* function expression
* Default parameters
* Rest parameters
* Destructuring parameters


Error: Permission denied to access property "x" - JavaScript

Error: Permission denied to access property "x"
===============================================

메시지
---
```

    Error: Permission denied to access property "x"
```

에러 형식
-----

`Error`.

무엇이 잘못되었을까?
-----------

접근이 허가되지 않은 객체에 접근하기 위한 시도가 있었습니다. 아마 동일 출처 정책(same-origin policy)을 침해하여 다른 도메인으로부터 로드된 `<iframe>` (en-US) 엘리먼트에 대한 것이었을 겁니다.

예
-

```html
<!doctype html>
<html>
  <head>
    <iframe
 id="myframe"
 src="http://www1.w3c-test.org/common/blank.html"></iframe>
    <script>
 onload = function () {
 console.log(frames[0].document);
 // Error: Permission denied to access property "document"
 };
 </script>
  </head>
  <body></body>
</html>
```

참조
--

* `<iframe>` (en-US)
* Same-origin policy


SyntaxError: missing ; before statement - JavaScript

SyntaxError: missing ; before statement
=======================================

메시지
---
```

    SyntaxError: missing ; before statement
```

오류 타입
-----

`SyntaxError`.

무엇이 잘 못 되었나?
------------

어딘가에 세미 콜론(`;`)이 빠져 있습니다. JavaScript 구문은 반드시 세미 콜론으로 끝나야 합니다. 일부는 자동 세미콜론 삽입 (automatic semicolon insertion (ASI) (en-US))의 영향을 받습니다. 그러나 이 경우에는 직접 세미 콜론을 써주어야 합니다. 그래야 JavaScript가 올바르게 해석 될 수 있기 때문입니다.

그러나, 가끔, 이 오류는 또 다른 오류의 결과로도 나타날 수도 있습니다. 문자열을 escape 문자로 적절히 처리해 주지 않았을 때, 또는 `var` 키워드를 잘 못 사용했을 때와 같은 경우 입니다. 또한 어딘가에 너무 많은 괄호 기호를 사용했을 것입니다. 이 오류가 발생했을 때에는 문법을 신중히 검토해야 합니다.

예제
--

### Escape 처리되지 않은 문자열

이 오류는 문자열을 escape 처리 하지 않았을 때, JavaScript 엔진이 문자열 끝을 미리 예측하여 발생합니다. 예를 들자면 아래와 같습니다. :

```js
var foo = 'Tom's bar';
// SyntaxError: missing ; before statement
```

문자열을 묶어줄 때 쌍 따옴표를 사용하거나, 역슬래시를 이용해서 홑따옴표를 사용 할 수 있습니다. :

```js
var foo = "Tom's bar";
var foo = 'Tom\'s bar';
```

### var와 함께 선언하는 것

이미 `var` 선언된 object나 array의 요소를 새로 선언 할 수 없습니다.

```js
var obj = {};
var obj.foo = 'hi'; // SyntaxError missing ; before statement

var array = [];
var array[0] = 'there'; // SyntaxError missing ; before statement
```

대신에, `var` 키워드를 생략하고 정의합니다. :

```js
var obj = {};
obj.foo = "hi";

var array = [];
array[0] = "there";
```

참조 문서
-----

* Automatic semicolon insertion (ASI) (en-US)
* JavaScript statements


SyntaxError: identifier starts immediately after numeric literal - JavaScript

SyntaxError: identifier starts immediately after numeric literal
================================================================

메세지
---
```

  SyntaxError: Unexpected identifier after numeric literal (Edge)
  SyntaxError: identifier starts immediately after numeric literal (Firefox)
  SyntaxError: Unexpected number (Chrome)
```

에러 타입
-----

`SyntaxError`무엇이 잘못되었을까?
-----------

식별자라고 불리는 변수의 이름은 반드시 지켜야 하는 특정 규칙을 따라야 합니다.

JavaScript의 식별자는 반드시 문자, 언더스코어(\_), 또는 달러 표시($)로 시작돼야 합니다. 숫자로 시작될 수 없습니다. 글자 뒤에만 숫자(0-9)가 올 수 있습니다.

예제
--

### 숫자로 시작하는 변수 이름

JavaScript에서 변수 이름은 숫자로 시작될 수 없습니다. 아래 예제는 에러가 발생합니다:

```js
var 1life = 'foo';
// SyntaxError: identifier starts immediately after numeric literal

var foo = 1life;
// SyntaxError: identifier starts immediately after numeric literal

alert(1.foo);
// SyntaxError: identifier starts immediately after numeric literal
```

숫자가 뒤에 오도록 변수 이름을 변경해야 합니다.

```js
var life1 = "foo";
var foo = life1;
```

같이 보기
-----

* 문법 (en-US)
* 변수(JavaScript Guide)