babel은 공식문서에 따르면 자바스크립트 컴파일러다.
인터프리터 언어에 컴파일러가 왜 필요한가?
babel은 소스 대 소스 컴파일러로, 상위 버전 script에서 작성된 소스를 하위 버전에서도 호환이 가능하도록 컴파일 해 준다.
*quick start vue.js의 저자는 ‘트랜스파일’과 ‘트랜스파일러’ 라는 용어를 사용했다.
참고 : babel 이란 무엇인가? (https://bravenamme.github.io/2020/02/12/what-is-babel/)
1. npm init (package.json 파일 생성)
2. npm install -g babel-cli yarn
3. yarn add -D babel-cli babel-preset-env babel-preset-stage-2 또는
npm install --save-dev babel-cli babel-preset-env babel-preset-stage-2
4. .babelrc 파일 생성 (babel 사용 위해 반드시 필요, 내가 직접 해야함)
{
“presets” : [“env”, “stage-2”]
}
5. js파일 생성 및 작성 후 터미널에서 babel src -d build 하면
build 폴더 밑에 트랜스파일된 스크립트 파일을 확인할 수 있음
ES2015이전에는 변수 선언 위해 var 키워드 사용했다. var키워드는 호이스팅 때문에 복잡하며 중복 선언해도 문제가 발생하지 않았다. 또한 블록 단위 스코프를 지원하지 않고 함수 단위 스코프만 지원했다.
*호이스팅 : 실행 컨텍스트가 만들어진 후에 변수를 미리 생성
이러한 var의 문제점을 개선하여 나온 키워드가 let이다.
let은 블록 단위 스코프를 지원하며, 변수의 중복 선언을 방지할 수도 있다.
[ babel 트랜스파일 전 코드 ]
let msg = "GLOBAL";
function outer(a) {
let msg = "OUTER";
console.log(msg);
if (true) {
let msg = "BLOCK";
console.log(msg);
}
}
[ babel 트랜스파일 후 코드 ]
"use strict";
var msg = "GLOBAL";
function outer(a) {
var msg = "OUTER";
console.log(msg);
if (true) {
var _msg = "BLOCK";
console.log(_msg);
}
}
babel의 트랜스파일 결과를 보면, let의 블록 단위 스코프를 보장하기 위해 임의로 _를 붙여 새로운 변수명을 만들어 낸 것을 확인할 수 있다.
const는 상수 기능을 제공하는 용도다. 한 번 값이 주어지면 다시 변경할 수 없다.
const또한 블록 스코프를 지원한다.
기존 var는 변수의 중복 선언을 허용하지만, const와 let은 중복 선언을 허용하지 않는다.
ES2015에서는 함수 파라미터의 기본값을 지정할 수 있다.
function addContact(name, mobile,
home="없음",
address="없음",
email="없음") {
var str = `name=${name}, mobile=${mobile}, home=${home},
address=${address}, email=${email}`;
console.log(str);
}
addContact("홍길동", "010-222-3331")
addContact("이몽룡", "010-222-3331", "02-3422-9900", "서울시");
ES2015에서는 여러 개의 파라미터 값을 배열로 받을 수 있다.
function foodReport(name, age, ...favoriteFoods) {
console.log(name + ", " + age);
console.log(favoriteFoods);
}
foodReport("이몽룡", 20, "짜장면", "냉면", "불고기");
foodReport("홍길동", 16, "초밥");
babel로 트랜스파일하면 전달하는 쪽의 인자가
[‘짜장면’, ‘냉면’, ‘불고기’] 와 같이 변환된 것을 확인할 수 있다.
구조분해 할당이란 배열,객체의 값들을 추출하여 여러 변수에 할당할 수 있는 기능이다.
let arr = [10,20,30,40];
let [a1,a2,a3] = arr;
console.log(a1, a2, a3); // 10 20 30
let p1 = {name:"홍길동", age:20, gender:"M"};
let { name:n, age:a, gender } = p1;
console.log(n,a,gender); // 홍길동 20 M
구조분해 할당은 함수의 파라미터에서도 사용 가능하다.
function addContact({name, phone, email="이메일 없음", age=0}) {
console.log("이름 : " + name);
console.log("전번 : " + phone);
console.log("이메일 : " + email);
console.log("나이 : " + age);
}
addContact({
name : "이몽룡",
phone : "010-3434-8989"
})
간결한 사용과 함수 정의한 영역의 this를 전달받기 위해 고안.
전통적인 자바스크립트의 this는 문맥에 따라 좌우되지만,
화살표 함수를 사용한 경우 this는 화살표 함수를 둘러싸고 있는 영역의 this를 그대로 따른다.
var test1 = function(a,b) {
return a+b;
}
let test2 = (a,b) => {
return a+b;
}
let test3 = (a,b) => a+b;
위 3개는 트랜스컴파일시 모두 동일한 코드로 작성된다.
ES2015에서는 객체의 속성을 작성할 때 변수명과 동일하다면 생략할 수 있다.
//기존 var obj = { name: name, age: age, email: email };
var obj = { name, age, email };
ES2015에서는 객체 내부 함수를 속성처럼 작성할 수 있다.
아래 예시에서 order는 기존 방식, discount는 ES2015 방식이다.
let p1 = {
name : "아이패드",
price : 200000,
quantity : 2,
order : function() {
if (!this.amount) {
this.amount = this.quantity * this.price;
}
console.log("주문금액 : " + this.amount);
},
discount(rate) {
if (rate > 0 && rate < 0.8) {
this.amount = (1-rate) * this.price * this.quantity;
}
console.log((100*rate) + "% 할인된 금액으로 구매합니다.");
}
}
역따옴표 (``)로 묶여진 문자열에서 템플릿 대입문(${})을 이용해 동적으로 문자열을 끼워넣어 구성할 수 있다. 템플릿 대입문에는 수식 구문, 변수, 함수 호출 구문 등 대부분의 표현식을 사용할 수 있다. 또한 템플릿 문자열은 개행 문자를 포함하여 여러 줄로 작성이 가능하다.
var d1 = new Date();
var name = "홍길동";
var r1 = `${name} 님에게 ${d1.toDateString() }에 연락했다.`;
console.log(r1);
var product = "갤럭시S7";
var price = 199000;
var str = `${product}의 가격은
${price}원 입니다.`;
트랜스파일 된 코드를 살펴보면 개행문자가 포함된 문자열은
각 문자열을 이어붙이는 코드로 변경된 것을 확인할 수 있다.
ES2015는 Set, Map, WeakSet, WeakMap과 같은 집합, 맵을 제공한다.
중복을 허용하지 않고 합집합(Union), 교집합(Intersect)과 같은 다양한 집합 연산자를 제공함.
var s1 = new Set();
s1.add("사과"); s1.add("배");
s1.add("사과"); s1.add("포도");
//실행 결과 : Set { '사과', '배', '포도' }
console.log(s1);
var john = new Set(["사과", "포도", "배"]);
var susan = new Set(["파인애플", "키위", "배"]);
//합집합 : Set { '사과', '포도', '배', '파인애플', '키위' }
var union = new Set([...john.values(), ...susan.values()]);
console.log(union);
//교집합 : Set { '배' }
var intersection = new Set([...john.values()].filter(e => susan.has(e)));
console.log(intersection);
//차집합 : Set { '사과', '포도' }
var diff = new Set([...john.values()].filter(e => !susan.has(e)));
console.log(diff);
키-값 쌍으로 이루어진 컬렉션이며 set(), get(), has(), claer(), delete() 등의 메서드를 제공
let teams = new Map();
teams.set('LG', '트윈스'); teams.set('삼성', '라이온스');
teams.set('NC', '다이노스'); teams.set('기아', '타이거스');
teams.set('한화', '이글즈'); teams.set('롯데', '자이언츠');
console.log(teams.has("SK")); //false
console.log(teams.get("LG")); //트윈스
기존 자바스크립트는 클래스가 제공되지 않아 함수를 이용해 유사 클래스를 만들어 사용했다. ES2015는 공식적으로 클래스를 지원한다.
class Person {
constructor(name, tel, address) {
this.name = name;
this.tel = tel;
this.address = address;
if (Person.count) { Person.count++; } else { Person.count = 1; }
}
static getPersonCount() {
return Person.count;
}
toString() {
return `name=${this.name}, tel=${this.tel}, address=${this.address}`;
}
}
var p1 = new Person('이몽룡', '010-222-3332', '경기도');
var p2 = new Person('홍길동', '010-222-3333', '서울');
console.log(p1.toString());
console.log(Person.getPersonCount());
다른 언어의 클래스와 유사하게 정적 메서드, 인스턴스 메서드, 생성자를 지원하며 상속도 가능하다.
class Person {
constructor(name, tel, address) {
this.name = name;
this.tel = tel;
this.address = address;
if (Person.count) { Person.count++; } else { Person.count = 1; }
}
static getPersonCount() {
return Person.count;
}
toString() {
return `name=${this.name}, tel=${this.tel}, address=${this.address}`;
}
}
var p1 = new Person('이몽룡', '010-222-3332', '경기도');
var p2 = new Person('홍길동', '010-222-3333', '서울');
console.log(p1.toString());
console.log(Person.getPersonCount());
class Employee extends Person {
constructor(name, tel, address, empno, dept) {
super(name,tel,address);
this.empno = empno;
this.dept = dept;
}
toString() {
return super.toString() + `, empno=${this.empno}, dept=${this.dept}`;
}
getEmpInfo() {
return `${this.empno} : ${this.name}은 ${this.dept} 부서입니다.`;
}
}
let e1 = new Employee("이몽룡", "010-222-2121", "서울시", "A12311", "회계팀");
console.log(e1.getEmpInfo());
console.log(e1.toString());
console.log(Person.getPersonCount());
모듈이란 독립성을 가진 재사용 가능한 코드 블록을 의미한다.
ES2015에서는 모듈을 JS코드를 포함하고 있는 파일이라고 간주해도 무방하다.
코드 블록 안에서 import, export 구문을 이용해서 모듈을 가져오거나 내보낼 수 있다.
모듈 내부에서 선언된 모든 변수, 함수, 객체, 클래스는 local로 간주되기 때문에 외부로 공개하고자 하는 것은 export해 주어야 한다. export된 모듈은 다른 모듈에서 import 구문으로 참조하여 사용할 수 있다.
export할 수 있는 대상은 변수, 함수, 객체, 클래스 등이며 다음과 같이 사용한다.
export let a = 1000;
export function f(a) { … }
export { a, b as othername, … }
일단 함수나 변수, 클래스를 작성한 다음 한 번에 export 할 수도 있다.
export { var1, functionAdd };
모듈 단위에서 export 하는 값이 단일 값, 단일 객체, 단일 함수, 단일 클래스라면 deafult 키워드를 이용해 export 한 후 추후에 단일 값으로 import 할 수 있다.
export default functionAdd;
import 할 때는 상대경로를 지정하여 사용하고, .js 확장자는 생략할 수 있다.
import { var1, functionAdd } from ‘./utils/utility1’;
(구조분해 할당이 이용되는 것)
import 할 때 이름을 변경하고싶다면 as 예약어를 사용할 수 있다.
import { functionAdd as add, var1 as v } from ‘./utils/utility1’;
console.log(v);
console.log(add(4,5));
export default functionAdd;
와 같이 단일 함수를 export한 상태라면,
import functionAdd from ‘./utils/utility1’;
와 같이 단일 값으로 import 할 수도 있다.
비동기 처리를 깔끔하게 수행할 수 있도록 고안된 객체.
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
var num = Math.round(Math.random()*20);
var isValid = num % 2;
if (isValid) { resolve(num); }
else { reject(num); }
}, 2000);
});
p.then(function(num) { // 여기에 resolve가 바인딩
console.log("홀수 : " + num);
}).catch(function(num) { // 여기에 reject가 바인딩
console.log("짝수 : " + num);
});
console.log("20까지의 난수중 홀수/짝수?");
console.log("결과는 2초후에 나옵니다.!!");
가변 파라미터와 다른 개념이며 사용법도 다르다.
기존 객체의 속성이나 배열의 요소들을 포함하여 새로운 객체, 배열을 생성하고자 할 때 사용한다.
let obj1 = { name:"박문수", age:29 };
let obj2 = { ...obj1 };
let obj3 = { ...obj1, email:"mspark@gmail.com" };
console.log(obj2); // {name: "박문수", age: 29}
console.log(obj3); // {name: "박문수", age: 29, email: "mspark@gmail.com"}
console.log(obj1 == obj2); //false
let arr1 = [ 100, 200, 300 ];
let arr2 = [ "hello", ...arr1, "world"];
console.log(arr2); // ["hello", 100, 200, 300, "world"]