위 사이트에 접속해 Current 버전을 다운로드 받는다.
설치가 완료되면 파워셸창이 실행되며 설치를 진행한다.
완료 후 명령 프롬프트를 실행시켜
# Node.js 버전 확인
node -v
# npm 버전 확인:
npm -v
LTS 버전 / Current 버전
LTS : 기업을 위해 3년간 지원하는 버전으로, 짝수 버전만 LTS 버전이 가능하다.
Current : 최신 기능을 담고 있는 버전으로, 신기능이 필요하거나 학습용으로 사용할 때 적합하다.
ES2015 이상의 자바스크립트를 통틀어 ES2015+ 문법
var : 오래된 방식으로, 과거 코드 호환성을 위한 경우에만 사용한다.
const : 최신 방식
let : 최신 방식
chrome 에서
about:blank로 가서 F12 개발자 모드를 켜서 콘솔에 들어가 예제를 실행해본다.코드를 실행하지 않고 줄 바꿈을 하려면
shift + Enter
// var은 함수 스코프를 가지므로 if문의 블록과 관계없이 접근할 수 있다.
if(true){
var x = 3;
}
console.log(x); //3이 출력
//const는 블록 스코프를 가지므로 블록 밖에서는 변수에 접근할 수 없다.
if(true){
const y = 3;
}
console.log(y); //Uncaught ReferenceError: y is not defined
| 특징 | const | let |
|---|---|---|
| 값 재할당 여부 | 선언 후 값 재할당 불가 = 상수 | 값 재할당 가능 |
| 초기화 필요 여부 | 선언과 동시에 초기화 필수 | 선언 시 초기화 선택 가능 |
| 스코프 | 블록 스코프(Block Scope) | 블록 스코프(Block Scope) |
const a = 0;
a = 1; //Uncaught TypeError: Assignment to constant variable
//값을 바꾸려고 해서 에러 발
let b = 0;
b = 1; //1
const c; //Uncaught SyntaxError: Missing initializer in const declaration
//초기화할 때 값을 할당하지 않아 에러 발생
큰 따옴표 ""나작은 따옴표 ''를 이용해 문자열 안에 변수를 넣었는데, 추가로백틱을 이용해 더욱 편리하게 사용 가능
var num1 = 1;
var num2 = 2;
var num3 = 3;
var string1 = num1 + " 더하기 " + num2 + ` 는 \` ` + result + `\` `;
console.log(string1); //1 더하기 2는 '3'
const num3 = 1;
const num4 = 2;
const result2 = 3;
const string2 = `${num3} 더하기 ${num4}는 `'${result2}'`;
console.log(string2); //1 더하기 2는 '3'
${변수} 형식으로 변수를 더하기 기호 없이 문자열에 넣을 수 있다. 기존 따옴표 대신 백틱을 사용하므로 큰 따옴표나 작은 따옴표도 함께 사용할 수 있다.속성명(Property Name) 과 변수명(Variable Name) 이 동일하다면, 변수명만 적어도 속성명과 변수명이 같은 객체를 생성할 수 있다. == 단축 속성명(Shorthand Property Names)
const name = "John";
const age = 30;
/* 전 > 속성명과 변수명을 따로 써야
const person = {
name: name,
age: age
*/
// 후 > 단축 속성명 사용
const person = {
name,
age
};
console.log(person); // { name: "John", age: 30 }
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() { //위 에서 : 를 사용하여 객체 내부에 함수를 정의하는 것 보다 메서드 단축 표현을 이용하는게 훨씬 간단
console.log('JS');
},
sayNode, //단축 속성명을 사용하여 위에서 정의된 함수를 직접 참조
//es는 값이'ES'고, es + 6은 문자열 결합 결과 es의 값인 "ES" + "6"으로 "ES6" 속성이 되는 것이다.
//대괄호를 사용하여 "ES6" 이라는 속성 이름을 생성하게된다.(동적으로)
[es + 6]: 'Fantastic',
};
newObject.sayNode(); //Node
newObject.sayJS(); //JS
console.log(newObject.ES6); //Fantastic
sayNode와 같이 단축 속성명을 사용하면, 키와 값이 동일한 변수일 때 단순히 변수명만 사용해도 된다. > 위 클린 코드에서는 외부 변수를 참조하기 때문에 자동으로키:값쌍을 생성한다.
=>기호를 이용해 함수를 선언한다.
//일반적 함수 표현식
const add = function(a, b) {
return a + b;
};
//화살표 함수로 변환
const add = (a, b) => {
return a + b;
};
//단일 표현식일 경우 중괄호와 return 생략 가능
const add = (a, b) => a + b;
특징 비교
| 상황 | 일반 함수 | 화살표 함수 |
|---|---|---|
this 동작 | 호출 방식에 따라 변경 | 상위 스코프의 this 고정 |
내부 함수에서 this 해결 | that = this 방식 필요 | 별도 처리 없이 상위 스코프의 this 사용 |
| 객체 메서드 정의 | 적합(this 가 객체를 정확히 참조) | 부적합(this가 상위 스코프를 참조하므로 undefined 발생 가능) |
| 비동기 작업에서 사용 | 콜백 내에서 this가 불안정할 수 있음 | this가 유지되므로 간결하고 직관적으로 사용 가능 |
const obj = {
name: "Hyunji",
arrowFunc: () => {
console.log(this.name); // 상위 스코프의 `this`를 참조 (window/undefined)
},
regularFunc: function () {
console.log(this.name); // 현재 객체인 obj를 참조
}
};
obj.arrowFunc(); // undefined (window 또는 글로벌 스코프를 참조)
obj.regularFunc(); // Hyunji (obj를 참조)
this 문제 해결화살표 함수는 자체적인
this를 가지지 않고 상위 스코프의this를 참조한다.
일반 함수는 내부 함수에서
this를 참조하지 못하기 때문에that = this방식을 사용하거나, 화살표 함수로 해결한다.
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); // `that`을 참조
});
},
};
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); //logFriends의 상위 스코프인 relationship2의 this를 의미
});
},
};
relationship2.logFriends();
객체 메서드 정의에서는 일반 함수가 적합 > 화살표 함수의
this는 상위 스코프를 참조하므로 예상치 못한 결과를 초래할 수 있다.
const obj = {
name: "Bob",
greet: function() {
console.log(this.name); // 일반 함수: this는 obj를 가리킴
},
greetArrow: () => {
console.log(this.name); // 화살표 함수: this는 상위 스코프(window 또는 undefined)를 참조
},
};
obj.greet(); // Bob
obj.greetArrow(); // undefined
비동기 함수나 콜백 함수에서는 화살표 함수가 this를 고정하기 때문에 유리하다.
class Timer {
constructor() {
this.seconds = 0;
}
start() {
setInterval(() => {
this.seconds++;
console.log(this.seconds); // this는 Timer 인스턴스를 참조
}, 1000);
}
}
const timer = new Timer();
timer.start();
// 1, 2, 3, ...
객체와 배열로부터 속성이나 요소를 손쉽게 추출해서, 변수에 할당하는 문법
객체의 속성을 바로 변수로 할당하기에, 별도 선언 없이 객체의 키 이름을 그대로 변수 이름으로 사용할 수 있다.
동작 원리
const obj = { a: 1, b: 2 };
const { a, b } = obj; // obj 객체에서 a, b를 추출해 각각 변수로 저장
console.log(a); // 1
console.log(b); // 2
객체나 배열의 특정 값을 변수로 추출하고, 해당 속성에 값을 할당하는 문법
중괄호 안에 명시된 경로에 따라 객체 내부의 값을 찾고, 해당 값을 새로운 변수에 할당
객체 속성을 기준으로 따로 변수 선언 없이 값을 꺼내올 수 있다.
const candyMachine = {
status: { //내부에 status 객체가 존재 name과 count 속성 포함
name: 'node',
count: 5,
},
getCandy(){ //메서드
this.status.count--; //값 반환 후 감소
return this.status.count;
},
}
const { getCandy, status: { count }} = candyMachine; //구조 분해 = 객체의 속성 키 이름을 그대로 사용해 변수를 자동 생
/* 위 코드를 구조 분해 없이 풀어서 쓰면
const getCandy = candyMachine.getCandy;
const count = candyMachine.status.count; */
console.log(getCandy); // [Function: getCandy] getCandy 함수 자체 (참조)
console.log(count); // 5 (status.count의 값)
candyMachine 객체 정의:
이 코드는 candyMachine이라는 객체를 정의하고 있다.
candyMachine 객체 안에는 두 가지 주요 요소가 있다.
status: 또 다른 객체로, 그 안에 name과 count라는 두 개의 키-값 쌍이 들어 있다.
getCandy: 메서드(일반 함수)로 정의된 함수다.
status의 구조:
status는 객체 내부에 있는 또 하나의 객체다.
status의 키와 값은
name: 'node' (문자열 데이터)
count: 5 (숫자 데이터)
getCandy 함수:
이 함수는 this.status를 참조하여, count 값을 하나 줄이고(this.status.count--), 줄어든 값을 반환한다(return this.status.count).
여기서 this는 candyMachine 객체를 참조한다. 즉, this.status는 candyMachine.status를 뜻한다.
const { getCandy, status: { count } } = candyMachine; >> 중첩된 객체에서 값을 추출
const 키워드
const는 변수를 선언하겠다는 의미로, getCandy와 count라는 두 변수를 선언하겠다는 의미중괄호 {}를 사용한 구조 분해
getCandy: 객체 candyMachine 의 속성 중 getCandy를 추출하여 변수 getCandy 변수에 할당
status: { count } : 객체 candyMachine의 status 속성에 접근한 뒤, 그 안에 있는 count 값을 추출해 변수 count에 할당한다.
status 속성 안에서 count 값을 추출해 중첩된 속성을 쉽게 가져올 수 있는 것이 구조 분해 할당의 장점
구조 분해로 변수를 만들 때, 다른 이름으로 사용할 수 있다.
const { getCandy: myCandyFunction, status: { count: candyCount } } = candyMachine;
console.log(myCandyFunction); // candyMachine.getCandy
console.log(candyCount); // candyMachine.status.count
getCandy 는 myCandyFunction 이라는 변수로 저장
status.count 는 candyCount라는 변수로 저장
기본 동작
배열의 인덱스 순서에 따라 값을 꺼내 변수를 초기화 한다.
중괄호
{}는 객체를 정의하거나 생성할 때 사용
var array = ['nodejs', {}, 10, true];
var node = array[0];
var obj = array[1];
var bool = array[3];
console.log(node); //nodejs
console.log(obj); //{} > 빈 객체 참조 = 객체를 값으로 저장
console.log(bool); //true
위와 같은 코드를 아래와 같이 할 수 있다
const array = ['nodejs', {}, 10, true];
const [node, obj, , bool] = array;
,(콤마)는 건너뛰기를 의미한다. array[2] 의 값인 10은 건너뛰어 변수로 할당되지 않고 bool 변수에 true가 할당된다.객체 구조 분해는 키로 접근
배열 구조 분해는 인덱스로 접근
클래스 기반 문법과 프로토타입 기반 문법
인스턴스(Instance) 의 개념
function Human(name) {
this.name = name;
}
const person1 = new Human('Hyunji');
const person2 = new Human('Zero');
console.log(person1.name); // Hyunji
console.log(person2.name); // Zero
class Human {
constructor(name) {
this.name = name;
}
}
const person1 = new Human('Hyunji');
const person2 = new Human('Zero');
console.log(person1.name); // Hyunji
console.log(person2.name); // Zero
var Human = function(type) {
this.type = type || 'human'; // type 기본값 설정
};
Human.isHuman = function(human) {
return human instanceof Human; // human이 Human의 인스턴스인지 확인하는 정적 메서드
};
Human.prototype.breathe = function() {
alert('h-a-a-a-m'); // 프로토타입 메서드
};
// Zero 생성자 함수 정의
var Zero = function(type, firstName, lastName) {
Human.apply(this, arguments); // Human의 생성자 호출 > this 초기화
this.firstName = firstName;
this.lastName = lastName;
};
// 상속 구현
Zero.prototype = Object.create(Human.prototype); // Human의 프로토타입을 상속받음
Zero.prototype.constructor = Zero; // Zero 생성자를 다시 설정
Zero.prototype.sayName = function() {
alert(this.firstName + ' ' + this.lastName); // Zero만의 메서드
};
var oldZero = new Zero('human', 'Zero', 'Cho');
console.log(Human.isHuman(oldZero)); // true
Object.create() : 주어진 객체를 프로토타입으로 설정한 새로운 객체를 생성 > 새로 생성된 객체는 ()안에 있는 객체를 상속 받게 되는 것 >> 자바스크립트에 내장되어 있는 함수
const proto = { greet: function() { console.log('Hello!'); } };
const obj = Object.create(proto);
obj.greet(); // 'Hello!' (proto 객체의 메서드 사용 가능)
// 위 함수로 생성한 객체는 프로토타입 체인을 통해 주어진 객체와 연결된다.
console.log(Object.getPrototypeOf(obj) === proto); // true
ES6에서 도입된 클래스 문법을 활용해 상속 구현
class Human {
constructor(type = 'human') {
this.type = type; // type 기본값 설정
}
static isHuman(human) {
return human instanceof Human; // Human의 정적 메서드
}
breathe() {
alert('h-a-a-a-m'); // 인스턴스 메서드
}
}
class Zero extends Human {
constructor(type, firstName, lastName) {
super(type); // 부모 클래스의 생성자 호출
this.firstName = firstName;
this.lastName = lastName;
}
sayName() {
super.breathe(); // 부모 클래스 메서드 호출
alert(`${this.firstName} ${this.lastName}`); // Zero만의 메서드
}
}
const newZero = new Zero('human', 'Zero', 'Cho');
console.log(Human.isHuman(newZero)); // true
Object.create 와 prototype.constructor를 직접 설정할 필요가 없다.1) 선언
클래스는 class 키워드를 사용하여 선언하며, 생성자 함수와 상속을 포함한 객체 생성 및 관리가 더 간편해진다.
2) 정적 메서드
static 키워드로 클래스에 속한 메서드를 정의한다. 정적 메서드는 클래스 자체에 속하며, 인스턴스에서는 호출할 수 없다.
3) 인스턴스 메서드
클래스 안에서 정의된 메서드는 각 인스턴스에서 사용할 수 있다.
4) 상속
extends 키워드로 부모 클래스를 상속받는다. super() 를 사용해 부모 클래스의 생성자와 메서드를 호출할 수 있다.
5) 문법 간결함
프로토타입 기반 코드를 작성할 때 필요한 Object.create와 prototype.constructor 설정을 자동으로 처리한다.
콜백 대신 프로미스 함수를 사용한다.
프로미스 객체의 세 가지 상태
Pending(대기 상태)
프로미스가 처음 생성되었을 때의 상태로, 작업이 아직 완료되지 않은 상태
resolve() 나 reject()가 호출되기 전의 상태
Fulfilled(이행됨)
작업이 성공적으로 완료되고, 결과 값을 반환하는 상태
resolve(값)이 호출되면서 then() 메서드 실행
Rejected(거부됨)
작업이 실패한 상태로, 에러가 반환된다.
reject(에러) 가 호출되면서 catch() 메서드 실행
Peding에서Fulfilled또는Rejected로 상태가 바뀌며, 이후에는 더 이상 상태가 변경되지 않는다 (불변 상태)
resolve()와 reject()
두 함수 모두 Promise 생성 함수 내 호출되어 상태 전환을 담당한다.
resolve(값)
프로미스의 상태를 Fulfilled 로 변경
resolve를 호출하면 리턴값이 then()으로 넘어간다
reject(에러)
프로미스의 상태를 Rejected로 변경한다.
reject를 호출할 때 리턴값(에러 메시지 등)이 catch()로 넘어간다.
finally 부분은 무조건 실행
new Promise를 사용해 비동기 작업을 나타내는 프로미스를 생성
const condition = true; // true면 resolve, false면 reject
const promise = new Promise((resolve, reject) => {
if (condition) {
resolve('성공');
} else {
reject('실패');
}
});
// 다른 코드가 들어갈 수 있음
promise
.then((message) => {
console.log(message); // 성공(resolve)한 경우 실행
})
.catch((error) => {
console.error(error); // 실패(reject)한 경우 실행
})
.finally(() => { // 끝나고 무조건 실행
console.log('무조건');
});
//성공
//무조건
const promise = new Promise((resolve, reject) => {
resolve('성공'); //resolve를 이용해 성공 상태로 전환
});
promise
.then((message) => {
return new Promise((resolve, reject) => { //새로운 Promise 객체를 생성해 이어받기
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() 블록은 값을 반환하거나 새 프로미스를 반환해야 다음 단계로 연결된다.
이전 단계에서 받은 값으로 새 프로미스를 생성하여 다음 then()으로 연결할 수 있다.
만약 then()에서 아무것도 반환하지 않으면, 기본적으로 undefined가 다음 단계로 전달된다.
//콜백 방식
function findAndSaveUser(Users) {
Users.findOne({}, (err, user) => { // 첫 번째 콜백 - DB에서 사용자 찾기
if (err) {
return console.error(err);
}
user.name = 'zero'; //찾은 사용자의 이름을 변경
user.save((err) => { // 두 번째 콜백 - 변경된 사용자 데이터를 저장
if (err) {
return console.error(err);
}
Users.findOne({ gender: 'm' }, (err, user) => { // 세 번째 콜백 - 조건에 맞는 사용자 다시 검색
// 생략
});
});
});
}
//Promise 방식
function findAndSaveUser(Users) {
Users.findOne({}) //Promise를 반환하여 첫 번째 사용자 검색
.then((user) => {
user.name = 'zero';
return user.save(); // 저장 결과 반환
})
.then((user) => {
return Users.findOne({ gender: 'm' }); // 새로운 사용자 검색
})
.then((user) => {
// 이후 작업
})
.catch(err => {
console.error(err); // 모든 과정에서의 에러 처리
});
}
Promise 방식은 비동기 작업을 then() 체이닝을 통해 순차적으로 처리하며, 코드가 훨씬 간결하고 읽기 쉬워진다.
모든 에러는 catch()에서 한 번에 처리한다.
Promise.all()
여러 개의 Promise를 배열로 받아 모든 Promise가 성공할 때 결과를 반환한다.
모든 Promise의 결과값이 배열 형태로 반환
하나라도 실패(reject)하면, 즉시 에러로 처리
성공: 모든 Promise가 resolve되면 then으로 결과가 전달
실패: 하나라도 reject되면 catch로 처리
const promise1 = Promise.resolve('성공1');
const promise2 = Promise.resolve('성공2');
Promise.all([promise1, promise2])
.then((result) => {
console.log(result); // ['성공1', '성공2'];
})
.catch((error) => {
console.error(error);
});
Promise.allSettled()
배열의 모든 Promise가 완료될 때까지 기다린 후, 성공(fulfilled)와 실패(rejected) 상태를 반환한다.
각 Promise의 상태롸 결과를 객체 형태로 반환
성공/실패 여부와 관계없이 모든 Promise가 완료된 후 결과를 볼 수 있다.
const promise1 = Promise.resolve('성공1');
const promise2 = Promise.resolve('성공2');
Promise.allSettled([promise1, promise2])
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
});
/* [
{ status: 'fulfilled', value: '성공1' },
{ status: 'fulfilled', value: '성공2' }
]
*/
Promise.resolve()
즉시 resolved 상태의 Promise를 생성한다.
초기값 설정이나 비동기 작업 없이 즉시 성공 값을 반환할 때 사용된다.
const promise = Promise.resolve('성공');
promise.then((result) => {
console.log(result); // '성공'
});
Promise.reject()
즉시 rejected 상태의 Promise를 생성한다.
비동기 작업 실패를 표현하거나 에러를 처리할 때 사용된다.
| 내장 함수 | 설명 | 특징 |
|---|---|---|
all | 여러 비동기 작업(여러 개의 프로미스를 동시에 실행)이 모두 성공해야 결과 반환(then). 하나라도 실패하면 에러 처리.(catch) | - 성공 시 결과를 배열로 반환 - 실패 시 빠르게 에러 처리. |
allSettled | 모든 비동기 작업이 완료되면 성공(fulfilled)과 실패(rejected) 상태를 반환. | - 각 상태와 결과를 객체로 반환. - 성공/실패 여부와 관계없이 결과 확인 가능. - 실패한 것만추릴 수 있다. |
resolve | 즉시 성공(resolved) 상태의 결과 생성. | - 비동기 작업 없이 성공값 반환. - 초기값 설정에 유용. |
reject | 즉시 실패(rejected) 상태의 결과 생성. | - 에러 상황 표현이나 테스트 시 유용. - 즉시 에러값 반환. |
Promise는 비동기 작업의 성공(resolve) 나 실패(rejected)를 처리하기 위한 객체 > 비동기 작업의 결과를then,catch등의 메서드로 처리 가능
async와await는 ES8에서 도입된 문법으로, Promise를 더 직관적으로 처리하기 위한 도구이다. 그러나 rejected를 처리하려면 try~catch 이용해야한다.
async
Promise 객체다.Promise.resolve()로 감싸진다.then() 또는 await을 사용해 결과를 처리할 수 있다.await
await 키워드는 async 함수 내부에서만 사용 가능하다.await은 Promise가 끝날 때까지 코드 실행을 일시 중단한다. > Promise가 resove 상태가 될 때까지 기다림//async
async function example() {
return "Hello, World!";
}
example().then((result) => {
console.log(result); // "Hello, World!"
});
//await
async function fetchData() {
const result = await new Promise((resolve) => {
setTimeout(() => resolve("비동기 작업 완료!"), 1000);
});
console.log(result); // "비동기 작업 완료!" (1초 후 출력)
}
fetchData();
function findAndSaveUser(Users) {
Users.findOne({})
.then((user) => { //실행이 완료되면 결과값이 user로 들어가서 실행
user.name = 'zero';
return user.save();
})
.then((user) => {
return Users.findOne({ gender: 'm' });
})
.then((user) => {
// 생략
})
.catch(err => {
console.error(err);
});
}
변수 = await 프로미스; 인 경우 프로미스가 resolve된 값이 변수에 저장
변수 await; 값인경우 그 값이 변수에 저장
async function findAndSaveUser(Users) {
let user = await Users.findOne({}); //순서가 오른쪽에서 왼쪽 순으로 진행된다고 생각하면 된다.
user.name = 'zero';
user = await user.save();
user = await Users.findOne({ gender: 'm' }); //마찬가지로 오른쪽에서 왼쪽
// 생략
}
Promise.resolve()로 감싸져서 반환된다.(해당 작업의 완료 상태) //개념적 예제 1
const promise = new Promise(...)
promise.then((result) => ...)
async function main() {
const result = await promise;
return result;
}
//아래 두 방법 중 택 1
main().then((name) => ...) //비동기의 반환값에 대해 호출하면서 then을 호출해야한다. > main().then()
const name = await main() //위와 같은 방법 또는 await을 사용해 작성 가능하다.
//응용적 예제 2
async function findAndSaveUser(Users) {
// 생략
}
findAndSaveUser().then(() => { /* 생략 */ });
// 또는
async function other() {
const result = await findAndSaveUser();
}
//개념적 예제 1
const promise = new Promise((resolve, reject) => {
reject('Promise rejected!'); // 에러 발생
});
async function main() {
try {
const result = await promise; // Promise의 결과를 기다림
return result; // 성공 시 결과 반환
} catch (error) {
console.error('에러 처리:', error); // 실패 시 에러 메시지 출력
}
}
main();
//응용 예제 2
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);
}
};
await을 사용하기 때문에 async 함수 안에서 사용해야한다.
각 Promise의 결과를 비동기적으로 처리하는 예제
for await (변수 fo 프로미스 배열)const promise1 = Promise.resolve('성공1'); //Promise.resolve : 즉시 resolved 상태의 Promise 생성
const promise2 = Promise.resolve('성공2');
(async () => {
for await (promise of [promise1, promise2]) {
console.log(promise);
}
})();
for-await-of 구문은 비동기 이터러블 객체를 순회하며, 각 Promise의 resolve 결과를 비동기적으로 처리한다.
const m = new Map(); //Map 생성
m.set('a', 'b'); //set(키, 값)으로 Map에 속성
m.set(3, 'c'); //문자열이 아닌 값을 키로 사용 가능
const d = {}; //객체 생성
m.set(d, 'e'); //객체도 키로 사용 가능 > 계속 비어 있는 객체로 유지되고 값만 바뀜
m.set({a: 'b'}, { c: 'd'}); //key도 객체, value도 객체 사용 가능
m.get({a: 'b'}); // 그러나 undefined > 위 {a: 'b'}와 여기 객체는 서로 다른 객체임
({ a: 'b' }) !== ({ a: 'b'}) // true > 객체는 참조타입으로 동작하기에 객체를 생성해 변수에 넣어 설정해줘야함
//해결책 > 변수에 객체를 저장 후 사용해야 같은 곳을 참조
const obj = { key : 'key' }
m.set(obj, 123);
m.get(obj); //123
m.get(d); //get(key) 로 속성값 조회
console.log(m.get(d)); //e
m.size; //속성 개수 조회 !== length와 다
console.log(m.size); //3
for(const [a, b] of m) {
console.log(a, b); //'a', 'b', 3, 'c', {}, 'e'
} //속성 간의 순서도 보장한다.
m.forEach((a, b) => {
console.log(a, b);
}); //forEach도 사용 가능하다. 결과는 위와 동일
m.has(d); //has(key)로 속성 존재 여부를 확인한다.
m.delete(d); //delete(key)로 속성을 삭제한다.
m.clear(); //clear()로 모든 키와 값을 전부 제거한다.
console.log(m.size); //0
Javascript의 참조 타입 개념
//원시타입
const a = 10;
const b = 10;
console.log(a === b); // true (값 비교)
//참조 타입
const obj1 = { key: 'value' };
const obj2 = { key: 'value' };
console.log(obj1 === obj2); // false (다른 메모리 주소를 참조)
따라서 Map에서 키나 값을 가져왔을 때 참조 타입이면 동일한 구조를 가진 값이라도 메모리주소가 다르면 같지 않다고 판단한다.
해결책
const objKey = { key: 'value' };
const map = new Map();
// 키를 동일한 참조로 사용
map.set(objKey, 'someValue');
// 같은 참조로 접근
console.log(map.get(objKey)); // 'someValue'
// 변수에 저장된 객체를 활용하여 비교
const value = map.get(objKey);
console.log(value === 'someValue'); // true
Set은 중복을 허용하지 않는다.
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()로 전부 제거한다.
기존 배열에서 중복을 제거하고 싶을 때
arr1 = [ 1, 1, 2, 2, 3, 3];
const s2 = new Set(arr1);
const result2 = Array.from(s2);
console.log(result2); //[1, 2, 3]