※ ES6 관련 내용은 많기 때문에 앞으로 계속 추가할 예정입니다.
※ 기초적인 내용만을 다뤘기 때문에 더 깊은 내용은 별도의 게시글에서 다룰 예정입니다.
ES6 [ECMAScript 6]
ECMA-262 기술 규격에 따라 정의하고 있는 표준화된 스크립트 프로그래밍 언어를 말합니다.
처음 접한 ES6 는 화살표 함수입니다.
// ES6 화살표 함수
var plus = (num) => num + 1;
plus(1);
// 결과
// 2
// 기존 Javascript 함수
var plus = function( num ) {
return num + 1;
}
plus(1)
// 결과
// 2
기존 Javascript 에서 함수를 만들 때와는 너무 다른 형식이었습니다.
(Java 의 Lambda 와 비슷해서 적응이 쉬웠지만, 몰랐다면 어려웠을 것 같습니다.)
1. Promise
ES5 환경에서는 외부 모듈을 사용해 Promise 를 사용했습니다.
하지만 ES6 에서는 Promise 가 표준 내장 객체로 추가돼서 외부 모듈 없이 사용할 수 있습니다.
Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.
1. 상태
상태 | 설명 |
대기(pending) | 이행하거나 거부되지 않은 초기 상태 |
이행(fulfilled) | 연산이 성공적으로 완료됨 |
거부(rejected) | 연산이 실패함 |
대기 중인 Promise 는 값과 함께 이행할수도, 거부될 수 있습니다.
이행이나 거부될 때 Promise에 연결한 처리는 그 Promise 의 then 메서드에 의해 대기열에 오릅니다.
이미 이행했거나 거부된 Promise 에 연결한 처리도 호출하므로 비동기 연산과 처리 연결 사이에 경합 조건은 없습니다.
2. 메서드
메서드 | 설명 |
Promise.all(iterable) | iterable 내의 모든 프로미스가 이행한 뒤 이행하고, 어떤 Promise가 거부하면 즉시 거부하는 Promise를 반환합니다. |
Promise.race(iterable) | iterable 내의 어떤 Promise가 이행하거나 거부하는 즉시 스스로 이행하거나 거부하는 Promise를 반환합니다. |
Promise.reject() | 주어진 이유로 거부하는 Promise 객체를 반환합니다. |
Promise.resolve() |
주어진 값으로 이행하는 Promise 객체를 반환합니다. 값이 then 가능한 (즉, then 메서드가 있는) 경우, 반환된 프로미스는 then 메서드를 따라가고 마지막 상태를 취합니다. 그렇지 않은 경우 반환된 프로미스는 주어진 값으로 이행합니다. 어떤 값이 프로미스인지 아닌지 알 수 없는 경우, Promise.resolve(value) 후 반환값을 프로미스로 처리할 수 있습니다. |
3. 예제
1. 기본 예제
let myFirstPromise = new Promise((resolve, reject) => {
setTimeout(function(){
resolve("Success!"); // Yay! Everything went well!
}, 250);
});
myFirstPromise.then((successMessage) => {
console.log("Yay! " + successMessage);
});
2. 고급 예제
다음의 작은 예제는 Promise의 동작 방식을 보여줍니다.
testPromise() 함수는 <button>을 클릭할 때마다 호출되며, window.setTimeout()을 사용해 1~3초의 무작위 간격 이후 Promise 횟수(1부터 시작하는 숫자)로 이행하는 Promise를 생성합니다.
Promise() 생성자는 Promise를 만드는 데 쓰입니다.
Promise 이행은 p1.then()을 사용하는 이행 콜백 세트를 통해 단순히 로그에 남습니다.
약간의 로그를 통해, 함수의 동기 부분이 비동기적 Promise의 완료와 어떻게 분리되어 있는지 확인할 수 있습니다.
'use strict';
var promiseCount = 0;
function testPromise() {
var thisPromiseCount = ++promiseCount;
var log = document.getElementById('log');
log.insertAdjacentHTML('beforeend', thisPromiseCount +
') 시작 (<small>동기적 코드 시작</small>)<br/>');
// 새 프로미스 생성 - 프로미스의 생성 순서를 전달하겠다는 약속을 함 (3초 기다린 후)
var p1 = new Promise(
// 실행 함수는 프로미스를 이행(resolve)하거나
// 거부(reject)할 수 있음
function(resolve, reject) {
log.insertAdjacentHTML('beforeend', thisPromiseCount +
') 프로미스 시작 (<small>비동기적 코드 시작</small>)<br/>');
// setTimeout은 비동기적 코드를 만드는 예제에 불과
window.setTimeout(
function() {
// 프로미스 이행 !
resolve(thisPromiseCount);
}, Math.random() * 2000 + 1000);
}
);
// 프로미스를 이행했을 때 할 일은 then() 호출로 정의하고,
// 거부됐을 때 할 일은 catch() 호출로 정의
p1.then(
// 이행 값 기록
function(val) {
log.insertAdjacentHTML('beforeend', val +
') 프로미스 이행 (<small>비동기적 코드 종료</small>)<br/>');
})
.catch(
// 거부 이유 기록
function(reason) {
console.log('여기서 거부된 프로미스(' + reason + ')를 처리하세요.');
});
log.insertAdjacentHTML('beforeend', thisPromiseCount +
') 프로미스 생성 (<small>동기적 코드 종료</small>)<br/>');
}
참고 자료 : MDN Promise
2. 화살표 함수(Arrow function expression)
function 표현에 비해 구문이 짧고 자신의 this, arguments, super 또는 new.target을 바인딩하지 않습니다.
화살표 함수는 항상 익명입니다.
화살표 함수는 메서드 함수가 아닌 곳에 가장 적합합니다.
(그래서 생성자로서 사용할 수 없습니다.)
1. 구문
1. 기본 구문
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// 다음과 동일합니다: => { return expression; }
// 매개변수가 하나뿐인 경우 괄호는 선택사항입니다:
(singleParam) => { statements }
singleParam => { statements }
// 매개변수가 없는 함수는 괄호가 필요합니다:
() => { statements }
2. 고급 구분
// 객체 리터럴 표현을 반환하기 위해서는 함수 본문(body)을 괄호 속에 넣습니다:
params => ({foo: bar})
// 나머지 매개변수 및 기본 매개변수를 지원합니다
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements }
// 매개변수 목록 내 구조분해할당도 지원됩니다
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
참고 자료 : MDN 화살표 함수
3. async function
AsyncFunction 객체를 반환하는 하나의 비동기 함수를 정의합니다.
비동기 함수는 이벤트 루프를 통해 비동기적으로 작동하는 함수로, 암시적으로 Promise를 사용하여 결과를 반환합니다. 그러나 비동기 함수를 사용하는 코드의 구문과 구조는, 표준 동기 함수를 사용하는것과 많이 비슷합니다.
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
Syntax
async function name(param) {
statement
}
1. 매개변수
매개변수명 | 설명 |
name | 함수의 이름 |
param | 함수에게 전달되기 위한 인자의 이름 |
statements | 함수본문을 구성하는 내용 |
2. 반환 값
Promise | async 함수에 의해 반환 된 값으로 해결되거나 async 함수 내에서 발생하는 캐치되지 않는 예외로 거부되는 값 |
참고 자료 : MDN async function
4. await
Promise를 기다리기 위해 사용됩니다. 연산자는 async function 내부에서만 사용할 수 있습니다.
Syntax
await 문은 Promise가 fulfill되거나 reject 될 때까지 async 함수의 실행을 일시 정지하고, Promise가 fulfill되면 async 함수를 일시 정지한 부분부터 실행합니다.
이때 await 문의 반환값은 Promise 에서 fulfill된 값이 됩니다.
만약 Promise가 reject되면, await 문은 reject된 값을 throw합니다.
await 연산자 다음에 나오는 문의 값이 Promise가 아니면 해당 값을 resolved Promise로 변환시킵니다.
[rv] = await expression;
명칭 | 설명 |
expression | Promise 혹은 기다릴 어떤 값입니다. |
rv | Promise에 의해 만족되는 값이 반환됩니다. Promise가 아닌 경우에는 그 값 자체가 반환됩니다. |
예제
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();
참고 자료 : MDN await
5. 템플릿 리터널(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`
템플릿 리터럴은 이중 따옴표 나 작은 따옴표 대신 백틱(` `) (grave accent) 을 이용합니다.
템플릿 리터럴은 또한 플레이스 홀더를 이용하여 표현식을 넣을 수 있는데, 이는 $와 중괄호( $ {expression} ) 로 표기할 수 있습니다.
플레이스 홀더 안에서의 표현식과 그 사이의 텍스트는 함께 함수로 전달됩니다.
기본 함수는 단순히 해당 부분을 단일 문자열로 연결시켜 줍니다.
템플릿 리터럴 앞에 어떠한 표현식이 있다면(여기에서는 태그), 템플릿 리터럴은 "태그가 지정된 템플릿"이라고 불리게 됩니다.
이 때, 태그 표현식 (주로 함수)이 처리된 템플릿 리터럴과 함께 호출되면, 출력하기 전에 조작할 수 있습니다.
템플릿 리터럴 안에서 백틱 문자를 사용하려면 백틱 앞에 백슬러쉬(\)를 넣으시면 됩니다.
`\`` === "`" // --> true
여러 줄의 문자열
기존 방식으로 여러 줄의 문자열을 처리하는 방식은 아래와 같습니다.
console.log("string text line 1\n"+
"string text line 2");
// "string text line 1
// string text line 2"
Template Literals 를 이용하면 아래와 같습니다.
console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"
참고 자료 : MDN Template Literals
6. 구조분해 할당(Destructuring assignment)
구조 분해 할당 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다.
let a, b, rest;
[a, b] = [10, 20];
console.log(a);
// expected output: 10
console.log(b);
// expected output: 20
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(rest);
// expected output: Array [30,40,50]
기본 변수 할당
var foo = ["one", "two", "three"];
var [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"
선언에서 분리한 할당
변수의 선언이 분리되어도 구조 분해를 통해 값을 할당할 수 있습니다.
var a, b;
[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2
기본 값
변수에 기본값을 할당하면, 분해한 값이 undefined일 때 그 값을 대신 사용합니다.
var a, b;
[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7
변수 값 교환
하나의 구조 분해 표현식만으로 두 변수의 값을 교환할 수 있습니다.
var a = 1;
var b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
객체 구조 분해
var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true
참고 자료 : MDN 구조분해할당
8. const, let
const | 블록 범위의 상수를 선언합니다. 상수의 값은 재할당 할 수 없고 다시 선언할 수도 없습니다. |
let | 블록 유효 범위를 갖는 지역 변수를 선언합니다. 선언과 동시에 임의의 값으로 초기화 할 수 있습니다. |
let 은 재할당이 가능하지만 const 는 재할당이 불가능입니다.
const
const number = 42;
try {
number = 99;
} catch (err) {
console.log(err);
}
console.log(number);
// expected output: 42
const 는 반드시 선언과 동시에 할당이 이루어져야합니다.
let
let x = 1;
if (x === 1) {
let x = 2;
console.log(x);
// expected output: 2
}
console.log(x);
// expected output: 1
변수 선언에는 기본적으로 const 를 사용하고 let은 재할당이 필요한 경우에 사용하는 것이 좋습니다.
※ ES6 에서는 var 를 사용하지 않는 것이 좋습니다.
9. 클래스(Classes)
Class는 객체를 생성하기 위한 템플릿입니다.
Class는 데이터와 이를 조작하는 코드를 하나로 추상화합니다.
자바스크립트에서 Class는 프로토타입을 이용해서 만들어졌지만 ES5의 Class 의미와는 다른 문법과 의미를 가집니다.
Class 를 정의하는 방법은 class 선언을 이용하는 것입니다.
class 를 선언하기 위해서는 class의 이름과 함께 class 를 사용해야합니다.
(java 의 class 와 비슷합니다.)
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
호이스팅(Hoisting)
함수 선언과 Class 선언의 중요한 차이점은 함수 선언은 호이스팅이 일어나지만 Class 선언은 그렇지 않습니다.
const p = new Rectangle(); // ReferenceError
class Rectangle {}
Class 표현식
Class 표현식은 이름을 가질 수도 있고 갖지 않을 수도 있습니다.
름을 가진 class 표현식의 이름은 Class body의 local scope에 한해 유효합니다.
(하지만, Class의 (인스턴스 이름이 아닌) name 속성을 통해 찾을 수 있습니다.)
// 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"
Constructor(생성자)
constructor 메서드는 class 로 생성된 객체를 생성하고 초기화하기 위한 특수한 메서드입니다.
constructor 라는 이름을 가진 특수한 메서드는 Class 안에 한 개만 존재할 수 있습니다.
만약 Class 에 여러 개의 constructor 메서드가 존재하면 SyntaxError 가 발생할 것입니다.
constructor는 부모 Class 의 constructor를 호출하기 위해 super 키워드를 사용할 수 있습니다.
프로토타입 메서드 (Prototype Method)
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
클래스 상속(extends)
extends 는 Class 선언이나 Class 표현식에서 다른 Class의 자식 Class를 생성하기 위해 사용됩니다.
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.
상위클래스 호출(super)
super 는 객체의 부모가 가지고 있는 메서드를 호출하기 위해 사용합니다.
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.
ES6 에서 Class 는 java와 비슷한 부분이 많습니다.
참고자료 : MDN Classes
10. 모듈(Modules)
ES6 에서 모듈을 공식적으로 제공하기 전까지는 CommonJS, AMD, RequireJS 등의 비공식 모듈 스팩을 사용해 왔습니다. 이제는 import 와 export 를 이용해 모듈을 불러오고 내보낼 수 있습니다.
import
import 문(statement)을 사용하고, 가져올 목록을 쉼표로 구분하여 나열한 뒤 괄호로 묶습니다.
그 뒤에는 from을 쓰고 모듈 파일의 경로를 작성합니다.
import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
import randomSquare from './modules/square.js';
import {default as randomSquare} from './modules/square.js';
export
functions, var, let, const, class를 내보낼 수 있지만, 최상위 항목이어야 합니다.
예를들어, 함수 안에서 export를 사용할 수 없습니다.
export { name, draw, reportArea, reportPerimeter };
export const name = 'square';
export function draw(ctx, length, x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, length, length);
return {
length: length,
x: x,
y: y,
color: color
};
}
export default function(ctx) {
...
}
참고 자료 : MDN JavaScript modules
11. 전개 구문(Spread syntax)
전개 구문을 사용하면 배열이나 문자열과 같이 반복 가능한 문자를 0개 이상의 인수 (함수로 호출할 경우) 또는 요소 (배열 리터럴의 경우)로 확장하여, 0개 이상의 키-값의 쌍으로 객체로 확장시킬 수 있습니다.
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
// expected output: 6
console.log(sum.apply(null, numbers));
// expected output: 6
// 함수 호출
myFunction(...iterableObj);
// 배열 리터럴과 문자열
[...iterableObj, '4', 'five', 6];
// 객체 리터럴
let objClone = { ...obj };
참고 자료 : MDN Spread syntax
12. 호이스팅(Hoisting)
호이스팅(hoisting)은 ECMAScript 2015 언어 명세 및 그 이전 표준 명세에서 사용된 적이 없는 용어입니다.
호이스팅을 변수 및 함수 선언이 물리적으로 작성한 코드의 상단으로 옮겨지는 것으로 가르치지만, 실제로는 그렇지 않습니다.
변수 및 함수 선언은 컴파일 단계에서 메모리에 저장되지만, 코드에서 입력한 위치와 정확히 일치한 곳에 있습니다.
JavaScript가 어떤 코드 구분을 실행하기 전에 함수 선언을 메모리에 저장하는 방식의 장점 중 하나는 코드에서 선언하기 전에 함수를 사용할 수 있다는 것입니다.
먼저 함수를 작성하고 난 뒤에 함수를 호출합니다.
function catName(name) {
console.log("My cat's name is " + name);
}
catName("Tigger");
/*
위 코드의 결과는: "My cat's name is Tigger"
*/
먼저 함수를 호출하고 함수를 작성합니다.
catName("Chloe");
function catName(name) {
console.log("My cat's name is " + name);
}
/*
위 코드의 결과는: "My cat's name is Chloe"
*/
위 두개의 코드는 모두 정상적으로 동작합니다. 이유는 JavaScript 에서 컨텍스트 실행이 작동하는 방식 때문입니다.
Hoisting은 다른 데이터 타입 및 변수와도 잘 작동합니다.
변수는 선언하기 전에 초기화하여 사용될 수 있습니다. 그러나 초기화 없이는 사용할 수 없습니다.
JavaScript는 초기화가 아닌 선언만 끌어올립니다(hoist).
만약 변수를 선언한 뒤 나중에 초기화시켜 사용한다면, 그 값은 undefined로 지정됩니다.
var x = 1; // x 초기화
console.log(x + " " + y); // '1 undefined'
var y = 2;
// 아래 코드는 이전 코드와 같은 방식으로 동작합니다.
var x = 1; // Initialize x
var y; // Declare y
console.log(x + " " + y); // '1 undefined'
y = 2; // Initialize y
참고 자료 : MDN Hoisting
※ ES6 사용하는 방법
ES6 는 확정되었지만 아직 모든 브라우저에서 완전하게 지원되지는 않습니다.
그래서 ES6를 사용하고 싶다면 Babel과 같은 컴파일러를 사용해야합니다.
(Babel 은 독립 실행형 도구로 실행하거나 빌드 시스템에서 사용할 수 있습니다.)
'개발 > javascript' 카테고리의 다른 글
Optional chaining (0) | 2023.06.01 |
---|
댓글