ES6 공부를 한 지 시간이 좀 지났다..
그리고 요즘은 SCSS, React 위주의 공부를 하다보니 내가 ES6 공부를 했었던가 하는 기억조차 가물가물해지는거 같다.
원래 공부란게 하나 공부하고 뒤돌으면 까먹고.. 최근 너무 모르는거 같아 ES6 문법을 다시 읽고 있긴 한데 정리가 안돼는거 같다.
각설하고..ES6공부를 완벽하게 숙지는 못하더라도 중요 개념 정도는 집고 넘어갸아겠다는 생각이 들어서 정리를 시작하게 되었다.
ES6? ECMA2015 ?
ECMAScript is a standard script language
즉 자바스크립트 언어의 표준을 의미한다. ECMAScript 6 는 2015년 6월에 업데이트 되었다고 한다. ECMAScript의 6번째 에디션이 ES6이자 ECMA2015인 셈이다.
ES6가 뜨는 이유는 ES5에서 제공하지 않던 다양한 기능들을 제공하기 때문인데, 아쉽게도 모든 브라우저에서 ES6의 기능을 제공하지 못한다.
ES6 호환성
https://kangax.github.io/compat-table/es6/
각 브라우저마다 ES6 를 지원하는지에 대해 정리해놓은 사이트이다.
구글 Chrome 기준으로, current brower 위에 98%, 즉 대부분의 ES6기능이 크롬에서 지원 가능하다고 나온다. 반대로 IE 11은 지원 안돼는 기능들이 거의 대부분이고, Edge는 상당부분 지원가능하다고 나온다.
반면, ES5 탭을 클릭해서 들어가면 브라우저에서 거의 대부분의 ES5 기능이 지원되는 것을 알 수 있다.
보통 그래서 ES6로 개발하고 Babel을 통해 ES5로 변환해서 올리는 방식을 많이 쓴다.
babel
babel 공식 사이트 : https://babeljs.io/
바벨(Babel)은 ECMAScript 2015 이상의 코드를 이전 버전과 호환되는 JavaScript 버전으로 변환하는 데 주로 사용되는 무료 오픈 소스 JavaScript 컴파일러이다. 쉽게 말해 es6 코드를 es5로 변환해주는 도구이다.
babel은 react에서도 create react-app 통해 react를 설치하면 자동으로 들어가 있기도 하다.
위의 babel 사이트를 들어가서 es6 문법 중 하나인 화살표 함수(arrow)를 입력하면 다음과 같이 변환해준다.
1 | //es6 |
babel 설치는 babel 설치하기를 가면 알 수 있다.
본격적으로 ES6의 제공 문법에 대해서 알아보자
var와 스코프(scope)
ES6 이전에 자바스크립트에서 변수를 선언할 수 있는 방법은 var를 사용하는 것이였다. var 키워드는 다른 언어와 다르게 몇 가지 특징이 있다.
var의 특징
- var는 함수 레벨 스코프를 따른다.
- var 키워드는 생략이 가능하다.
- 변수 중복 선언을 허용한다.
- 변수 호이스팅이 발생한다.
var는 함수 레벨 스코프를 따른다.
스코프란 시야, 범위라는 뜻인데, 변수와 상수, 매개변수가 언제 어디서 정의되는지를 결정하는 유효범위를 가리킨다.
자바스크립트는 다른 프로그래밍 언어가 블록 레벨 스코프를 따르는 것과 달리 함수 레벨 스코프를 따른다는 점에서 차이가 있다.
1 | // 참고 : https://poiemaweb.com/js-scope |
위의 코드를 보면 if 문 내에서 선언된 변수 x는 if문 코드 블록 내에서만 유효하고, if 문 밖에서는 참조가 불가능하므로 에러를 발생시킨다.
그러나 자바스크립트는 함수 레벨 스코프를 따른다. 그렇기에 다음과 같은 상황이 발생하게 된다.
1 | var x = 1; //전역 변수 |
얼핏 보면 블록 스코프 밖에 있는 x는 1을 찍어낼 거 같지만 var는 함수레벨 스코프를 따르기 때문에 코드 블록 내의 x는 전역 변수가 된다.
그런데 이미 var x = 1이라는 전역변수가 있기 때문에, var에서는 변수 중복 선언이 가능하므로 별 문제 없이 x의 값을 재할당하여 새로운 값 2로 덮어쓰게 된다.
이러한 문제는 예상치 못한 에러를 종종 발생시켰고 , ES6는 이러한 var 키워드의 단점을 보완하기 위해 let과 const 키워드를 도입하였다.
let, const의 스코프(scope)
let과 const는 블록 레벨 스코프를 따른다.
위의 코드를 let으로 바꾸면 다음과 같은 결과가 나온다.
1 | let x = 1; //전역 변수 |
코드 블록({}) 내에 선언된 x는 블록 레벨 스코프를 가지며 그 블록 내에서만 사용가능한 지역변수이다. 따라서 블록 밖에 let x 와는 다른 별개의 변수이다. 또한, 코드 블록 내의 y 역시 블록 내에서만 사용 가능한 지역 변수이므로 블록 밖, 즉 외부에서 이를 참조할 수 없다. 그러므로 외부에서 이를 참조하려고 하면 참조에러(ReferenceError)를 발생시키게 된다.
스코프의 종류
정적 스코프와 동적 스코프
자바스크립트는 정적 스코프를 따른다.
1 | var x = 1; |
위 실행 결과는 함수 bar()의 상위 스코프가 무엇인지에 따라 값이 다르게 나온다.
첫 번째는 함수를 어디서 호출하는지에 따라 스코프가 결정되는 방식인, 동적 스코프이고, 두 번째는 함수를 어디서 선언했는지에 따라 값이 다르게 나오는 정적 스코프이다.
자바스크립트는 정적 스코프(렉시컬 스코프)이다. 즉 함수가 어디서 선언되었는지가 중요하지, 어디서 호출했는지는 중요하지 않다.
따라서 위의 예제를 보면 함수 bar()는 전역변수 var x = 1의 값을 참조하게 된다. 설사 foo() 함수 안에서 호출되었다고 해도 스코프 결정에 별 영향을 주지 못하므로 bar()를 두 번 호출한 것과 같은 결과인 1을 두 번 출력하게 된다.
이러한 정적 스코프는 전역 스코프, 블록 스코프 , 함수 스코프에 적용된다.
전역 스코프
전역에 변수를 선언하면 이 변수는 어디서든지 참조할 수 있는 전역 스코프를 갖는 전역 변수가 된다
1 | let name = "lee"; |
위의 name은 전역 스코프를 갖는 전역 변수이다. 이 변수는 어디서든지 참조가 가능하게 된다. 자바스크립트는 다른 언어와 달리 특별한 시작점 없이 전역 변수 선언이 가능하다. 이런 편리함때문에 전역 변수를 남발하게 되면 변수 이름이 중복되게 되고, 변수가 중복되면 값이 재할당이 되므로 의도치 않은 문제를 발생시킬 수 있다.
이러한 문제를 해결하기 위해서는 전역 스코프에 가면 확인 할 수 있다.
지역 스코프
코드의 특정 부분에서만 사용할 수 있는 변수는 지역 스코프에 있다고 할 수 있다. 함수 내부에서 선언한 변수나 , 코드 블록내에서 let,const로 선언한 변수는 외부에서 참조할 수 없으므로 지역 변수가 된다.
함수 스코프
함수 내부에서 변수를 선언하면 그 변수는 함수 내부에서만 접근이 가능한 함수 스코프를 가진다.
블록 스코프
블록의 스코프안에서만 보이는 식별자를 말한다. let,const는 식별자를 블록 스코프에서 선언한다.
이러한 블록 스코프를 중첩해서 변수 숨기기가 가능하다.
1 | //스코프 중첩 |
위 코드를 보면 외부 블록 x와 내부 블록 x는 이름만 같지 다른 지역변수이다.
그러므로 내부 블록에서는 마치 외부 스코프 x를 가리는 것과 같은 효과를 발휘하게 된다.
이러한 것을 변수 숨기기 라고 한다.
var / let / const
1) var : 함수 레벨 스코프 / let,const : 블록 레벨 스코프
2) 중복 선언 여부
var로는 동일한 이름을 갖는 변수를 중복해서 선언이 가능했지만,
let과 const로는 으로는 중복 선언이 불가능하다.
1 | //var |
3) 호이스팅
자바스크립트는 ES6에서 도입된 let,const를 포함하여 모든 선언(var, function,class..)등을 호이스팅한다.
호이스팅이란 ? : var 선언문이나 function 선언문 등을 해당 스코프의 선두로 옮긴 것처럼 동작하는 특성을 말한다.
먼저 알아야할 것은 변수는 3단계에 거쳐 생성된다는 것이다.
- 선언
: 변수를 실행 컨텍스트의 변수 객체(Variable Object)에 등록한다. 이 변수 객체는 스코프가 참조하는 대상이 된다. - 초기화
: 변수를 위한 공간을 메모리에 확보한다. 이 단계에서 변수는 undefined로 초기화된다. - 할당
: undefined로 초기화된 변수에 실제 값을 할당한다.
var
var로 선언된 변수는 선언과 초기화가 한번에 이루워진다. 즉 스코프에 변수를 선언(등록)하자마자 그 변수를 위한 공간을 메모리에 확보(초기화)가 동시에 발생한다.
단, 아직 변수에 값을 할당하지 않았으므로 undefined를 반환한다. 변수값을 할당하는 문에 도달해서야 비로소 할당 단계가 완료된다.
1 | // var 변수는 스코프의 가장 선두로 호이스팅되고 선언 단계와 초기화 단계가 실행된다. |
let
let으로 선언된 변수는 선언과 초기화가 분리되어 진행된다. 즉 스코프를 변수에 선언(등록)은 하지만, 초기화 단계는 그 변수에 도달했을 때 이뤄진다. 그러므로 초기화 이전에 변수를 참조하려고 하면 참조에러(ReferenceError)가 발생한다.
이렇게되면 변수가 선언되고 초기화 되기 전까지는 그 변수를 참조할 수 없게 되는 구간이 생기는데 이를 일시적 사각지대(Temporal Dead Zone; TDZ)라고 부른다.
1 | //let 변수는 스코프의 선두에서 선언이 실행된다.(호이스팅) |
많은 사람들이 이 코드를 보면 let이 호이스팅이 발생하지 않는것 아니냐고 생각하곤 한다.
그러나 그것이 아니고 var은 선언과 초기화가 동시에 호이스팅 되는 것이고, let은 선언만 스코프 선두로 올라가는 호이스팅이 된다고 생각하면 될 것 같다.
let과 const
let은 변할 수 있는 값을 위해, const는 변하지 않는 값(상수)를 위해 사용한다.
const는 let과 거의 비슷하나 몇 가지 차이가 있다.
- 선언과 할당
let은 재할당이 자유로우나 const는 선언과 동시에 반드시 할당이 되어야 하며 재할당이 금지된다.
1 | //let |
- const의 객체의 내용 변경
const는 재할당 자체는 불가능하지만, 할당된 객체의 내용을 추가, 삭제, 프로퍼티 값 변경 등은 가능하다.
1 | const a = {name : "somoong"}; |
NEXT : 자바스크립트의 클로저
참고 링크
let, const와 블록 레벨 스코프 : https://poiemaweb.com/es6-block-scope
자바스크립트의 변수범위와 호이스팅 : http://chanlee.github.io/2013/12/10/javascript-variable-scope-and-hoisting/
let과 const는 호이스팅 될까? : https://medium.com/korbit-engineering/let%EA%B3%BC-const%EB%8A%94-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85-%EB%90%A0%EA%B9%8C-72fcf2fac365