로그인하고 있지 않습니다. 편집하면 당신의 IP 주소가 공개적으로 기록됩니다. 계정을 만들고 로그인하면 편집 시 사용자 이름만 보이며, 위키 이용에 여러 가지 편의가 주어집니다.스팸 방지 검사입니다. 이것을 입력하지 마세요!== 추가 및 변경점 == === let, const === ES6 이전에는 변수를 선언하기 위해 <code>var</code>키워드를 사용했다. 기존 <code>var</code>로 선언한 변수는 함수 스코프를 가지고 있었지만 <code>let</code>과 <code>const</code>로 선언한 변수나 상수는 블록 스코프를 가진다. 즉 중괄호 블록을 벗어나면 변수를 참조할 수 없게 된다. <syntaxhighlight lang="js"> { var a = 42 } console.log(a) // 42 { let b = 42 } console.log(b) // ReferenceError: b is not defined </syntaxhighlight> <code>const</code>로 선언하면 값을 변경할 수 없는 상수가 된다. <syntaxhighlight lang="js"> const x = 0; x = 3; // 에러가 발생한다. </syntaxhighlight> <code>var</code>로 선언한 변수와는 달리, <code>let</code>을 이용해 같은 스코프 내에 같은 이름의 변수를 두 번 만들면 에러를 발생시킨다. <code>var</code>로 선언한 변수를 <code>let</code>으로 다시 선언하거나, 그 반대의 경우에도 에러가 발생한다. <syntaxhighlight lang="js"> var a = 3; var a = 7; // 문제 없음 let b = 3; let b = 7; // SyntaxError: redeclaration of let b let a = 3; // SyntaxError: redeclaration of var a var b = 3; // SyntaxError: redeclaration of let b </syntaxhighlight> <code>let</code>을 이용해 for 반복문 내에서 클로저를 더 쉽게 사용할 수 있게 되었다. 다음 예제를 보자. <syntaxhighlight lang="js"> var arr = []; for (var i = 0; i < 3; i++) { arr.push(function() { console.log(i) }); } arr[0](); // 3 arr[1](); // 3 arr[2](); // 3 </syntaxhighlight> i를 출력하는 함수를 세 개 만들어 배열에 넣었는데, 결과는 모두 3을 출력하고 있다. 반복문이 끝나고 나면 i의 값이 3이 되기 때문이다. 반면 다음과 같이 <code>let</code>을 사용하면 좀 더 사용자가 원하는 동작을 볼 수 있다. <syntaxhighlight lang="js"> var arr = []; for (let i = 0; i < 3; i++) { arr.push(function() { console.log(i) }); } arr[0](); // 0 arr[1](); // 1 arr[2](); // 2 </syntaxhighlight> <code>let</code>을 이용해 변수를 선언시 매 반복마다 새 변수 i가 선언되기 때문에, 다음 반복이 일어나도 기존에 클로저에 캡쳐된 변수의 값이 변하지 않는다. === 화살표 함수 (Arrow function) === 기존의 <code>function() {}</code>를 이용한 익명 함수 정의 대신 화살표 함수라고 부르는 새로운 함수 문법이 도입되었다. <syntaxhighlight lang="js"> let fn1 = function(a, b) { let c = a + b return c } console.log(fn1(1, 2)) // 3 let fn2 = (a, b) => { let c = a + b return c } console.log(fn2(1, 2)) // 3 </syntaxhighlight> 위와 아래는 같은 역할을 한다. 다음과 같은 변형 문법도 존재한다. <syntaxhighlight lang="js"> // 매개변수가 하나인 경우 괄호를 생략할 수 있다. let fn1 = a => { let c = 2 * a return c } console.log(fn1(1)) // 2 // 간단한 식을 바로 리턴하려면 다음과 같이 블록과 return을 생략할 수 있다. let fn2 = (a, b) => a + b console.log(fn2(1, 2)) // 3 // 둘 다 적용하는 것도 가능하다. let fn3 = obj => obj.name console.log(fn3({ name: "aa" })) // "aa" </syntaxhighlight> 문법이 약간 간단해진 것 외에, <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>undefined</code>인지 일일히 검사하여 값을 할당했다. <syntaxhighlight lang="js"> function f(x, y) { if (x === undefined) x = 3; if (y === undefined) y = 2; return x + y; } console.log(f()); // 5 </syntaxhighlight> 이제 매개변수 이름 뒤에 <code>= 기본값</code>을 붙여 기본값을 지정할 수 있다. <syntaxhighlight lang="js"> function f(x = 3, y = 2) { return x + y; } console.log(f()); // 5 </syntaxhighlight> === 해체 할당 (Destructuring Assignment) === 비구조화 할당, 구조 분해 할당 등등으로도 번역하는데, 딱 정해진게 없다. [[Python]]의 unpack과 같은 기능으로, 배열이나 객체의 구조를 분해해 그 안의 값들을 변수에 각각 할당하는 기능이다. <syntaxhighlight lang="js"> const arr = [1, 2, 3]; let [x, y, z] = arr; // x, y, z에 각각 1, 2, 3이 대입된다. console.log(x, y, z); // 1 2 3 </syntaxhighlight> 이를 이용해 두 변수의 값을 임시 변수 없이 바꿀 수 있다. <syntaxhighlight lang="js"> let x = 3; let y = 10; [x, y] = [y, x]; console.log(x, y); // 10 3 </syntaxhighlight> 받고 싶지 않은 값은 생략할 수 있다. 또한, ...을 이용하면 남은 값을 새 배열로 받을 수도 있다. <syntaxhighlight lang="js"> const arr = [1, 2, 3, 4, 5]; let [, y, z, ...rest] = arr; // y, z에 각각 2, 3이 대입된다. rest는 [4, 5]가 된다. console.log(y, z); // 2 3 console.log(rest); // [4, 5] </syntaxhighlight> 객체에도 적용할 수 있다. 할당 구문에서, <code>:</code>가 없으면 같은 이름의 프로퍼티를 가져와 대입하며, <code>:</code>가 있으면, 그 왼쪽과 같은 이름의 프로퍼티를 가져와서 오른쪽 이름의 변수에 대입한다. <syntaxhighlight lang="js"> const obj = { x: 1, y: 2, z: 3 }; let { x, y, z: a } = obj; // 프로퍼티 x, y, z를 가져와서 변수 x, y, a에 각각 대입한다. console.log(x, y, a); // 1 2 3 </syntaxhighlight> <code>let</code>이나 <code>var</code>등의 변수 선언 키워드가 앞에 오지 않으면 문 전체를 소괄호<code>(...)</code>로 감싸줘야 한다. 그렇게 하지 않으면 해체 할당 문법이 아니라 블록 문법으로 해석해버리기 때문이다. <syntaxhighlight lang="js"> const obj = { x: 1, y: 2, z: 3 }; let x, y, a; ({ x, y, z: a } = obj); // 프로퍼티 x, y, z를 가져와서 변수 x, y, a에 각각 대입한다. console.log(x, y, a); // 1 2 3 </syntaxhighlight> 객체에서 <code>...</code>를 사용해 나머지를 새 객체에 할당하는 기능은 [[ECMAScript 2018]]에 표준화되었다. === class === 자바스크립트도 [[Java]]나 [[C++]]와 같은 다른 많은 언어처럼 [[클래스]] 문법을 지원하게 되었다. 기존에는 클래스와 그 멤버를 정의하기 위해 다음과 같이 했다. <syntaxhighlight lang="js"> function Person(name) { this.name = name; } Person.prototype.say = function() { console.log("My name is " + this.name + "."); } </syntaxhighlight> 이제 다음과 같이 작성할 수 있다. <syntaxhighlight lang="js"> class Person { constructor(name) { this.name = name; } sayName() { console.log("My name is " + this.name + "."); } } const p = new Person("Kim"); p.sayName() // "My name is Kim." </syntaxhighlight> <code>extends</code>를 이용해 상속도 가능하다. 상속받은 클래스의 생성자에서는 <code>super()</code>를 이용해 부모 클래스의 생성자를 호출해야 한다. <syntaxhighlight lang="js"> class Person { constructor(name) { this.name = name; } sayName() { console.log("My name is " + this.name + "."); } } class Student extends Person { constructor(name, score) { super(name); this.score = score; } sayScore() { console.log("My score is " + this.score + "."); } } const s = new Student("Kim", 80); s.sayName() // "My name is Kim." s.sayScore() // "My score is 80." </syntaxhighlight> === Promise === 비동기 처리를 위한 객체인 <code>Promise</code>가 추가되었다. 기존 자바스크립트에서는 비동기 처리를 위해 흔히 콜백(callback)함수를 이용했다. 그러나 콜백을 이용한 비동기 처리가 반복되면 계속 함수가 안쪽으로 중첩되어 가독성과 직관성이 떨어지는 문제가 생기게 된다. 이를 [[콜백 지옥]]이라고도 부른다. 또한 콜백 패턴에서의 에러 처리는 전통적인 방식인 <code>try...catch</code>를 적용할 수 없고 콜백의 인자에 넘겨줘야 하는데, 에러를 미처 처리하지 못하고 빼먹는 등 실수에 취약했다. 이러한 문제를 해결하기 위해 도입된 패턴이 Promise 패턴이다. ES6 이전에도 라이브러리를 통해 지원되어 사용하는 경우가 있었는데, ES6에서 이를 표준화한 것이다. 전통적인 비동기 처리 방식은 다음과 같았다. <code>asyncTask1</code>과 <code>asyncTask2</code>를 수행해서 그 반환값을 더해 출력하는 작업이다. <syntaxhighlight lang="javascript"> asyncTask1(function (value1) { asyncTask2(function (value2) { console.log(value1 + value2); }); }); </syntaxhighlight> 비동기 작업을 하는 함수가 <code>Promise</code>를 지원한다면, 다음과 같이 코드를 쓸 수 있다. <syntaxhighlight lang="javascript"> asyncTask1() .then(() => asyncTask2()) .then(() => { console.log(value1 + value2); }); </syntaxhighlight> <code>Promise</code>를 리턴하는 함수를 실행하고 <code>.then()</code>에 다음 실행할 함수를 넣는다. <code>.then()</code>을 계속 매달아 그 다음 실행할 함수를 지정할 수 있다. 에러 처리는 <code>.catch()</code>로 한다. <syntaxhighlight lang="javascript"> somethingAsync(value1) .then((result) => { // 성공시 수행할 작업 }) .catch((error) => { // 실패시 수행할 작업 }); </syntaxhighlight> 기존 콜백 방식의 비동기 작업을 <code>Promise</code>로 바꾸려면, <code>new Promise()</code>를 이용해서 <code>Promise</code> 객체를 반환하면 된다. <code>new Promise()</code>의 인자에는 <code>(resolve, reject)</code>를 매개변수로 하는 함수를 넣어야 하는데, 그 안에서 기존 방식으로 비동기 함수를 실행하고, 성공시 <code>resolve</code>를, 실패시 <code>reject</code>를 실행하면 된다. <syntaxhighlight lang="javascript"> function newAsyncFunction() { return new Promise((resolve, reject) => { oldAsyncFunction((error, ret) => { if (error) reject(error); else resolve(ret); }); }); } </syntaxhighlight> [[ECMAScript 2017]]에서 표준으로 확정된 <code>async ... await</code>는 이 <code>Promise</code>를 이용한다. 자세한 사항은 [[ECMAScript 2017]]을 참조. === 컬렉션 === 다른 객체들을 담기 위한 컬렉션 객체들이 추가되었다. <code>Map</code>, <code>Set</code>, <code>WeakMap</code>, <code>WeakSet</code>이 새로 추가된 객체들이다. <code>Map</code>은 키-값 쌍(key-value pair)을 저장할 수 있는 컬렉션이다. 이미 자바스크립트의 객체(<code>{}</code>)는 키-값의 쌍을 저장하기는 하지만 객체의 기본 내장 메서드들과 이름이 충돌하는 문제가 있을 수 있고, 키가 문자열과 ES6에서 추가된 Symbol로만 한정되는 문제가 있다. <code>Map</code>은 데이터를 추가하거나 가져오는 메서드를 분리하여 데이터와 내장 메서드가 충돌하는 문제를 해결하였고, 문자열 뿐 아니라 숫자나 심지어 다른 객체를 키로 사용할 수 있다. <code>Map</code>은 다음과 같이 사용한다. <syntaxhighlight lang="js"> let map = new Map(); map.set(300, "aa"); let keyObject = { a: "b" }; map.set(keyObject, "bb"); console.log(map.get(300)); // "aa" console.log(map.get(keyObject)); // "bb" map.set(keyObject, "cc"); console.log(map.get(keyObject)); // "cc", 같은 키를 두 번 사용하면 값을 덮어쓴다. </syntaxhighlight> <code>Set</code>은 [[집합 (추상 자료형)|집합]] 자료형을 구현한 것으로, 값들을 저장하되 중복 없이 딱 한 번씩만 저장한다. 값이 존재하는지 여부를 빠르게 검사할 수 있게 된다. <syntaxhighlight lang="js"> let set = new Set(); set.add("aaaa"); console.log(set.has("aaaa")); // true console.log(set.has("bbbb")); // false set.add("aaaa"); // 이미 "aaaa"가 존재하므로 무시됨 </syntaxhighlight> <code>Map</code>과 <code>Set</code> 모두 데이터를 넣은 순서를 그대로 유지하기 때문에, 다음과 같이 순회할 때 일정한 순서를 보장한다. Python의 dictionary와 set에는 이러한 보장이 없다. <syntaxhighlight lang="js"> let set = new Set(); set.add("aaaa"); set.add("bbbb"); set.add("cccc"); for (let i of set) { console.log(i); // "aaaa", "bbbb", "cccc" 순서대로 출력 } </syntaxhighlight> V8의 구현에 따르면 <code>Map</code>과 <code>Set</code> 모두 해시를 이용해 시간복잡도 <math>O(1)</math>로 빠르게 데이터를 넣고 존재여부를 판단하거나 값을 가져올 수 있다. <code>Map</code>, <code>Set</code>의 경우 키와 값에 대해 강한 레퍼런스를 가지고 있기 때문에, 키(<code>Set</code>의 경우에는 키=값으로 생각하면 된다)를 정의한 블록에서 벗어나 더는 그 키를 이용할 수 없게 되었더라도 <code>Map</code>이나 <code>Set</code>이 살아있는 한 키와 값이 계속 메모리를 차지하고 있게 된다. 즉, 메모리 누수의 위험이 항상 있다. 이러한 문제를 해결하기 위해 도입된 것이 <code>WeakMap</code>과 <code>WeakSet</code>이다. 이들은 각각 <code>Map</code>, <code>Set</code>과 같은 기능을 수행한다. 단 여기 사용된 키와 값은 가비지 컬렉션을 막지 않고, 가비지 컬렉션이 일어나면 사라지게 된다. 원래 객체의 수명 동안에만 필요한 추가 데이터를 저장한다든지 할 때 유용하게 사용할 수 있다. 단 <code>WeakMap</code>과 <code>WeakSet</code>은 넣은 객체들을 순회하거나, 가진 키-값 쌍을 모두 배열로 바꾸는 기능 등은 지원하지 않는다. 이 기능이 없기 때문에 키에 대한 레퍼런스를 잃어버리면 컬렉션에서도 접근할 수 없게 되어 안전하게 가비지 컬렉션을 수행할 수 있다. <syntaxhighlight lang="js"> let map = new Map(); { let keyObject = { a: "b" }; let valueObject = { b: "c" }; map.set(keyObject, valueObject); } // 이 경우, 블록을 벗어나도 keyObject와 valueObject의 메모리는 반환되지 않는다. let weakMap = new WeakMap(); { let keyObject = { a: "b" }; let valueObject = { b: "c" }; weakMap.set(keyObject, valueObject); } // 이 경우, 블록을 벗어나면 가비지 컬렉션이 수행될 때 안전하게 keyObject와 valueObject가 제거된다. </syntaxhighlight> [[분류:ECMAScript]] 요약: 리브레 위키에서의 모든 기여는 크리에이티브 커먼즈 저작자표시-동일조건변경허락 3.0 라이선스로 배포됩니다(자세한 내용에 대해서는 리브레 위키:저작권 문서를 읽어주세요). 만약 여기에 동의하지 않는다면 문서를 저장하지 말아 주세요. 글이 직접 작성되었거나 호환되는 라이선스인지 확인해주세요. 리그베다 위키, 나무위키, 오리위키, 구스위키, 디시위키 및 CCL 미적용 사이트 등에서 글을 가져오실 때는 본인이 문서의 유일한 기여자여야 하고, 만약 본인이 문서의 유일한 기여자라는 증거가 없다면 그 문서는 불시에 삭제될 수 있습니다. 취소 편집 도움말 (새 창에서 열림) | () [] [[]] {{}} {{{}}} · <!-- --> · [[분류:]] · [[파일:]] · [[미디어:]] · #넘겨주기 [[]] · {{ㅊ|}} · <onlyinclude></onlyinclude> · <includeonly></includeonly> · <noinclude></noinclude> · <br /> · <ref></ref> · {{각주}} · {|class="wikitable" · |- · rowspan=""| · colspan=""| · |} {{lang|}} · {{llang||}} · {{인용문|}} · {{인용문2|}} · {{유튜브|}} · {{다음팟|}} · {{니코|}} · {{토막글}} {{삭제|}} · {{특정판삭제|}}(이유를 적지 않을 경우 기각될 가능성이 높습니다. 반드시 이유를 적어주세요.) {{#expr:}} · {{#if:}} · {{#ifeq:}} · {{#iferror:}} · {{#ifexist:}} · {{#switch:}} · {{#time:}} · {{#timel:}} · {{#titleparts:}} __NOTOC__ · __FORCETOC__ · __TOC__ · {{PAGENAME}} · {{SITENAME}} · {{localurl:}} · {{fullurl:}} · {{ns:}} –(대시) ‘’(작은따옴표) “”(큰따옴표) ·(가운뎃점) …(말줄임표) ‽(물음느낌표) 〈〉(홑화살괄호) 《》(겹화살괄호) ± − × ÷ ≈ ≠ ∓ ≤ ≥ ∞ ¬ ¹ ² ³ ⁿ ¼ ½ ¾ § € £ ₩ ¥ ¢ † ‡ • ← → ↔ ‰ °C µ(마이크로) Å °(도) ′(분) ″(초) Α α Β β Γ γ Δ δ Ε ε Ζ ζ Η η Θ θ Ι ι Κ κ Λ λ Μ μ(뮤) Ν ν Ξ ξ Ο ο Π π Ρ ρ Σ σ ς Τ τ Υ υ Φ φ Χ χ Ψ ψ Ω ω · Ά ά Έ έ Ή ή Ί ί Ό ό Ύ ύ Ώ ώ · Ϊ ϊ Ϋ ϋ · ΐ ΰ Æ æ Đ(D with stroke) đ Ð(eth) ð ı Ł ł Ø ø Œ œ ß Þ þ · Á á Ć ć É é Í í Ĺ ĺ Ḿ ḿ Ń ń Ó ó Ŕ ŕ Ś ś Ú ú Ý ý Ź ź · À à È è Ì ì Ǹ ǹ Ò ò Ù ù · İ Ż ż ·  â Ĉ ĉ Ê ê Ĝ ĝ Ĥ ĥ Î î Ĵ ĵ Ô ô Ŝ ŝ Û û · Ä ä Ë ë Ï ï Ö ö Ü ü Ÿ ÿ · ǘ ǜ ǚ ǖ · caron/háček: Ǎ ǎ Č č Ď ď Ě ě Ǐ ǐ Ľ ľ Ň ň Ǒ ǒ Ř ř Š š Ť ť Ǔ ǔ Ž ž · breve: Ă ă Ğ ğ Ŏ ŏ Ŭ ŭ · Ā ā Ē ē Ī ī Ō ō Ū ū · à ã Ñ ñ Õ õ · Å å Ů ů · Ą ą Ę ę · Ç ç Ş ş Ţ ţ · Ő ő Ű ű · Ș ș Ț ț