ES6 업데이트 이후 let, const 사용
기본적인 변수 선언에는
const
를 사용하여 재할당을 방지하고 재할당이 필요한 경우let
을 사용하자
호이스트란, 변수의 정의가 그 범위에 따라 선언(declaration)/초기화(initialization)/할당 분리되는 것을 의미한다.
함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다.
var는 함수 스코프
function counter () {
for(var i=0; i<10; i++) {
console.log('i', i)
}
}
counter()
console.log('after loop i is', i) // ReferenceError: i is not defined
(immediately-invoked function expression)
// IIFE를 사용하면
// i is not defined가 뜬다.
(function() {
// var 변수는 여기까지 hoisting이 된다.
for(var i=0; i<10; i++) {
console.log('i', i)
}
})()
console.log('after loop i is', i) // ReferenceError: i is not defined
//////////
// var i 전역변수화 됨 IIFE
(function() {
for(i=0; i<10; i++) {
console.log('i', i)
}
})()
console.log('after loop i is', i) // after loop i is 10
IIFE는 함수 스코프처럼 보여지지만 결과는 같지 않다.
에러없이 샐행되는 이유는
i
가 hoisiting 되어global-variable
이 되었기 때문
이것을 막기위해
use-strict
사용
// 아까랑 다르게 실행하면 i is not defined라는 에러가 발생한다.
(function() {
'use strict'
for(i=0; i<10; i++) {
console.log('i', i)
}
})()
console.log('after loop i is', i) // ReferenceError: i is not defined
const와 let은 범위가 지정된 변수를 갖는다.
이 둘의 호이스팅이 실행 되기전 까지 액세스 할수 없는 것을 TDZ라 한다.
즉, let/const선언 변수는 호이스팅되지 않는 것이 아니다. 스코프에 진입할 때 변수가 만들어지고 TDZ(Temporal Dead Zone)가 생성되지만, 코드 실행이 변수가 실제 있는 위치에 도달할 때까지 액세스할 수 없는 것이다. let/const변수가 선언된 시점에서 제어흐름은 TDZ를 떠난 상태가 되며, 변수를 사용할 수 있게 된다.
ecma 6 (es6)(ECMAScript 2015) 이상의 버전에서 사용
크롬 V8 JavaScript 엔진으로 빌드된 JS 런타임기
Chrome의 V8엔진을 이용하여 브라우저에서 JavaScript를 해석하듯이 서버에서 JavaScript를 동작할 수 있도록 하는 환경(플랫폼)
말 그대로 환경이기 때문에 NodeJS만으로는 할 수 없다.
Node.js 라이브러리 내의 API는 모두 비동기. (None-Blocking) API를 실행하고 완료되기까지 기다리지않고 바로 다음 API를 실행합니다.
그리고 예전에 실행한 API가 값을 반환하면 이벤트 루프가 이를 확인하고 값을 받아옵니다.
단일 쓰레드 모델을 사용하고, 이벤트 메커니즘을 통해 서버가 멈추지 않고 반응할 수 있어 확장성을 키워줍니다.
그리고 Chrome의 V8 JavaScript 엔진을 사용하여 빠른 코드 실행을 제공하며, 버퍼링이 없습니다.
위와 같은 특징을 가지고 있어 데이터를 실시간으로 다루는 애플리케이션이나 싱글페이지 애플리케이션(SPA), 입출력이 잦은 애플리케이션을 개발할 때 뛰어난 효율성을 발휘합니다.
단, 싱글 쓰레드 모델이기 때문에 하나의 작업 자체가 시간이 많이 걸리면 전체 시스템의 성능이 아주 급격하게 나빠지므로 CPU 사용률이 높은 애플리케이션에선 Node.js 사용을 권장하지 않습니다.
// #1
console.log('Hello');
// #2
setTimeout(function() {
console.log('Bye');
}, 3000);
// #3
console.log('Hello Again');
결과
‘Hello’ 출력
‘Hello Again’ 출력
3초 있다가 ‘Bye’ 출력
비동기 콜백패턴으로 중첩하여 사용하면 가독성 및 디버깅이 힘들어짐.
그래서Promise
를 씀.
await
async
?
const a = [1, 2, 3]
const doubled = a.forEach((num, index) => {
// num나 index로 무언가 합니다.
return arr[index] = num * 2;
})
// doubled = undefined
// arr = [2, 4, 6]
const a = [1, 2, 3]
const doubled = a.map(num => {
return num * 2
})
// doubled = [2, 4, 6]
.map()이 새로운 배열을 반환한다. 즉 원본 배열의 변경을 피하려면 .map()을 단순히 배열을 반복한다면 .foreach()를 추천합니다.
“A closure is the combination of a function and the lexical environment within which that function was declared.”
클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합이다. -MDN-
위 정의에서 말하는 “함수” 란 반환된 내부함수를 의미하고 “그 함수가 선언될 때의 렉시컬 환경(Lexical environment)”란 내부 함수가 선언됐을 때의 스코프를 의미한다.
즉, 클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 말한다.
이를 조금 더 간단히 말하면 클로저는 자신이 생성될 때의 환경(Lexical environment)을 기억하는 함수다 라고 말할 수 있다.
function outerFunc() {
var x = 10;
var innerFunc = function () { console.log(x); };
return innerFunc;
}
/**
* 함수 outerFunc를 호출하면 내부 함수 innerFunc가 반환된다.
* 그리고 함수 outerFunc의 실행 컨텍스트는 소멸한다.
*/
var inner = outerFunc();
inner(); // 10
// 함수를 인자로 전달받고 함수를 반환하는 고차 함수
// 이 함수가 반환하는 함수는 클로저로서 카운트 상태를 유지하기 위한 자유 변수 counter을 기억한다.
function makeCounter(predicate) {
// 카운트 상태를 유지하기 위한 자유 변수
var counter = 0;
// 클로저를 반환
return function () {
counter = predicate(counter);
return counter;
};
}
// 보조 함수
function increase(n) {
return ++n;
}
// 보조 함수
function decrease(n) {
return --n;
}
// 함수로 함수를 생성한다.
// makeCounter 함수는 보조 함수를 인자로 전달받아 함수를 반환한다
const increaser = makeCounter(increase);
console.log(increaser()); // 1
console.log(increaser()); // 2
// increaser 함수와는 별개의 독립된 렉시컬 환경을 갖기 때문에 카운터 상태가 연동하지 않는다.
const decreaser = makeCounter(decrease);
console.log(decreaser()); // -1
console.log(decreaser()); // -2
도일 멋져요!