Search
▪️

ES2018

const & let

ES6로 넘어오면서 변수에 대한 선언은 var보다 const와 let을 통해서 선언하도록 바뀌었다.
기존 var와 const-let의 차이는 Block Scoping이다. var의 경우, 선언해둔 변수가 Block 내에 선언이 되어 있더라도 Block 밖에서도 이용할 수 있었다. 하지만 Block내에서 const-let으로 선언한 값은 Block 바깥에서 사용할 수 없도록 바뀌었다.

Template Strings (Backtick, `)

ES6이전 String에 대해서 조합을 하게 되면 String 값에 +를 사용하여 String을 만들었다.
이런 방법들은 '와 + 남발로 복잡하고, 지저분하게 길어지는 구문들이 생기기 때문에, 쉽게 String을 조합할 수 있도록 Backtick이 생겼다.
이런 Backtick 안에는 미리 정의해둔 변수나 상수 값을 이용할 수 있을 뿐 아니라, Multi Line에 대해서도 지원하기 때문에 굉장히 편리하게 쓸 수 있다.
Backtick 안에서는 Single Quotation, Double Quotation을 \ (Escaping) 없이 그대로 뽑을 수 있다.

Object Literal의 변화

ES6 이전 문법에서의 Object Literal은 Object Literal 내에 Function을 할당하는 것도 가능했고, 동적인 값을 이용하여 할당할 때는 동적으로 Object Literal 내에 값을 할당하는 것도 가능했다.
반면에 ES6에서도 이전의 기능들을 그대로 쓸 수 있는데 표기법에 대한 변경이 있다.
Object Literal에 Function을 작성하여 추가하려고 할 때, Key 값 없이 Function의 작성이 가능할 뿐 아니라 function Keyword없이 Function의 이름만으로 Function 추가가 가능하다.
또 다른 변경점은 Key와 Value의 값이 서로 같다면, 단일 Value 표기만으로 Object Literal에 할당이 가능하다.
마지막으로 동적으로 바뀌는 변수를 이용하여 Key를 할당해야 하는 경우에는 동적으로 추가하는 방법이 아니라, []내에 변수를 이용하면 변수 값에 대해서 이용하여 Object Literal에 할당 가능하다. (이전에는 이런 문법이 없어서 Object Literal의 선언이 끝나고, 추가로 할당하는 문법을 통해서 가능했었다.)

Arrow Function

기존 함수는 function() {}을 통해서 선언을 했었다. 이는 함수 선언문이라고 한다. 이렇게 선언한 함수를 변수에 할당한 것을 함수 표현식이라고 한다.
ES6부터는 이런 함수 선언문이나 함수 표현식을 () ⇒ {}와 같이 Arrow Function을 통해서 나타낼 수 있다.
() ⇒ {} 에서 한 줄만에 Return이 가능하다면 () ⇒ $returningExpression으로 줄일 수 있다.
var이 const와 let으로 완전히 대체가 되었듯이 function() {} 역시 () ⇒ {} 로 완전히 대체가 되었을까? → 그렇지 않다. 바로 this를 이용하는 경우 때문에 완전히 사라지지 않았다. function() {}와 Arrow Function의 this 동작 방식이 서로 다르다. 상황마다 필요한 동작 방식에 맞춰서 function과 Arrow Function을 이용한다.

Destructuring

ES6 이전에는 Destructuring이 없기 때문에 Object의 값을 따로 빼내어 할당하려고 하면 .(Dotting)을 이용해야 했다.
ES6부터는 .(Dotting) 없이도 값을 할당할 수 있고, 이는 이전에 할당한 값을 갖고 있는 이름을 {}내에 넣고 Object를 할당함으로써 이용할 수 있다. 이는 할당하려는 값의 수가 많아질 수록 많은 코드 절약이 가능하다.
ES6 이전이든 이후든, Function에서 this에 대한 접근을 하고 싶다면 bind()나 call()이라는 Method를 통해서 해야 한다
위와 같이 하지 않고 Function의 this에 접근을 하려면 this를 인식할 수 있도록 .(Dotting)을 이용해야 한다. 따라서 .(Dotting)을 통해서 Function 호출을 하고 싶지 않다면 할당한 값에 bind()나 call()을 이용하게 되는 것이다.
Destructuring은 Object가 아니라 Array에서도 사용이 가능하다. Array의 Destructuring은 {}가 아닌 []로 진행한다.
** Destructuring을 통해서 매개 변수 없이 바로 쓸 수 있다.

Rest 문법과 Q&A

위 Array Destructuring에서는 Index 순서대로 할당이 되기 때문에, 1개 혹은 2개 할당 후 나머지 남은 모든 Index내에 있는 값들을 하나에 담기 위해선 Spread Operator를 써야 한다.
ES6 이전에는 function() {}에서 Spread Operator와 같은 것을 사용할 때는 모든 인자들을 담은 Keyword인 arguments를 사용했었다.
Spread Operator와 arguments의 차이는 Spread Operator로 받아온 값들은 Array이지만 arguments로 받아온 값들은 Array는 아니고 유사 Array이다.
객체 참조는 일종의 얕은 복사와 같다. 깊은 복사를 원한다면 이에 대해서 찾아보도록 하자.

Callback Function & Promise 비교

비동기 Code를 작성하기 위해선 Callback Function을 작성하게 되었고, 한번 Callback Function을 작성하게 되면 그 이후의 작업을 모두 Callback Function 안에 작성을 해야 했다.
심지어 Callback Function이 여러 번 Nested 되는 순간에는 Callback Hell이 펼쳐지게 된다.
이를 해결하기 위해선, 예전 문법으로는 분명 한계가 있었다. 이런 Callback Hell을 해결하기 위해서 Callback Function들을 변수나 상수에 담아서 할당하기 시작했다. 하지만 이런 방법도 따로 선언되어 있는 부분으로 가서 읽어야 해서 가독성이 떨어지는 문제가 있었다. (Code를 역순으로 읽어야 하는 경우도 있었다.)
따라서 Callback의 여러 문제들을 해결하기 위해서 ES6부터 탄생하게 된 것이 Promise이다.
비동기 Code들은 Promise를 Return할 수 있게 되어 .then() .catch() 문법 이용이 가능해졌고 이에 따라 Nested된 Callback Hell은 어느 정도 해결이 가능했다.

Promise 이해하기

Promise는 모든 곳에 모두 다 쓰는 것이 아니라, Promise를 만드는 방법이 존재한다.
Promise는 실제로 Function이다. 하지만 Promise는 대문자로 시작하기 때문에 단순 Function이 아니라 new Keyword를 붙여서 Instance를 생성할 수 있는 Construction Function이다.
Promise는 인자로 Callback Function을 가지며 Callback Function의 인자로는 resolve, reject를 가진다. 즉, resolve, reject를 가지고 Callback Function 내에서 로직을 펼치며 작성되는 것이다. .then() .catch()에서 처리가 되는 것 역시 Promise의 Callback 내에서 로직을 처리하고 반환된 값이 Promise의 resolve라면 .then(), Promise의 reject라면 Error를 Throw하면서 .catch()로 가게 되는 것이다.
외부에서 가져온 함수들이 Promise로 작성되어 있지 않고 resolve, reject가 보이지 않는데도 .then() .catch() Method가 이용 가능한 이유는 내부적으로 Promise에 대해서 정의가 되어 있기 때문이다. 어쨌든 보이지 않더라도, Promise의 Callback Function으로서 인자로 갖는 resolve와 reject를 가지고 로직이 구현되어 있다.
Code를 참고하자. (.then() Chaining은 Return값만 있다면 가능하다.)

Promise API

Promise를 이용하는 경우 Callback Function을 갖게 되고, Callback Function 내부에 resolve, reject 인자를 가지면서 로직을 펼칠 수 있다고 했다.
여기서 무조건 성공 혹은 무조건 실패하는 Promise에 대해서는 길게 Callback Function을 작성할 필요 없이, Promise.resolve(), Promise.reject()와 같이 나타낼 수 있다.
Promise.all()이라는 Method도 있다. 이는 인자로 여러 Promise들이 존재하는 Array를 받고 .then(). catch()로 Chaining이 가능하다. 이렇게 하면 한 번에 Promise를 묶어서 실행이 가능하다. 이 때, .then()에 들어가는 Result 값은 Promise.all()에서 실행된 Promise의 결과 값들이 Array로 들어가게 된다. 만일 Array로 넘긴 Promise들 중 하나라도 Error가 있다면 .catch()로 넘어가게 된다.
Callback Function은 Promise의 all() Method처럼 사용이 불가능하다.
** Promise는 결과값을 이미 가지고 있지만, .then() .catch()를 붙이기 전까지는 값을 반환하지 않는다. 이것의 장점은, Callback Function의 경우 작성 즉시 로직을 이어가야 하지만, Promise는 .then() .catch()를 만나기 전까지 값을 갖고만 있기 때문에, 다른 로직을 작성한 이후에 값을 활용할 수 있는 것이다. (Callback Function은 값을 이용하는 부분과 로직이 합쳐져있고, Promise는 값을 갖고 오는 부분과 로직이 따로 있다는 것이다.)

Async Await

Callback Function을 Promise로 대체 되면서 Promise에 대해서 .then() .catch()를 통해 비동기 Code를 작성할 수 있었다.
가독성이 올라가긴 했지만 이에 대한 문제점이 여전히 있는데, 동기적으로 Code를 작성하는 것이 어렵다는 점과 여전히 가독성 문제가 있다는 점이다.
따라서 이런 Promise의 처리에 대한 문제점을 해결하기 위해서 나온 것이 * 라는 yield Generator이다. Code가 순서대로 처리되는 것처럼 보이게 하는 것이다. 이것이 바로 Async Await이다.