편집을 취소할 수 있습니다. 이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 게시해주세요.
최신판 | 당신의 편집 | ||
11번째 줄: | 11번째 줄: | ||
== 추가 및 변경점 == | == 추가 및 변경점 == | ||
=== let, const === | === let, const === | ||
ES6 이전에는 변수를 선언하기 위해 <code>var</code>키워드를 사용했다. 기존 <code>var</code>로 선언한 변수는 함수 스코프를 가지고 있었지만 <code>let</code>과 <code>const</code>로 선언한 변수나 상수는 블록 스코프를 가진다. 즉 중괄호 블록을 벗어나면 변수를 참조할 수 없게 된다. | ES6 이전에는 변수를 선언하기 위해 <code>var</code>키워드를 사용했다. 기존 <code>var</code>로 선언한 변수는 함수 스코프를 가지고 있었지만 <code>let</code>과 <code>const</code>로 선언한 변수나 상수는 블록 스코프를 가진다. 즉 중괄호 블록을 벗어나면 변수를 참조할 수 없게 된다. | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
{ | { | ||
23번째 줄: | 22번째 줄: | ||
} | } | ||
console.log(b) // ReferenceError: b is not defined | console.log(b) // ReferenceError: b is not defined | ||
</ | </source> | ||
<code>const</code>로 선언하면 값을 변경할 수 없는 상수가 된다. | <code>const</code>로 선언하면 값을 변경할 수 없는 상수가 된다. | ||
29번째 줄: | 28번째 줄: | ||
const x = 0; | const x = 0; | ||
x = 3; // 에러가 발생한다. | x = 3; // 에러가 발생한다. | ||
</ | </source> | ||
<code>var</code>로 선언한 변수와는 달리, <code>let</code>을 이용해 같은 스코프 내에 같은 이름의 변수를 두 번 만들면 에러를 발생시킨다. <code>var</code>로 선언한 변수를 <code>let</code>으로 다시 선언하거나, 그 반대의 경우에도 에러가 발생한다. | <code>var</code>로 선언한 변수와는 달리, <code>let</code>을 이용해 같은 스코프 내에 같은 이름의 변수를 두 번 만들면 에러를 발생시킨다. <code>var</code>로 선언한 변수를 <code>let</code>으로 다시 선언하거나, 그 반대의 경우에도 에러가 발생한다. | ||
41번째 줄: | 40번째 줄: | ||
let a = 3; // SyntaxError: redeclaration of var a | let a = 3; // SyntaxError: redeclaration of var a | ||
var b = 3; // SyntaxError: redeclaration of let b | var b = 3; // SyntaxError: redeclaration of let b | ||
</ | </source> | ||
<code>let</code>을 이용해 for 반복문 내에서 클로저를 더 쉽게 사용할 수 있게 되었다. 다음 예제를 보자. | <code>let</code>을 이용해 for 반복문 내에서 클로저를 더 쉽게 사용할 수 있게 되었다. 다음 예제를 보자. | ||
52번째 줄: | 51번째 줄: | ||
arr[1](); // 3 | arr[1](); // 3 | ||
arr[2](); // 3 | arr[2](); // 3 | ||
</ | </source> | ||
i를 출력하는 함수를 세 개 만들어 배열에 넣었는데, 결과는 모두 3을 출력하고 있다. 반복문이 끝나고 나면 i의 값이 3이 되기 때문이다. 반면 다음과 같이 <code>let</code>을 사용하면 좀 더 사용자가 원하는 동작을 볼 수 있다. | i를 출력하는 함수를 세 개 만들어 배열에 넣었는데, 결과는 모두 3을 출력하고 있다. 반복문이 끝나고 나면 i의 값이 3이 되기 때문이다. 반면 다음과 같이 <code>let</code>을 사용하면 좀 더 사용자가 원하는 동작을 볼 수 있다. | ||
63번째 줄: | 62번째 줄: | ||
arr[1](); // 1 | arr[1](); // 1 | ||
arr[2](); // 2 | arr[2](); // 2 | ||
</ | </source> | ||
<code>let</code>을 이용해 변수를 선언시 매 반복마다 새 변수 i가 선언되기 때문에, 다음 반복이 일어나도 기존에 클로저에 캡쳐된 변수의 값이 변하지 않는다. | <code>let</code>을 이용해 변수를 선언시 매 반복마다 새 변수 i가 선언되기 때문에, 다음 반복이 일어나도 기존에 클로저에 캡쳐된 변수의 값이 변하지 않는다. | ||
80번째 줄: | 79번째 줄: | ||
} | } | ||
console.log(fn2(1, 2)) // 3 | console.log(fn2(1, 2)) // 3 | ||
</ | </source> | ||
위와 아래는 같은 역할을 한다. 다음과 같은 변형 문법도 존재한다. | 위와 아래는 같은 역할을 한다. 다음과 같은 변형 문법도 존재한다. | ||
99번째 줄: | 98번째 줄: | ||
let fn3 = obj => obj.name | let fn3 = obj => obj.name | ||
console.log(fn3({ name: "aa" })) // "aa" | console.log(fn3({ name: "aa" })) // "aa" | ||
</ | </source> | ||
문법이 약간 간단해진 것 외에, <code>this</code> 바인딩 문제를 쉽게 해결할 수 있다는 장점이 있다. <code>function</code>으로 정의한 함수는 호출시 <code>this</code>가 전역 객체(브라우저에선 <code>window</code>)가 된다. 객체의 메서드인 경우 <code>this</code>가 객체를 가리키고 있는데, 여기서 익명 함수를 정의하여 사용하고자 할 때 <code>this</code>가 원래 객체가 아니라 <code>window</code>가 되는 문제를 많은 사람들이 겪었다. 이를 해결하기 위해 원래 <code>this</code>를 <code>self</code> 등으로 옮겨 놓거나, <code>.bind</code>를 이용해 <code>this</code>를 바인딩해주는 등의 귀찮음이 있었다. 반면 화살표 함수로 함수를 정의할 경우, 정의할 당시의 <code>this</code>를 그대로 화살표 함수의 <code>this</code>로 사용하여 이런 문제가 없다. | 문법이 약간 간단해진 것 외에, <code>this</code> 바인딩 문제를 쉽게 해결할 수 있다는 장점이 있다. <code>function</code>으로 정의한 함수는 호출시 <code>this</code>가 전역 객체(브라우저에선 <code>window</code>)가 된다. 객체의 메서드인 경우 <code>this</code>가 객체를 가리키고 있는데, 여기서 익명 함수를 정의하여 사용하고자 할 때 <code>this</code>가 원래 객체가 아니라 <code>window</code>가 되는 문제를 많은 사람들이 겪었다. 이를 해결하기 위해 원래 <code>this</code>를 <code>self</code> 등으로 옮겨 놓거나, <code>.bind</code>를 이용해 <code>this</code>를 바인딩해주는 등의 귀찮음이 있었다. 반면 화살표 함수로 함수를 정의할 경우, 정의할 당시의 <code>this</code>를 그대로 화살표 함수의 <code>this</code>로 사용하여 이런 문제가 없다. | ||
112번째 줄: | 111번째 줄: | ||
} | } | ||
console.log(f()); // 5 | console.log(f()); // 5 | ||
</ | </source> | ||
이제 매개변수 이름 뒤에 <code>= 기본값</code>을 붙여 기본값을 지정할 수 있다. | 이제 매개변수 이름 뒤에 <code>= 기본값</code>을 붙여 기본값을 지정할 수 있다. | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
119번째 줄: | 118번째 줄: | ||
} | } | ||
console.log(f()); // 5 | console.log(f()); // 5 | ||
</ | </source> | ||
=== 해체 할당 (Destructuring Assignment) === | === 해체 할당 (Destructuring Assignment) === | ||
127번째 줄: | 126번째 줄: | ||
let [x, y, z] = arr; // x, y, z에 각각 1, 2, 3이 대입된다. | let [x, y, z] = arr; // x, y, z에 각각 1, 2, 3이 대입된다. | ||
console.log(x, y, z); // 1 2 3 | console.log(x, y, z); // 1 2 3 | ||
</ | </source> | ||
이를 이용해 두 변수의 값을 임시 변수 없이 바꿀 수 있다. | 이를 이용해 두 변수의 값을 임시 변수 없이 바꿀 수 있다. | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
134번째 줄: | 133번째 줄: | ||
[x, y] = [y, x]; | [x, y] = [y, x]; | ||
console.log(x, y); // 10 3 | console.log(x, y); // 10 3 | ||
</ | </source> | ||
받고 싶지 않은 값은 생략할 수 있다. 또한, ...을 이용하면 남은 값을 새 배열로 받을 수도 있다. | 받고 싶지 않은 값은 생략할 수 있다. 또한, ...을 이용하면 남은 값을 새 배열로 받을 수도 있다. | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
141번째 줄: | 140번째 줄: | ||
console.log(y, z); // 2 3 | console.log(y, z); // 2 3 | ||
console.log(rest); // [4, 5] | console.log(rest); // [4, 5] | ||
</ | </source> | ||
객체에도 적용할 수 있다. 할당 구문에서, <code>:</code>가 없으면 같은 이름의 프로퍼티를 가져와 대입하며, <code>:</code>가 있으면, 그 왼쪽과 같은 이름의 프로퍼티를 가져와서 오른쪽 이름의 변수에 대입한다. | 객체에도 적용할 수 있다. 할당 구문에서, <code>:</code>가 없으면 같은 이름의 프로퍼티를 가져와 대입하며, <code>:</code>가 있으면, 그 왼쪽과 같은 이름의 프로퍼티를 가져와서 오른쪽 이름의 변수에 대입한다. | ||
148번째 줄: | 147번째 줄: | ||
let { x, y, z: a } = obj; // 프로퍼티 x, y, z를 가져와서 변수 x, y, a에 각각 대입한다. | let { x, y, z: a } = obj; // 프로퍼티 x, y, z를 가져와서 변수 x, y, a에 각각 대입한다. | ||
console.log(x, y, a); // 1 2 3 | console.log(x, y, a); // 1 2 3 | ||
</ | </source> | ||
<code>let</code>이나 <code>var</code>등의 변수 선언 키워드가 앞에 오지 않으면 문 전체를 소괄호<code>(...)</code>로 감싸줘야 한다. 그렇게 하지 않으면 해체 할당 문법이 아니라 블록 문법으로 해석해버리기 때문이다. | <code>let</code>이나 <code>var</code>등의 변수 선언 키워드가 앞에 오지 않으면 문 전체를 소괄호<code>(...)</code>로 감싸줘야 한다. 그렇게 하지 않으면 해체 할당 문법이 아니라 블록 문법으로 해석해버리기 때문이다. | ||
156번째 줄: | 155번째 줄: | ||
({ x, y, z: a } = obj); // 프로퍼티 x, y, z를 가져와서 변수 x, y, a에 각각 대입한다. | ({ x, y, z: a } = obj); // 프로퍼티 x, y, z를 가져와서 변수 x, y, a에 각각 대입한다. | ||
console.log(x, y, a); // 1 2 3 | console.log(x, y, a); // 1 2 3 | ||
</ | </source> | ||
객체에서 <code>...</code>를 사용해 나머지를 새 객체에 할당하는 기능은 [[ECMAScript 2018]]에 표준화되었다. | 객체에서 <code>...</code>를 사용해 나머지를 새 객체에 할당하는 기능은 [[ECMAScript 2018]]에 표준화되었다. | ||
169번째 줄: | 168번째 줄: | ||
console.log("My name is " + this.name + "."); | console.log("My name is " + this.name + "."); | ||
} | } | ||
</ | </source> | ||
이제 다음과 같이 작성할 수 있다. | 이제 다음과 같이 작성할 수 있다. | ||
184번째 줄: | 183번째 줄: | ||
const p = new Person("Kim"); | const p = new Person("Kim"); | ||
p.sayName() // "My name is Kim." | p.sayName() // "My name is Kim." | ||
</ | </source> | ||
<code>extends</code>를 이용해 상속도 가능하다. 상속받은 클래스의 생성자에서는 <code>super()</code>를 이용해 부모 클래스의 생성자를 호출해야 한다. | <code>extends</code>를 이용해 상속도 가능하다. 상속받은 클래스의 생성자에서는 <code>super()</code>를 이용해 부모 클래스의 생성자를 호출해야 한다. | ||
211번째 줄: | 210번째 줄: | ||
s.sayName() // "My name is Kim." | s.sayName() // "My name is Kim." | ||
s.sayScore() // "My score is 80." | s.sayScore() // "My score is 80." | ||
</ | </source> | ||
=== Promise === | === Promise === | ||
223번째 줄: | 222번째 줄: | ||
}); | }); | ||
}); | }); | ||
</ | </source> | ||
비동기 작업을 하는 함수가 <code>Promise</code>를 지원한다면, 다음과 같이 코드를 쓸 수 있다. | 비동기 작업을 하는 함수가 <code>Promise</code>를 지원한다면, 다음과 같이 코드를 쓸 수 있다. | ||
232번째 줄: | 231번째 줄: | ||
console.log(value1 + value2); | console.log(value1 + value2); | ||
}); | }); | ||
</ | </source> | ||
<code>Promise</code>를 리턴하는 함수를 실행하고 <code>.then()</code>에 다음 실행할 함수를 넣는다. <code>.then()</code>을 계속 매달아 그 다음 실행할 함수를 지정할 수 있다. 에러 처리는 <code>.catch()</code>로 한다. | <code>Promise</code>를 리턴하는 함수를 실행하고 <code>.then()</code>에 다음 실행할 함수를 넣는다. <code>.then()</code>을 계속 매달아 그 다음 실행할 함수를 지정할 수 있다. 에러 처리는 <code>.catch()</code>로 한다. | ||
244번째 줄: | 243번째 줄: | ||
// 실패시 수행할 작업 | // 실패시 수행할 작업 | ||
}); | }); | ||
</ | </source> | ||
기존 콜백 방식의 비동기 작업을 <code>Promise</code>로 바꾸려면, <code>new Promise()</code>를 이용해서 <code>Promise</code> 객체를 반환하면 된다. <code>new Promise()</code>의 인자에는 <code>(resolve, reject)</code>를 매개변수로 하는 함수를 넣어야 하는데, 그 안에서 기존 방식으로 비동기 함수를 실행하고, 성공시 <code>resolve</code>를, 실패시 <code>reject</code>를 실행하면 된다. | 기존 콜백 방식의 비동기 작업을 <code>Promise</code>로 바꾸려면, <code>new Promise()</code>를 이용해서 <code>Promise</code> 객체를 반환하면 된다. <code>new Promise()</code>의 인자에는 <code>(resolve, reject)</code>를 매개변수로 하는 함수를 넣어야 하는데, 그 안에서 기존 방식으로 비동기 함수를 실행하고, 성공시 <code>resolve</code>를, 실패시 <code>reject</code>를 실행하면 된다. | ||
256번째 줄: | 255번째 줄: | ||
}); | }); | ||
} | } | ||
</ | </source> | ||
[[ECMAScript 2017]]에서 표준으로 확정된 <code>async ... await</code>는 이 <code>Promise</code>를 이용한다. 자세한 사항은 [[ECMAScript 2017]]을 참조. | [[ECMAScript 2017]]에서 표준으로 확정된 <code>async ... await</code>는 이 <code>Promise</code>를 이용한다. 자세한 사항은 [[ECMAScript 2017]]을 참조. | ||
274번째 줄: | 273번째 줄: | ||
map.set(keyObject, "cc"); | map.set(keyObject, "cc"); | ||
console.log(map.get(keyObject)); // "cc", 같은 키를 두 번 사용하면 값을 덮어쓴다. | console.log(map.get(keyObject)); // "cc", 같은 키를 두 번 사용하면 값을 덮어쓴다. | ||
</ | </source> | ||
<code>Set</code>은 [[집합 (추상 자료형)|집합]] 자료형을 구현한 것으로, 값들을 저장하되 중복 없이 딱 한 번씩만 저장한다. 값이 존재하는지 여부를 빠르게 검사할 수 있게 된다. | <code>Set</code>은 [[집합 (추상 자료형)|집합]] 자료형을 구현한 것으로, 값들을 저장하되 중복 없이 딱 한 번씩만 저장한다. 값이 존재하는지 여부를 빠르게 검사할 수 있게 된다. | ||
284번째 줄: | 283번째 줄: | ||
console.log(set.has("bbbb")); // false | console.log(set.has("bbbb")); // false | ||
set.add("aaaa"); // 이미 "aaaa"가 존재하므로 무시됨 | set.add("aaaa"); // 이미 "aaaa"가 존재하므로 무시됨 | ||
</ | </source> | ||
<code>Map</code>과 <code>Set</code> 모두 데이터를 넣은 순서를 그대로 유지하기 때문에, 다음과 같이 순회할 때 일정한 순서를 보장한다. Python의 dictionary와 set에는 이러한 보장이 없다. | <code>Map</code>과 <code>Set</code> 모두 데이터를 넣은 순서를 그대로 유지하기 때문에, 다음과 같이 순회할 때 일정한 순서를 보장한다. Python의 dictionary와 set에는 이러한 보장이 없다. | ||
296번째 줄: | 295번째 줄: | ||
console.log(i); // "aaaa", "bbbb", "cccc" 순서대로 출력 | console.log(i); // "aaaa", "bbbb", "cccc" 순서대로 출력 | ||
} | } | ||
</ | </source> | ||
V8의 구현에 따르면 <code>Map</code>과 <code>Set</code> 모두 해시를 이용해 시간복잡도 <math>O(1)</math>로 빠르게 데이터를 넣고 존재여부를 판단하거나 값을 가져올 수 있다. | V8의 구현에 따르면 <code>Map</code>과 <code>Set</code> 모두 해시를 이용해 시간복잡도 <math>O(1)</math>로 빠르게 데이터를 넣고 존재여부를 판단하거나 값을 가져올 수 있다. | ||
320번째 줄: | 319번째 줄: | ||
} | } | ||
// 이 경우, 블록을 벗어나면 가비지 컬렉션이 수행될 때 안전하게 keyObject와 valueObject가 제거된다. | // 이 경우, 블록을 벗어나면 가비지 컬렉션이 수행될 때 안전하게 keyObject와 valueObject가 제거된다. | ||
</ | </source> | ||