ES6는 ECMAScript 2015로도 알려져있다.
ECMAScript는 Ecma international 의 ECMA-262 기술 규격에 정의된 표준화 스크립트 프로그래밍 언어이다. 자바스크립트를 표준화하기 위해 만들어졌고 지금도 자바스크립트가 제일 잘 알려져있지만, 액션스크립트와 J스크립트 등 다른 구현체도 포함하고 있다.
React를 이용하여 서비스를 제작하려 하니 레퍼런스 사이트를 포함한 모든 문서가 ES6 문법으로 작성되어 있어서 별 생각 없이 React는 ES6로 작성해야만 하나보다 라고 생각하다 이번 포스트를 위해 조사를 해보니 정확하지는 않지만 JavaScript로도 작성할 수 있는 것 같다.
하지만 Javascript 언어의 특성(?)으로 인해 ES6를 쓰는 이유가 있었고 이건 뒤에서 설명할 예정이다. (Arrow Function 단락에서)
따라서 오늘은 ES6 문법을 기존에 사용하던 JavaScript와 비교하여 정리한다.
let
- 기존의 var를 대체하는 키워드
- 기존의 JavaScript에서 var로 선언한 변수는 그 변수의 범위가 함수(function)으로 함수 스코프 변수여서 전역범위로 스크립트 내 어디서건 참조가 가능했다.
var v1 = 10; function varTest() { for(var i = 0; i < 10; i++) console.log(i); // 1, 2, ..., 9 if(v1 == 10) console.log(i); // 9 }
- 그러나 let은 함수가 아니라 블럭 스코프 변수이기 때문이 결과가 다르다
let l1 = 10; function letTest() { for(let i = 0; i < 10; i++) console.log(i); // 1, 2, ..., 9 if(l1 == 10) consoloe.log(i); // Reference Error Exception }
- let은 스코프가 블럭단위이기 때문에 for문을 벗어난 범위에서 변수 i를 참조하는 것이 불가능해 에러가 발생한다.
Const
- 기존 JavaScript에는 상수가 없어 var TEST_CONST 와 같이 대문자로 선언해 상수처럼 사용하는 것이 관용적이였다.
- ES6에서는 const를 사용하여 상수형 변수를 선언할 수 있게 했다.
const PI = 3.14; console.log(PI); // 3.14; PI = 3.147592; // 상수형이기 때문에 변수가 바뀌지 않음 console.log(PI); //3.14;
- 변수의 스코프는 let과 같이 블럭이다.
import, export
- import -다른 스크립트의 함수, 객체, 등을 사용하기 위해 들여오는 키워드
- export – 현재 스크립트의 함수, 객체, 등을 내보내는 키워드
- import 표현식
import * as name from "module-name"; import { member as alias } from "module-name"; import { member1 , member2 } from "module-name"; import { member1 , member2 as alias2 , [...] } from "module-name"; import defaultMember, { member [ , [...] ] } from "module-name"; import defaultMember, * as name from "module-name"; import "module-name";
- export 표현식
export { variable1 as name1, variable2 as name2, …, nameN }; export let name1, name2, …, nameN; export let name1 = …, name2 = …, …, nameN; export { name1 as default, … }; export * from …; export { name1, name2, …, nameN } from …; export { import1 as name1, import2 as name2, …, nameN } from …;
기존 JavaScript의 구조적 특성(?)
React 개발 중 혹은 JavaScript 개발 중 이런 코드를 자주 봤을 것이다.
this.function.bind(this)
this에 속한 어떤 method(위에서는 function)를 다시 this에 bind하는 이유가 뭘까?
이를 알기위해 bind()와, this의 역할부터 알고가자.
bind()
-
- bind 함수는 bind하는 함수에서 사용하는 this의 대상을 지정해주는 역할
const objA = { id: 'a', funcA: function() { console.log(this.id) }, } const objB = { id: 'b', } objA.funcA() // a objA.funcA.bind(objB) // b const test = objA.aFunc.bind(objB) test() // b
A와 B Object(objA, objB)가 있다. objA는 id와 funcA를 objB는 id만을 가지고 있다.
- 12번 줄의 실행 결과로는 objA의 funcA를 실행하여 this.name으로 objaA의 ‘a’라는 id값을 출력한다.
- 13번 줄의 실행 결과로는 objA 객체의 funcA함수에서 bind(objB)를 호출한다. 그러면서 funcA 함수와 동일한 기능을 하는 objB를 바인딩한 새로운 함수가 만들어진다. 이 때, bind 메서드에 전해진 인자는 복사된 바인딩 함수의 this로 전달됨.
즉, funcA 함수 내의 this가 objB가 된다. 이렇게 바인딩한 함수만 존재할 뿐 aFunc을 실행하여 결과값이 출력되진 않고 함수를 새롭게 생성하기만 한다. - 14번 줄은 위에 13번 줄에서 설명한 것 과 같은 바인딩된 함수를 test라는 상수에 담아둔다.
- 15번 줄은 test상수에 담겨진 14번 줄에서 생성된 바인딩된 함수를 실행한다 즉, objB를 인자로 갖는 funcA를 실행한다 따라서 objB의 id인 ‘b’를 출력한다.
- bind 함수는 bind하는 함수에서 사용하는 this의 대상을 지정해주는 역할
this
혹시 JavaScript에서의 this를 보통 OOP에서의 this(현재 객체를 지칭)와 같다고 생각할수 있지만 아니다. JavaScript에서 this는 실행시의 context를 말한다.
const test = function() { console.log(this.value) } test.value = 'TEST MESSAGE' test()
위 예제코드의 결과로는 ‘TEST MESSAGE’가 아닌 undefined가 출력된다.
왜냐하면 test()가 출력될 때의 context가 전역객체이기 때문이다. test.value는 test의 속성인데 전역객체에서 value를 찾으려고 하니 undefined가 출력된다.
즉 test.value 에서 test와 test()가 다른 context여서 4번줄에서 갖게된 값이 아닌 5번줄에서 실행된 this.value에 값이 정의되지 않은 값이 출력되어 undefined이 출력된다.
const test = function() { console.log(this.value) } test.value = 'this is this' test.func = function(){ console.log(this.value) } this.func()
위 코드를 실행하면 결과는 예상대로 ‘this is this’가 출력된다.
test 객체의 func() 메서드를 호출하면 this가 test 가 되기 때문에
정상적으로 this.value를 가져와 예상한 결과가 출력됨을 알 수 있다.
Arrow Function
- 기존의 function보다 빠르고 간결한 구문을 보여주는 함수
- 항상 익명함수이다.
- 메소드 함수가 아닌 곳에 가장 적합하다.
- 생성자로 사용할 수 없다.
- 위의 글인 JavaScript의 구조적 특성(?)을 참고하여 this를 bind해서 객체를 지정하고 값을 변화 및 참조하는 경우에 Arrow Function은 외부함수의 this를 상속받기 때문에 항상 일정하여 짧고 유연하게 코드작성이 가능하다.
// 함수안에 that 변수를 선언하기 let duck = { sound: "quack-quack", soundPlay: function () { let that = this // that 사용 setTimeout(function () { console.log(that.sound); }, 1000); } } duck.soundPlay(); // 1초 후에 ... "quack-quack" // bind 사용하기 let duck = { sound: "quack-quack", soundPlay: function () { setTimeout(function () { console.log(this.sound); }.bind(this), 1000); // bind 사용 } } // arrow function 사용하기 duck.soundPlay(); // 1초 후에 ... "quack-quack" let duck = { sound: "quack-quack", soundPlay: function () { setTimeout(() => { console.log(this.sound); }, 1000); } } duck.soundPlay(); // 1초 후에 ... "quack-quack"
위 코드 원본링크는 (클릭)을 통해 확인가능하다.
구문
클릭하면 참고한 사이트로 이동
- 기본구문
(param1, param2, …, paramN) => { statements } (param1, param2, …, paramN) => expression // 다음과 동일함: => { return expression; } // 매개변수가 하나뿐인 경우 괄호는 선택사항: (singleParam) => { statements } singleParam => { statements } // 매개변수가 없는 함수는 괄호가 필요: () => { statements }
- 고급구문
// 객체 리터럴 표현을 반환하기 위해서는 함수 본문(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
위에 정리한 내용을 토대로 React.js를 사용하기 위해 필요한 기본적인 ES6 문법은 정리가 된 것 같다. 후에 또 필요한 내용이 있으면 추가적으로 글을 작성할 것.
진보만이 답이네요. 좋은 프로젝트 응원합니다.