function oneMore(){
console.log('one more');
}
function run(){
console.log('run run');
setTimeout(()=>{
console.log('wow');
},0);
new Promise((resolve)=>{
resolve('hi');
})
.then(console.log);
oneMore();
}
setTimeout(run,5000);
1) 호출스택 → anonymous
2) 호출스택 → anonymous, setTimeout(run,5000)
3) 호출스택 → anonymous , 백그라운드 → 타이머(run,5초)
4) 백그라운드 → 타이머(run,5초)
5) 테스크 큐 → run (이제 호출 스택이 비었으니 이동, 비어있어야 이동가능!)
6) 호출스택 → run, 콘솔 → run run
7) 호출스택 → run, setTimeout(익명,0) , 콘솔 → run run
8) 호출스택 → run, 백그라운드 → 타이머(익명,0), 콘솔 → run run
9) 호출스택 → run, new Promise , resolve(’hi’) , 백그라운드 → 타이머(익명,0), 콘솔 → run run
10) 호출스택 → run , 백그라운드 → 타이머(익명,0) , then console.log(hi)
11) 호출스택 → run, oneMore, console.log , 백그라운드 → 타이머(익명,0), then console.log(hi) , 콘솔 → run run
12) 백그라운드 → 타이머(익명,0), then console.log(hi) , 콘솔 → run run , one more
13) 태스크 큐 → 익명 , console.log(hi)
14) 호출 스택 → console.log(hi) , 테스크 큐 → 익명
15) 최종 콘솔 : run run , one more, hi , wow
const : 블록밖에서 사용X, 블록: if,while,for,function 등의 중괄호({와} 사이), const 는 다른 값 할당불가(상수)
const a=3;
a='5'; //에러
const b={name : 'zerocho'};
b.name ='nerocho'; //이건 가능
const c; //에러
var won=1000;
va result='이 과자는' + won + '원입니다.;
//이 과자는1000원입니다. (띄어쓰기 안댐 -> 직접 해야함)
const result=`이 과자는 ${won}원입니다`; //최신기능
function a() {}
a(); //예전 함수호출
a``; //최신버전 함수호출예전버전
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
최신버전
const newObject={
sayJS(){ //:function 삭제(객체의 메서드에 함수를 연결할 때, 콜론과 function 붙이지 않아도댐)
console.log('JS');
},
sayNode, //:sayNode 삭제(속성명과 변수명 동일한 경우 한번만 써도 가능!)
[es+6]:'fantastic', //바로 넣음(객체의 속성명을 동적으로 변경 가능, 객체 리터럴 안에 동적 속성 선언 가능!)
};
newObject.sayNode(); //Node
newObject.sayJS(); //JS
console.log(newObject.ES6); //fantastic
function 과 ⇒ 의 차이점
결론 : 기본적으로 화살표 함수를 쓰되, this를 사용해야 하는 경우에는 화살표 함수와 함수 선언문(function) 둘 중 하나 고르기!!
var relationship1 = {
name: 'zero',
friends: ['nero', 'hero', 'xero'],
logFriends: function () {
var that = this; // relationship1을 가리키는 this를 that에 저장
this.friends.forEach(function (friend) {
console.log(that.name, friend); //this로 변경할 경우, undefined nero, undefined hero, undefined xero
});
},
};
relationship1.logFriends(); //zero nero, zero hero, zero xero
const relationship2 = {
name: 'zero',
friends: ['nero', 'hero', 'xero'],
logFriends() {
this.friends.forEach(friend => {
console.log(this.name, friend);
});
},
};
relationship2.logFriends(); //zero nero, zero hero, zero xero
객체와 배열로부터 속성이나 요소 쉽게 꺼낼 수 있음
단, this는 함수를 호출할 때 어떻게 호출되었냐에 따라 결정되기 때문에 this가 있으면 구조 분해 할당을 안하는 것이 좋음!!, 구조분해 할당하면 함수의 this가 달라짐
- 달라진 this를 원래대로 바꿔주려면 bind함수를 따로 사용해야함
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;
var array = [‘nodejs’, {}, 10, true];
var node = array[0];
var obj = array[1];
var bool = array[3];
//구조 분해 할당(배열)
const array = [‘nodejs’, {}, 10, true];
const [node, obj, , bool] = array;
다른 언어처럼 클래스 기반 동작X, 프로토타입 기반으로 동작하지만 보기 좋게 클래스로 바꾼것
프로토타입으로만 작성한 것(예전 버전)
var Human = function(type) {
this.type = type || 'human';
};
Human.isHuman = function(human) {
return human instanceof Human;
}
Human.prototype.breathe = function() {
alert('h-a-a-a-m');
};
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); // true
클래스로 바꾼것(최신 버전) → 프로토타입 기반으로 동작!!!
class Human {
constructor(type = 'human') { //생성자 함수
this.type = type;
}
static isHuman(human) { //Human.isHuman같은 클래스 함수 static 전환
return human instanceof Human;
}
breathe() {
alert('h-a-a-a-m');
}
}
class Zero extends Human { //extends: 상속
constructor(type, firstName, lastName) {
super(type); //super : Human
this.firstName = firstName;
this.lastName = lastName;
}
sayName() {
super.breathe();
alert(`${this.firstName} ${this.lastName}`);
}
}
const newZero = new Zero('human', 'Zero', 'Cho');
Human.isHuman(newZero); // true
자바스크립트와 노드는 주로 비동기를 접함 → 이벤트 리스너 사용에서 콜백말고 프로미스기반으로 재구성, 중요!!
실행은 바로 하되 결과값은 나중에 받는 객체, 결과값은 실행이 완료된 후 then이나 catch메서드를 통해 받음!
- 밑의 코드에서 new Promise는 바로 실행되지만, 결과값은 then을 붙였을 때 받음
const condition = true; // true이면 resolve, false이면 reject
const promise = new Promise((resolve, reject) => { //1. 프로미스 생성
if (condition) {
resolve('성공');
} else {
reject('실패');
}
});
// 다른 코드가 들어갈 수 있음
promise
.then((message) => {
console.log(message); // 성공(resolve)한 경우 실행
})
.catch((error) => {
console.error(error); // 실패(reject)한 경우 실행
})
.finally(() => { // 끝나고 무조건 실행
console.log('무조건');
});
function findAndSaveUser(Users) {
Users.findOne({}, (err, user) => { // 첫 번째 콜백
if (err) {
return console.error(err);
}
user.name = 'zero';
user.save((err) => { // 두 번째 콜백
if (err) {
return console.error(err);
}
Users.findOne({ gender: 'm' }, (err, user) => { // 세 번째 콜백
// 생략
});
});
});
}
//위의 콜백 코드를 프로미스로 변경!
function findAndSaveUser(Users) {
Users.findOne({})
.then((user) => {
user.name = 'zero';
return user.save();
})
.then((user) => {
return Users.findOne({ gender: 'm' });
})
.then((user) => {
// 생략
})
.catch(err => {
console.error(err);
});
}
function findAndSaveUser(Users) {
Users.findOne({})
.then((user) => {
user.name = 'zero';
return user.save();
})
.then((user) => {
return Users.findOne({ gender: 'm' });
})
.then((user) => {
// 생략
})
.catch(err => {
console.error(err);
});
}
//async/await로 변경한것!
async function findAndSaveUser(Users) {
let user = await Users.findOne({}); //프로미스 앞에 await 붙임, 함수는 해당 프로미스가 resolve될 때까지 기다린 뒤 다음 로직으로 넘어감
user.name = 'zero';
user = await user.save();
user = await Users.findOne({ gender: 'm' });
// 생략
}
//try, catch로 에러 처리
async function findAndSaveUser(Users) {
try {
let user = await Users.findOne({});
user.name = 'zero';
user = await user.save();
user = await Users.findOne({ gender: 'm' });
// 생략
} catch (error) {
console.error(error);
}
}
//화살표 사용!!
const findAndSaveUser = async (Users) => {
try {
let user = await Users.findOne({});
user.name = 'zero';
user = await user.save();
user = await Users.findOne({ gender: 'm' });
// 생략
} catch (error) {
console.error(error);
}
};
const m = new Map(); //map 생성
m.set('a', 'b'); // set(키, 값)으로 Map에 속성 추가
m.set(3, 'c'); // 문자열이 아닌 값을 키로 사용 가능합니다
const d = {};
m.set(d, 'e'); // 객체도 됩니다
m.get(d); // get(키)로 속성값 조회
console.log(m.get(d)); // e
m.size; // size로 속성 개수 조회
console.log(m.size) // 3
for (const [k, v] of m) { // 반복문에 바로 넣어 사용 가능합니다
console.log(k, v); // 'a', 'b', 3, 'c', {}, 'e'
} // 속성 간의 순서도 보장됩니다
m.forEach((v, k) => { // forEach도 사용 가능합니다
console.log(k, v); // 결과는 위와 동일
});
m.has(d); // has(키)로 속성 존재 여부를 확인합니다
console.log(m.has(d)); // true
m.delete(d); // delete(키)로 속성을 삭제합니다
m.clear(); // clear()로 전부 제거합니다
console.log(m.size); // 0
const s = new Set();
s.add(false); // add(요소)로 Set에 추가합니다
s.add(1);
s.add('1');
s.add(1); // 중복이므로 무시됩니다
s.add(2);
console.log(s.size); // 중복이 제거되어 4
s.has(1); // has(요소)로 요소 존재 여부를 확인합니다
console.log(s.has(1)); // true
for (const a of s) {
console.log(a); // false 1 '1' 2
}
s.forEach((a) => {
console.log(a); // false 1 '1' 2
})
s.delete(2); // delete(요소)로 요소를 제거합니다
s.clear(); // clear()로 전부 제거합니다
널 병합(??) : 주로 || 연산자 대용으로 사용되며, falsy 값(0,’’,false,NaN,null,undefined)중 null과 undefined만 따로 구분
const a = 0;
const b = a || 3; // || 연산자는 falsy 값이면 뒤로 넘어감
console.log(b); // 3
const c = 0;
const d = c ?? 3; // ?? 연산자는 null과 undefined일 때만 뒤로 넘어감
console.log(d); // 0;
const e = null;
const f = e ?? 3;
console.log(f); // 3;
const g = undefined;
const h = g ?? 3;
console.log(h); // 3;
옵셔널 체이닝: null이나 undefine의 속성을 조회하는 경우 에러가 발생하는 것을 막음(?.)
const a = {}
a.b; // a가 객체이므로 문제없음
const c = null;
try {
c.d;
} catch (e) {
console.error(e); // TypeError: Cannot read properties of null (reading 'd')
//위의 에러 주의!!! -> reading 'd'는 d가 null이 아니라 앞에 c 가 null임!!!!
}
c?.d; // 문제없음
try {
c.f();
} catch (e) {
console.error(e); // TypeError: Cannot read properties of null (reading 'f')
}
c?.f(); // 문제없음
try {
c[0];
} catch (e) {
console.error(e); // TypeError: Cannot read properties of null (reading '0')
}
c?.[0]; // 문제없음