ECMAScript 2015 편집하기


편집하면 당신의 IP 주소가 공개적으로 기록됩니다. 계정을 만들고 로그인하면 편집 시 사용자 이름만 보이며, 위키 이용에 여러 가지 편의가 주어집니다.

편집을 취소할 수 있습니다. 이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 게시해주세요.

최신판 당신의 편집
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
</syntaxhighlight>
</source>


<code>const</code>로 선언하면 값을 변경할 수 없는 상수가 된다.
<code>const</code>로 선언하면 값을 변경할 수 없는 상수가 된다.
29번째 줄: 28번째 줄:
const x = 0;
const x = 0;
x = 3; // 에러가 발생한다.
x = 3; // 에러가 발생한다.
</syntaxhighlight>
</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
</syntaxhighlight>
</source>


<code>let</code>을 이용해 for 반복문 내에서 클로저를 더 쉽게 사용할 수 있게 되었다. 다음 예제를 보자.
<code>let</code>을 이용해 for 반복문 내에서 클로저를 더 쉽게 사용할 수 있게 되었다. 다음 예제를 보자.
52번째 줄: 51번째 줄:
arr[1](); // 3
arr[1](); // 3
arr[2](); // 3
arr[2](); // 3
</syntaxhighlight>
</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
</syntaxhighlight>
</source>
<code>let</code>을 이용해 변수를 선언시 매 반복마다 새 변수 i가 선언되기 때문에, 다음 반복이 일어나도 기존에 클로저에 캡쳐된 변수의 값이 변하지 않는다.
<code>let</code>을 이용해 변수를 선언시 매 반복마다 새 변수 i가 선언되기 때문에, 다음 반복이 일어나도 기존에 클로저에 캡쳐된 변수의 값이 변하지 않는다.


80번째 줄: 79번째 줄:
}
}
console.log(fn2(1, 2)) // 3
console.log(fn2(1, 2)) // 3
</syntaxhighlight>
</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"
</syntaxhighlight>
</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
</syntaxhighlight>
</source>
이제 매개변수 이름 뒤에 <code>= 기본값</code>을 붙여 기본값을 지정할 수 있다.
이제 매개변수 이름 뒤에 <code>= 기본값</code>을 붙여 기본값을 지정할 수 있다.
<syntaxhighlight lang="js">
<syntaxhighlight lang="js">
119번째 줄: 118번째 줄:
}
}
console.log(f()); // 5
console.log(f()); // 5
</syntaxhighlight>
</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
</syntaxhighlight>
</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
</syntaxhighlight>
</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]
</syntaxhighlight>
</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
</syntaxhighlight>
</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
</syntaxhighlight>
</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 + ".");
}
}
</syntaxhighlight>
</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."
</syntaxhighlight>
</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."
</syntaxhighlight>
</source>


=== Promise ===
=== Promise ===
223번째 줄: 222번째 줄:
     });
     });
});
});
</syntaxhighlight>
</source>


비동기 작업을 하는 함수가 <code>Promise</code>를 지원한다면, 다음과 같이 코드를 쓸 수 있다.
비동기 작업을 하는 함수가 <code>Promise</code>를 지원한다면, 다음과 같이 코드를 쓸 수 있다.
232번째 줄: 231번째 줄:
   console.log(value1 + value2);
   console.log(value1 + value2);
});
});
</syntaxhighlight>
</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번째 줄:
     // 실패시 수행할 작업
     // 실패시 수행할 작업
   });
   });
</syntaxhighlight>
</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번째 줄:
   });
   });
}
}
</syntaxhighlight>
</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", 같은 키를 두 번 사용하면 값을 덮어쓴다.
</syntaxhighlight>
</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"가 존재하므로 무시됨
</syntaxhighlight>
</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" 순서대로 출력
}
}
</syntaxhighlight>
</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가 제거된다.
</syntaxhighlight>
</source>
 
[[분류:ECMAScript]]
리브레 위키에서의 모든 기여는 크리에이티브 커먼즈 저작자표시-동일조건변경허락 3.0 라이선스로 배포됩니다(자세한 내용에 대해서는 리브레 위키:저작권 문서를 읽어주세요). 만약 여기에 동의하지 않는다면 문서를 저장하지 말아 주세요.
글이 직접 작성되었거나 호환되는 라이선스인지 확인해주세요. 리그베다 위키, 나무위키, 오리위키, 구스위키, 디시위키 및 CCL 미적용 사이트 등에서 글을 가져오실 때는 본인이 문서의 유일한 기여자여야 하고, 만약 본인이 문서의 유일한 기여자라는 증거가 없다면 그 문서는 불시에 삭제될 수 있습니다.
취소 편집 도움말 (새 창에서 열림)

| () [] [[]] {{}} {{{}}} · <!-- --> · [[분류:]] · [[파일:]] · [[미디어:]] · #넘겨주기 [[]] · {{ㅊ|}} · <onlyinclude></onlyinclude> · <includeonly></includeonly> · <noinclude></noinclude> · <br /> · <ref></ref> · {{각주}} · {|class="wikitable" · |- · rowspan=""| · colspan=""| · |}

이 문서에서 사용한 틀: