2015년 자바스크립트 문법에 큰 변화가 생겼다.
ES2015(ES6라고도 함)가 등장한 것.
ES2015+ 문법과 프런트엔드 환경에서 브라우저가 제공하는 몇 가지 객체들을 간단히 설명한다.
const와 let은 var과 달리 블록레벨 스코프를 지원한다.
const와 let은 변수의 초기화(undefined)와 변수의 할당이 별개로 이루어진다.
따라서, 임의의 블록 내에서 변수의 선언 전에 값을 참조하면 ReferenceError가 발생한다.
let과 const외에도 class, class의 constructor()내부 super(), 함수 매개변수 또한 TDZ의 영향을 받는다.
백틱(`)을 통한 문자열 표현.
문자열 안에 $()형식을 통해 변수를 넣을 수 있음.
객체의 메서드에 함수를 연결할 때 콜론(:)과 function을 사용하지 않아도 됨.
const relationship = {
name: "zero",
friends: ["A", "B", "C"],
logFriends() {
this.friends.forEach((friend) => {
console.log(this.name, friend);
});
},
};
forEach()문 내부에서 화살표 함수를 사용함으로써 상위 스코프의 this를 그대로 물려받는다.
기본적으로 화살표 함수를 쓰되, this를 사용해야 하는 경우네는 화살표함수와 function중 선택하면 된다.
const candyMachine = {
status: {
name: "node",
count: 5,
},
getCandy() {
this.status.count--;
return this.status.count;
},
};
// 구조 분해 할당
const {
getCandy,
status: { count },
} = candyMachine;
구조 분해 할당 문법도 코드의 줄 수를 상당히 줄여주기 때문에 유용하다.
특히 노드는 모듈 시스템을 사용하기 때문에 이러한 방식을 자주 사용한다.
클래스(class)문법이 추가되었다.
하지만 내부적으로는 여전히 프로토타입을 기반으로 동작한다. 문법적 설탕일 뿐.
프로토타입 기반 상속과 클래스 기반 상속 두종류의 코드를 모두 적는다.
const Human = function (type) {
this.type = type || "human";
};
Human.isHuman = function (human) {
return human instanceof Human;
};
Human.prototype.breath = function () {
alert("h-a-a-a-m");
};
const Me = function (type, firstName, lastName) {
Human.apply(this, arguments);
this.firstName = firstName;
this.lastName = lastName;
};
Me.prototype = Object.create(Human.prototype);
Me.prototype.constructor = Me;
Me.prototype.sayName = function () {
alert(this.firstName + "" + this.lastName);
};
const oldMe = new Me("human", "Lee", "Sangmin");
class Human {
constructor(type = "human") {
this.type = type;
}
static isHuman(human) {
return human instanceof Human;
}
breathe() {
alert("h-a-a-a-m");
}
}
class Me extends Human {
constructor(type, firstName, lastName) {
super(type);
this.firstName = firstName;
this.lastName = lastName;
}
sayName() {
super.breathe();
alert(`${this.firstName} ${this.lastName}`);
}
}
const newMe = new Me("human", "Lee", "Sangmin");
Human.isHuman(newMe);
자바스크립트를 사용하면 비동기를 자주 접한다.
특히 이벤트 리스너를 사용할 때 콜백 함수를 자주 사용한다.
ES6부터는 사용된 프로미스를 통해 API들이 콜백 지옥을 극복했다는 평을 받는다.
const condition = true;
// 우선 프로미스 객체 생성.
const promise = new Promise((resolve, reject) => {
if (condition) {
reolve("성공");
} else {
reject("실패");
}
});
// ...code
promise
.then((message) => {
console.log(message); // 성공(resolve)
})
.catch((error) => {
console.error(error); // 실패(reject)
})
.finally(() => {
console.log("무조건 실행"); // 성공 여부 상관없이 무조건 실행
});
또한 다음과 같이 then이나 catch에서 다시 다른 then이나 catch를 연결할 수 있다.
promise
.then((message) => {
return new Promise((resolve, reject) => {
resolve(message);
});
})
.then((message2) => {
console.log(message2);
return new Promise((resolve, reject) => {
resolve(message2);
});
})
.then((message3) => {
console.log(message3);
})
.catch((error) => {
console.error(error); // 실패(reject)
})
.finally(() => {
console.log("무조건 실행"); // 성공 여부 상관없이 무조건 실행
});
단, 위처럼 then에서 new Promise를 return해야 다음 then에서 받을 수 있다.
프로미스 여러개를 한 번에 실행할 수 있는 방법은 다음과 같다.
// 즉시 resolve, reject하는 프로미스를 만드는 방법
const promise1 = Promise.resolve("성공");
const promise2 = Promise.resolve("실패");
// 모두 resolve 될 때까지 기다렸다가 then으로 넘어간다.
Promise.all([promise1, promise2])
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
});
// 어떤 프로미스에서 reject 되었는지 알기 위해서 사용하는 .allSettled
Promise.allSettled([promise1, promise2])
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
});
노드 7.6 버전부터 지원되는 기능으로, ES2017에서 추가되었다.
노드처럼 비동기 위주의 프로그래밍을 해야할 때 정말 많이 사용.
프로미스가 콜백 지옥을 어느정도 해결 했음에도, 여전히 코드의 길이가 길다.
then과 catch가 반복되기 때문.
async/await을 통해 보다 더 간결한 코드를 유지할 수 있다.
// 기존 Promise
const findUserPromise = (Users) => {
Users.findOne({})
.then((user) => {
user.name = "Lee";
return user.save();
})
.then((user) => {
// 생략
})
.catch((error) => {
consle.error(error);
});
};
// async/await
const findUser = async (Users) => {
try {
let user = await Users.findOne({});
user.name = "Lee";
user = await user.save();
} catch (error) {
console.error(error);
}
};
함수 선언부를 일반 함수 대신 async function으로 교체한 후, 프로미스 앞에 await을 붙힌다.
해당 프로미스가 resolve될 때 까지 기다린 뒤, 다음 로직으로 넘어간다.
별도의 error handle을 제공하지 않아 try catch문 사용한다.
다음처럼 for문과 async/await을 같이 사용하여 프로미스를 순차적으로 실행할 수 있다.
(노드 10 버전부터 지원하는 ES2018 문법)
const promise1 = Promise.resolve("성공1");
const promise2 = Promise.resolve("성공2");
// IIFE
(async () => {
for await (promise of [promise1, promise2]) {
console.log(promise);
}
})();
(생략)
(생략)
프로미스이므로 async/await을 방식을 사용할 수 있다.
// IIFE
import axios from "axios";
// ...
(async () => {
try {
const result = await axios.get("https://www.~~", {
name: "Lee",
age: 27,
});
console.log(result);
console.log(result.data);
} catch (error) {
console.error(error);
}
})();
HTML form 태그의 데이터를 동적으로 제어할 수 있는 기능.
const formData = new FormData();
formData.append("name", "Lee");
formData.append("item", "book");
formData.append("item", "lecture");
formData.append("age", 27);
formData.has("item"); // true
formData.get("item"); // book
formData.getAll("item"); // ['book', 'lecture']
formData.delete("age");
formData.get("age"); // null
formData.append("age", 27);
formData.set("age", 7);
formData.get("age"); // 7
AJAX 요청을 보낼 때, 'http://localhost:4000/search/노드'처러 주소에 한글이 들어가는 경우가 있다.
서버 종류에 따라 다르지만 서버가 한글 주소를 이해하지 못하는 경우가 있다.
한글 주소 부분만 encodeURIComponent 메서드로 감싸 서버가 이해할 수 있도록 만든다.
// IIFE
(async () => {
try {
const result = await axios.get(
`https://www.~.com/api/search/${encodeURIComponent(노드)}`
);
console.log(result);
console.log(result.data); // {}
} catch (error) {
console.error(error);
}
})();
받는 쪽에서는 decodeURIComponent를 사용하면 된다.
(생략)