진취적 삶
02 알아둬야 할 자바스크립트 본문
2.1 ES2015+
ES2015(ES6)
2.1.1 const ,let
const ,let 블록 스코프의 사용으로 호이스팅 같은 문제 해결
const 로 선언한 변수는 상수
const a = 0;
a = 1; //TypeError: Assignment to constant variable.
let b = 0;
b = 1;
const c;//'const' declarations must be initialized
자바스크립트 에서는 한번 초기화 했던 변수에 다른 값을 할당하는경우는 의외로 적다.
변수 선언시에 기본적으로 const 사용하고 다른 값에 할당해야 하는 상황이 생기면 let 사용
2.1.2 템플릿 문자열
백틱 사용
const num1 = 1;
const num2 = 2;
const num3 = 3;
const result = num1 + num2 + num3;
const string2 = `${num1} 더하기 ${num2} 더하기 ${num3} = ${result}`;
console.log(string2);
2.1.3 객체 리터럴
oldObejct
var sayNode = function () {
console.log("node");
};
var es = "ES";
var oldObject = {
sayJs: function () {
console.log("JS");
},
sayNode: sayNode,
};
oldObject[es + 6] = "fantastic";
oldObject.sayNode(); //node
oldObject.sayJs(); //JS
console.log(oldObject.ES6); //fantastic
newObject
let es = "ES";
const newObject = {
sayJs() {
console.log("js");
},
sayNode() {
console.log("node");
},
[es + 6]: "fantastic",
};
newObject.sayNode();
newObject.sayJs();
console.log(newObject.ES6);
2.1.4 화살표 함수
예전 버전
var relationship1 = {
name: "zero",
friends: ["a", "b", "c"],
logFriends: function () {
var that = this;
this.friends.forEach(function (friend) {
console.log(that.name, friend);
});
},
};
relationship1.logFriends();
/*
zero a
zero b
zero c
*/
지금 버전
const relationship2 = {
name: "suha",
friends: ["a", "b", "c"],
logFriends() {
this.friends.forEach((friend) => {
console.log(this.name, friend);
});
},
};
relationship2.logFriends();
/*
suha a
suha b
suha c*/
상위 스코프의 this를 그대로 물려받는다 .
this 를 사용해야 하는경우 화살표 함수와 함수 선언문 둘중 하나를 고르면 된다.
2.1.5 구조 분해 할당
이전 버전
var candyMachine = {
status: {
name: "node",
count: 5,
},
getCandy: function () {
this.status.count--;
return this.status.count;
},
};
var getCandy = candyMachine.getCandy;
var count = candyMachine.status.count;
최신 버전
const candyMachine = {
status: {
name: "node",
count: 5,
},
getCandy() {
this.status.count--;
return this.status.count;
},
};
const {
getCandy,
status: { count },
} = candyMachine;
- getCandy: candyMachine 객체의 getCandy() 메소드를 할당합니다.
- status: {count}: candyMachine 객체의 status 속성에서 count 속성을 추출하여 count 변수에 할당합니다.
배열에 대한 구조 분해 할당 문법
const array = ["nodejs", {}, 10, true];
const [node, obj, , bool] = array;
console.log(node); //nodejs
console.log(obj); //{}
console.log(bool); //true
2.1.6 클래스
프로토타입 기반 문법을 보기 좋게 클래스로 바꾼것
프로토 타입 버전
var Human = function (type) {
this.type = type || "human";
};
Human.isHuman = function (human) {
return human instanceof Human;
};
Human.prototype.breathe = function () {
alert("haaaam");
};
var Zero = function (type, firstName, lastName) {
Human.apply(this, arguments);
this.firstName = firstName;
this.lastName = lastName;
};
Zero.prototype = Object.create(Human.prototype);
Zero.prototype.constructor = Zero; //상속하는 부분
Zero.prototype.sayName = function () {
alert(this.firstName + this.lastName);
};
var oldZero = new Zero("human", "Zero", "Cho");
Human.isHuman(oldZero);
클래스 기반 코드
클래스 문법으로 바뀌었더라도 자바스크립트는 프로토타입 기반으로 동작한다는것을 명심
class Human {
constructor(type = "human") {
this.type = type;
}
static isHuman(human) {
return human instanceof Human;
}
breathe() {
console.log(`haaam`);
}
}
class Suha extends Human {
constructor(type, firstName, lastName) {
super(type);
this.firstName = firstName;
this.lastName = lastName;
}
sayName() {
super.breathe();
console.log(`${this.lastName} ${this.firstName}`);
}
}
const newSuha = new Suha("human", "suha", "hwang");
newSuha.sayName(); //haaam hwang suha
console.log(Human.isHuman(newSuha)); //true
2.1.7 프로미스
콜백 지옥 현상을 극복하기 위해서 프로미스사용
const condition = true;
const promise = new Promise((resovle, reject) => {
if (condition) {
resovle("성공");
} else {
reject("실패");
}
});
promise
.then((message) => {
console.log(message); //성공한 경우 실행
})
.catch((error) => {
console.error(error); //실패한 경우 실행
})
.finally(() => {
console.log("무조건"); //끝나고 무조건 실행
});
프로미스 내부에서 resolve 가 호출되면 then reject가 호출되면 catch 실행
프로미스는 실행은 바로 하되 결과값은 나중에 받는 객체이다 .
new Promise는 바로 실행되지만 , 결과값은 then을 붙였을때 받게 된다.
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);
});
처음 then에서 resolve 하면 다음 then에서 message2로 받을수 있다.
다시 message2 resolve 하며 다음 then에서 message3 받는다.
단, then 에서 new Promise를 return 해야 다음 then 에서 받을수 있다.
해당 무한 콜백을 프로미스로 바꿔보자.
콜백 함수가 나올때마다 코드의 깊이가 깊어진다. 또한 콜백마다 에러도 따로 처리해야한다.
function findAndSaveUser(Users) {
Users.findOne({}, (err, user) => {
//첫번째 콜백
if (err) {
return console.error(err);
}
user.name = "suha";
user.save((err) => {
//두번째 콜백
if (err) {
return console.error(err);
}
Users.findOne({ gender: "m" }, (err, user) => {
//세번째 콜백
});
});
});
}
밑의 코드로 변경 가능
코드의 깊이가 세 단계 이상 깊어지지 않는다.
에러 처리또한 catch 에서 한번에 가능
function findAndSaveUser(Users) {
Users.findOne({})
.then((user) => {
user.name = "suha";
return user.save();
})
.then((user) => {
return Users.findOne({ gender: "m" });
})
.then((user) => {
//생략
})
.catch((err) => {
console.err(err);
});
}
프로미스를 여러개 사용할수 있는 방법이 있다.
Promise.all 사용하면됨
const promise1 = Promise.resolve("성공1");
const promise2 = Promise.resolve("성공2");
Promise.all([promise1, promise2])
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
});
Promise.resolve 는 즉시 resolve 하는 프로미스를 만드는 방법이다 .
premise.reject 또한 있음
프로미스가 여러개 있을때 Promise.all 에 넣으면 모두 resolve 될 때까지 기다렸다가 then 으로 넘어감
result 매개변수에는 각각의 프로미스 결과값이 들어가 있음
Promise 중 하나라도 reject 되면 catch 로 넘어간다.
다만 ,여러 프로미스중 어떤 프로미스가 reject 되었는지는 알수 없다.
정확히 어떤 프로미스가 reject 된지 알고싶을 경우 Promise.all 대신 Promise.allSettled를 사용해야한다.
const promise1 = Promise.resolve("성공1");
const promise2 = Promise.resolve("성공2");
const promise3 = Promise.reject("실패3 ");
Promise.allSettled([promise1, promise2, promise3])
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
});
/*
[
{ status: 'fulfilled', value: '성공1' },
{ status: 'fulfilled', value: '성공2' },
{ status: 'rejected', reason: '실패3 ' }
]*/
Promise.all 대신 Promise.allSetteled 사용을 권장
reject 된 Promise에 catch 를 달지 않으면 오류가 발생한다.
Promise.reject("에러").catch(() => {});
2.1.8 async/await
노드처럼 비동기 위주로 프로그래밍 해야할 때 도움이 많이된다.
프로미스가 콜백 지옥을 해결했지만 then catch가 계속 반복되기 때문에 코드가 장황하다
function findAndSaveUser(Users) {
Users.findOne({})
.then((user) => {
user.name = "suha";
return user.save();
})
.then((user) => {
return Users.findOne({ gender: "m" });
})
.then((user) => {
//생략
})
.catch((err) => {
console.err(err);
});
}
assync/await 문법을 통해 간격하게 한다.
async function findAndSaveUser(Users) {
let user = await Users.findOne({});
user.name = "suha";
user = await user.save();
user = await Users.findOne({ gender: "m" });
}
프로미스 앞에 await를 붙여서 함수는 해당 프로미스가 resolve 될때까지 기다린뒤 다음 로직으로 넘어간다.
await Users.findOne({}) 이 resolve 될때까지 기다린후 user 변수 초기화
const findAndSaveUser = async (Users) => {
try {
let user = await Users.findOne({});
user.name = "suha";
user = await user.save();
usere = await Users.findOne({ gender: "m" });
} catch (error) {
console.error(error);
}
};
for 문과 async/await을 같이 써서 프로미스를 순차적으로 실행할수 있다.
중첩되는 콜백 함수가 있을 경우 async/await 문법으로 바꾸는 연습을 하자
const promise1 = Promise.resolve("성공1");
const promise2 = Promise.resolve("성공2");
(async () => {
for await (promise of [promise1, promise2]) {
console.log(promise);
}
})();
2.1.9 Map/Set
Map 은 객체와 유사하고 Set은 배열과 유사하다고 생각하면된다.
Map 은 속성들 간의 순서를 보장하고 반복문을 사용할수 있다. size 메서드를 통해 속성의 수를 쉽게 알수 있다.
const m = new Map();
m.set("a", "b");
console.log(m.get("a")); //b
const d = {};
m.set(d, "e");
console.log(m.get(d)); //e 객체도 됨
console.log(m.size); //2
for (const [k, v] of m) {
console.log(k, v);
/*
a b
{} e
*/
}
m.forEach((v, k) => {
console.log(k, v);
});
/*
a b
{} e
*/
console.log(m.has(d)); //true
m.clear();
console.log(m.size); //0
set 은 중복을 허용하지 않는다는것이 가장 큰 특징
배열 자료구조를 사용하고 싶고 중복은 허용하고 싶지 않을 때 Set을 대신 사용하면된다.
const s = new Set();
s.add(false);
s.add(1);
s.add("1");
s.add(1); //중복 무시
s.add(2);
console.log(s.size); //4
for (const a of s) {
console.log(a); //false 1 '1' 2
}
s.forEach((e) => {
console.log(e); //false 1 '1' 2
});
s.delete(2);
s.clear();
console.log(s.size); //0
const arr = [1, 1, 1, 2, 3, 4, 5];
const s = new Set(arr);
console.log(s); //Set(5) { 1, 2, 3, 4, 5 }
result = Array.from(s); // 배열로 바꾸기
console.log(result); //[ 1, 2, 3, 4, 5 ]
2.1.10 null 병합/옵셔널 체인닝
널 병합 : ??
옵셔널 체이닝 : ?.
널 병합 연산자는 주로 || 연산자 대용으로 사용한다.
옵ㅅ
const a = 0;
const b = a || 3; //falsy 값이면 뒤로 넘어감
console.log(b); //3
const c = 0;
const d = c ?? 3; // ?? 연산자는 null 과 undefined 일때만 뒤로 넘어감
console.log(c); // 0
const e = null;
const f = e ?? 3;
console.log(f); //3
const g = undefined;
const h = g ?? 3;
console.log(h); //3
옵셔널 체이닝 연산자는 null 이나 undefined 속성을 조회하는 경우 에러가 발생하는것을 막는다.
const a = [];
a.b;
const c = null;
try {
c.d;
} catch (e) {
console.error(e); //Cannot read properties of null (reading 'd')
}
c?.d; //문제없음
try {
c.f();
} catch (error) {
console.error(error);
}
c?.f(); //문제없음
try {
c[0];
} catch (error) {
console.error(error);
}
c?.[0]; //문제없음
c?.d 와 c?.f() c?.[0]의 값은 undefined 된다
옵셔널 체이닝 연산자는 자바스크립트 프로그래밍을 할 때 발생하는 TypeError:cannot read properties of undefined 또는 null 에러의 발생 빈도를 획기적으로 낮출수 있다.
2.2 프런트엔드 자바스크립트
2.2.1 AJAX
AJAX : 비동기적 웹 서비스를 개발할때 사용하는 비법 , 페이지 이동없이 서버에 요청을 보내고 응답을 받는 기술 웹사이트 중에서 페이지 전환 없이 새로운 데이터를 불러오는 사이트는 대부분 AJAX 기술을 사용하고 있다고 보면된다.
GET 요청
(async () => {
try {
const result = await axios.get("<<a href=https://www.zerocho.com/api/get>https://www.zerocho.com/api/get</a>>");
console.log(result);
console.log(result.data);
} catch (error) {
console.error(error);
}
})();
POST 방식의 요청 보내기
(async () => {
try {
const result = await axios.post(
"<<a href=https://www.zerocho.com/api/post/json>https://www.zerocho.com/api/post/json</a>>",
{
name: "suha",
birth: 1998,
}
);
console.log(result);
console.log(result.data);
} catch (error) {
console.error(error);
}
})();
두번째 인수로 데이터를 넣어 보내는 것이 다르다.
GET 요처이면 axiois.get POST 요청이면 axios.post 사용
2.2.2 FormData
HTML form 태그의 데이터를 동적으로 제어할수 있는 기능
FormData 생성자로 formData 객체를 만든다 .
async () => {
try {
const formData = new FormData();
formData.append("name", "suha");
formData.append("birth", 1998);
const result = await axois.post(
"<<a href=https://www.zerocho.com/api/post/formdata>https://www.zerocho.com/api/post/formdata</a>>",
formData
);
console.log(result);
console.log(result.data);
} catch (error) {
console.error(error);
}
};
2.2.3 encodeURIComponent ,decodeURIComponent
서버가 한글 주소를 이해하지 못할경우
window 객체의 메서드인 encodeURIComponent 메서드를 사용한다.
(async () => {
try {
const result = await axios.get(
`https://www.zerocho.com/api/search/${encodeURIComponent("노드")}`
);
console.log(result);
console.log(result.data);
} catch (error) {
console.error(error);
}
})();
받는 쪽에서는 deCodeURIComponent 사용하면된다.
2.2.4 데이터 속성과 dataset
서버에서 보내준 데이터를 프런트앤드 어디에 넣어햐 할지 고민하게 된다.
프런트엔드에 민감한 데이터를 내려보내는것은 실수이다.
비밀번호 같은것은 절대 내보내면 안됨
HTML5 에도 HTML 관련된 데이터를 저장하는 공식적인 방법이 있다.
데이터 속성이다 .
데이터 속성의 장점은 자바스크립트로 쉡게 접근할수 있다.
<body>
<ul>
<li data-id="1" data-user-job="programmer">a</li>
<li data-id="2" data-user-job="designer">b</li>
<li data-id="3" data-user-job="programmer">c</li>
<li data-id="4" data-user-job="cero">d</li>
</ul>
<script>
console.log(document.querySelector("li").dataset);
/*
id: "1"
userJob:"programmer"
*/
</script>
</body>
'개발 도서 > Node.js 교과서' 카테고리의 다른 글
06 익스프레스 웹 서버 만들기 (0) | 2023.07.14 |
---|---|
05 패키지 매니저 (0) | 2023.07.14 |
04 http 모듈로 서버 만들기 (0) | 2023.07.14 |
03 노드 기능 알아보기 (0) | 2023.07.14 |
01 노드 시작하기 (0) | 2023.07.14 |