ECMAScript2015의 기본 개념에 대해 대략적으로 정리를 한 부분이다.


ECMAScript2015에서는 아래의 내용이 화면 전체 혹은 함수 내에 작성되어있는 것을 볼 수 있다.

'use strict';

이것은 '엄격모드'라고도 하며, ES6 버전에서 새롭게 추가된 기능이다. 프로그램 또는 함수를 사용할 때, 문법을 더 정확히 사용할 수 있도록 도와주는 역할로 기존에 가능했던 사용방법에서 오류가 발생할 수 있다.

- 필수 사용은 아니다.

- 모호하거나 틀린 문법에서 오류를 발생시킨다. (ex. 같은 이름의 변수 선언 등)

- IE의 경우 버전 10 이전에서는 사용이 불가하다.



1. Arrow(=>, 화살표 함수)

- ES6에서 처음 도입된 개념

- 짧은 함수 및 바인딩하지 않은 this가 arrow의 도입에 영향을 끼쳤다. (this 사용의 번거로움 해소를 위해)

- 함수 표현에 비해 구문이 짧다.

- 항상 익명으로 사용이 된다.

- 메소드가 아닌 곳에 적합하므로 생성자로 사용할 수 없다.


아래의 경우 arrow 함수 사용 형태에 대한 설명이다.

1) arrow 사용의 기본 형태

(param1, param2, ..., paramN) => {statement}

(param1, param2, ..., paramN) => expression        // {return expression}과 동일하다


2) 매개변수가 하나일 경우 괄호는 선택사항이다.

(singleParam) => {statement}

singleParam => {statement}


3) 매개변수가 없을 경우 괄호는 필수사항이다.

() => {statement}


4) 객체 리터럴 식을 반환하는 본문(body)은 괄호속에 넣어서 표현한다.

params => ({foo:bar})


5) 나머지 매개변수 및 기본 매개변수가 지원된다.

(param1, param2, ...rest) => {statement}

(param1 = defaultValue1, param2, ..., paramN = defaultValueN) => {statement}


6) 매개변수 목록 내 비구조화도 지원된다.

var f = ([a, b] = [1, 2], {x : c} = {x : a + b} => a + b + c);

f();                // 결과값


아래는 이해에 도움이 되도록 JS에서 기존 사용했던 방식과 arrow 함수를 사용한 방식이다.

// JS

function(a) { return a > 0; }


// ES6

a => a > 0


기존 콜백함수나 이벤트리스너를 arrow 함수를 이용해 새로운 방식으로 사용할 수 있다.

(콜백함수를 등록하는 시점에 this를 콜백함수에 access를 하는 경우가 발생하는데, 클로저를 이용하여 this를 속박하는 등의 방식 대신 arrow 함수로 더 효율적으로 사용할 수 있다.)


var exFunc = {

var cnt : 0,

ex1 : function(selector) {

var node = document.querySelector(selector);

node.addEventListener('click', function(evt) {

this.cnt++;

}.bind(this));

}

};

exFunc.ex1('body');

위의 내용을 아래처럼 바꿔서 사용할 수 있다.

var exFunc = {

var cnt : 0,

ex1 : function(selector) {

var node = document.querySelector(selector);

node.addEventListener('click', (evt) => {

this.cnt++;

});

}

};

exFunc.ex1('body');



아래는 바인딩되지 않는 this에 대한 예제로 arrow 함수 사용 이전에는 모든 새로운 함수는 자신의 this값을 정의해서 사용해야하는 것을 보여준다.

function addFunc() {

this.num= 0;

setInterval(function add() {

this.num++;

}, 1000);

}

var a = new addFunc();

위의 예제에는 add()함수는 this를 전역 객체로 정의하여 사용한다. 따라서 addFunc() 생성자의 this와는 다른 this이다.

아래의 예제는 비전역 변수에 할당하여 위의 문제를 해결을 하는 것이다.

function addFunc() {

var temp = this;

temp.num= 0;

setInterval(function add() {

temp.num++;

}, 1000);

}

var a = new addFunc();

위의 문제를 ES6부터는 arrow 함수를 이용하여 처리할 수 있다.

arrow 함수는 자신만의 this를 생성하지 않고, 감싸고 있는 컨텍스트의 this를 가져오므로 의도한대로의 기능을 가진다.

function addFunc() {

this.num

setInterval(() => {

this.num++;

}, 1000);

}

var a = new addFunc();

다시 말해 위의 arrow 함수를 이용한 뒤의 this는 addFunc()의 this와 같은 this이다.



2. Promise 객체

- 콜백이 중첩되어 사용되는 경우(하나의 작업을 콜백으로 처리한 뒤, 순차적으로 다음 작업을 진행하고자 하는 경우)에 사용할 수 있다.

- Promise 패턴을 사용하면 비동기 작업을 순차적으로 진행하거나, 병렬로 진행하는 등의 작업의 효율이 높아진다.

- 예외처리 구조가 잘되어 있으므로 오류처리에 대해 더 가시적인 처리가 가능하다.

- chrome 32 버전부터 native promise가 지원 가능하다.


아래는 Promise 패턴의 기본적인 예제이다.

var promiseFunc(param) {

return new Promise(function(resolve, reject) {

window.setTimeout(function() {

if (param) {

resolve("해결!");

} else {

reject(Error("실패!"));

}

}, 1000);

});

};

// 실행

promiseFunc(true)

.then(function(text) {

console.log(text);

}, function(error) {

console.error(error);

};

함수 선언은 var promiseFunc = function(param){...}; 의 형식으로 선언하여도 무관하다.

Promise 객체를 return으로 감싸는 이유는 Promise 객체 생성을 위한 것이다. 그리고 parameter를 익명함수로 가지고 있으며, resolve와 reject를 parameter로 가진다.


위의 과정을 볼 때, new Promise로 Promise가 생성되는 직후부터 resolve나 reject가 호출되기 전까지의 순간을 pending상태라고 한다.

이후, 비동기 작업을 마친 뒤, 결과물을 약속대로 전달할 수 있다면 첫번째 parameter로 주입되는 resolve 함수를 호출하고, 실패하면 두번째 parameter로 주입되는 reject함수를 호출한다.


아래는 Promise 객체의 네가지 상태를 정리한 것이다.

1. pending

: 아직 Promise를 수행중인 단계 (fullfilled 혹은 rejected 이전)

2. fullfilled

: Promise가 지켜진 상태

3. rejected

: Promise가 지켜지지 못한 상태

4. settled

: Promise 성공 여부와 무관하게 결론이 난 상태


예제에서 함수를 실행하는 부분을 보면 Promise 객체는 정상적으로 비동기화가 완료될 경우 then이라는 API가 존재하여 이를 이용한 결과를 실행한다. 위의 예제에서는 콘솔로그를 이용하여 '해결!'이라는 문구를 보여준다.

then API는 첫번째 parameter에는 성공시 호출할 함수를, 두번째 parameter에는 실패시 호출할 함수를 선언하고 Promise의 상태에 따라 수행한다.

작업 중 중간에 에러를 잡기 위해서는 catch API를 사용할 수 있다. catch API의 형태는 .catch(function(){......}) 와 같다.


* 여러개의 Promise 완료를 확인 해야하는 경우

var promise1 = new Promise(function(resolve, reject) {......});

var promise2 = new Promise(function(resolve, reject) {......});


Promise.all([promise1, promise2]).then(function(values) {

console.log("promise1과 promise2가 모두 완료됨.", values);

});

위와 같이 사용하면 promise1과 promise2를 처리하는데 시간차가 나더라도 두 promise가 모두 완료되어야 .all이 실행되어 확인이 가능하다.



3. 블록스코프

ES6부터 사용이 가능한 기능으로 기존에 사용하던 변수 var 외의 let 변수를 사용할 수 있다.

let 변수는 var와 다르게 호이스팅(hoisting)을 하지 않는다.

* 호이스팅(hoisting)

: 선언이 뒤에서 이루어진 경우, 선언된 변수나 함수가 Scope의 최상위에 위치하는 것을 의미하는 것으로 이로 인해 뒤에서 선언한 변수나 함수를 그 이전에 사용할 수 있도록 해준다.

따라서 변수가 선언된 이후부터 변수가 유효하고, 한 블록 내에서도 변수 선언 이전에는 에러처리가 된다.

같은 스코프에서 같은 이름의 변수를 다시 선언할 경우 에러처리가 된다. 하지만 변수 선언에서 문제가 되는 것이 아니라 실제로 해당 구문을 실행하면서 에러처리가 이루어지는 것이므로 같은 이름의 변수를 선언만 하고 사용하지 않을 경우 에러처리가 이루어지지 않는다.



4. 클래스 문법

class 키워드가 ES6에 추가되었지만 클래스기반 객체지향 개념이 추가된 것은 아니며, 프로토타입의 개념이다.

//클래스 선언

class Shape {

// 생성자

constructor(width, height) {

this.width = width;

this.height = height;

}

// 멤버메서드

getArea() {

return 0;

}

// static 메서드

static getType() {

return 'Shape';

}

}

위의 예제에서 class를 사용하는 방법을 확인할 수 있다.

클래스 선언을 할 때 위의 형태 대신 var Shape = class {......}의 형태로 선언할 수 있다. 이는 클래스도 함수이므로 함수표현식(function expression)으로 정의가 가능한 것이며, 클래스표현식(class expression)이라고도 한다.

+) getType()과 같이 static 메서드는 정의할 수 있으나 static 멤버를 정의할 수는 없다.


new Person();

class Person {......}

클래스 선언에서 유의할 점 중 하나는 클래스 선언에는 호이스팅(hoisting)이 적용되지 않는다는 것이다. 그러므로 위처럼 class 선언이 뒤에 나올 경우 Uncaught SyntaxError가 발생한다. 그리고 같은 이름의 클래스를 중복 선언할 경우 문법 에러가 발생한다.


class Rect extends Shape {

constructor(width, height) {

super(width, height);

}

getArea() {

return (this.width * this.height);

}

getType() {

return super.getType() + ' : Rect()';

}

}

또한 클래스를 이용하여 위와 같이 extends를 이용해 상속을 받을 수 있다.

생성자의 경우 super로 부모 참조가 가능하며, getArea()와 같이 부모의 메서드명과 같은 메서드가 있다면 부모의 메서드를 덮어쓸 수 있다. 그리고 getType()에서 확인 할 수 있듯이 멤머 메서드 내에서도 부모 인스턴스를 참조하여 사용할 수 있다.

+ Recent posts