화살표 함수
var는 let,const에 의해 대체가 쌉가능.
그치만 화살표함수는 함수선언문(function(){}) 을 완벽하게 대체할 수 없다.
{} return이 같이 나오면 생략 가능함.
function add1(x,y){
return x+y
}
const add2 = (x,y) => {return x+y}
const add2 = (x,y) => x+y
const add2 = (x,y) => x+y
객체를 리턴하는 경우엔 소괄호가 필수다.
엔진이 헷갈려버려잉
const obj = (x,y) => ({x,y})
기존 function이 안사라진 이유는 this 떄문이다.
var relationship1 = {
name: 'minho'
friends : ['minsoo','mindo','mini']
logFriends : function(){
var that = this; //relationship1을 가리키는 this를 that에 저장
this.friends.forEach(function(friend){
console.log(that.name , friend)
})
},
};
relationship1.logFriends()
부모의 this를 받으려면 that 또는 self 이런 걸 써줬어야 함. (안그러면 window 로 찍힘)
근데 이건 화살표함수를 쓰면, 자기만의 this를 안가지고 부모한테서 물려받음 ㅇㅇ 자기 this가 없음.
var relationship1 = {
name: 'minho'
friends : ['minsoo','mindo','mini']
logFriends : function(){
this.friends.forEach(friend => {console.log(this.name,friend)})
},
};
relationship1.logFriends()
함수 선언문은 자기만의 this를 가질 수 있음. 그래서 살아남음.
button.addEventListner('click',function(){
console.log(this.textContent)
})
- 여기서 function 키워드로 만든 일반 함수는 this가 호출하는 객체를 가리켜요.
- addEventListener 안에서는 이벤트가 연결된 button 요소가 this가 됩니다.
- 그래서 this.textContent는 버튼 안에 있는 텍스트를 정확히 출력합니다.
button.addEventListner('click',() => {
console.log(this.textContent)
})
- 화살표 함수는 자신의 this를 가지지 않아요. 대신, 화살표 함수가 정의된 위치의 this를 상속받아요.
- 즉, this는 버튼이 아니라 **그 코드를 감싸고 있는 상위 스코프의 this*를 가리키게 됩니다.
- 브라우저 환경에서는 상위 스코프가 **전역 객체 (window)**일 가능성이 커요. window.textContent는 없으니 출력이 안 되는 거죠.
그래서 this를 쓸거면 함수선언을 하고 this를 안쓸거면 화살표함수로 통일하는 것을 권장한다고 함.
구조분해 할당
객체는 키가 정확히 일치해야 한다.
//이렇게 꺼냈어야 했는데
const example = {a: 123, b: {c:135, d:146}}
const a = example.a;
const d = example.b.d;
// 구조분해 문법
const {a,b:{d}} = example;
console.log(a) // 123
console.log(d) // 146
array에서 사용할 땐 자리를 맞춰줘야 한다.(0부터 시작함.)
arr = [1,2,3,4,5]
const x = arr[0]
const y = arr[1]
const z = arr[4]
const [x,y,,,z] =.arr;
this가 있을 땐 구조분해 할당을 안하는게 좋다. (문제가 생긴다고 하는데 알아보자)
Class,프로토타입
Class는 프로토타입이다. (JS 객체의 숨겨진 설계도)
"프로토타입은 객체가 자신의 부모처럼 여기는 또다른 객체다"
// 객체 생성
const obj = {name : "minho"}
//obj의 프로토타입 확인
console.log(Object.getPrototypeOf(obj)); // [object : null prototype] {}
obj 객체는 프로토타입으로 object.prototype을 갖고 있다.
즉,Obj가 직접 갖고 있지 않은 메서드나 속성은 object.prototype에서 찾는다.
프로토타입 체인
JS에서 객체는 프로토타입 체인을 통해 필요한 속성을 찾는다.
const obj = {};
//toString은 어디서 오지?
console.log(obj.toString()); // [object object]
// obj에는 toString이 없으니, Object.prototype에서 찾는다!
프로토타입 직접 만들기
JS에서 생성자 함수나 Class로 객체를 만들 때도 프로토타입이 자동으로 설정 된다.
// 생성자 함수
function Person(name){
this.name = name;
}
//프로토타입 추가
Person.prototype.sayHello = function (){
return `안녕하세요,저는 ${this.name}입니다.`
}
//객체 생성
const minho = new Person('민호라는 사람')
console.log(minho.sayHello()); // 안녕하세요 저는 민호라는 사람입니다.
minho라는 객체는 sayHello 메서드를 직접 가지지 않는다.
대신,Person.prototype에 잇는 sayHello를 사용한다.
Class로도 똑같이 작동한다.
class 문법은 사실 프로토타입을 편하게 쓰기 위한 syntax sugar다.
내부적으로는 프로토타입 기반으로 동작한다.
class Person{
constructor(name){
this.name = name
}
sayHello(){
return `안녕하세요 저는 ${this.name}입니다!`
}
}
const minho = new Person('민호라는 사람')
console.log(minho.sayHello()); // 안녕하세요 저는 민호라는 사람입니다.
요약
- 프로토타입은 객체가 상속받는 또 다른 객체
- 프로토타입 체인 : 필요한 속성이나 메서드를 객체에서 못찾으면 부모 프로토타입에서 찾음
- Class 문법도 프로토타입 기반으로 작동
생성자,스태틱 메서드,인스턴스 메서드
생성자
- 클래스 인스턴스를 만들 때 호출 되는 세더드
- 객체의 초기값(프로퍼티)를 설정하거나 초기화하는 데 사용된다.
- 클래스를 'constructor'라는 이름으로 정의한다.
특징
- new 키워드로 클래스를 호출하면 자동으로 실행한다.
- 한 클래스에 생성자는 하나만 정의할 수 있다.
class Person {
constructor(name,age){
this.name = name // 초기값 설정
this.age = age;
}
}
const minho = new Person('민호',28)
console.log(minho.name) // 민호
console.log(minho.age) // 28
스태틱 메서드(Static Method)
- 클래스에 직접 붙어 있는 메서드다.
- 즉, 클래스 자체에서 호출하지,생성된 인ㄷ스턴스에서는 호출할 수 없다.
- static 키워드로 정의한다
특징
- 클래스의 유틸리티 함수처럼 동작한다.
- ex)데이터 변환, 특정 계산 등
- 인스턴스와 무관하게 동작하며,클래스의 공통 기능을 구현할 때 사용한다.
class Calculator{
static add(a,b){
return a+b ; //인스턴스 없이도 동작
}
}
console.log(Calculator.add(3,7)); //10
// const calc = new Calculator();
// console.log(calc.add(3,7)) // 오류 (스태틱 메서드는 인스턴스에서 호출 불가)
인스턴스 메서드(Instance Method)
- 생성된 인스턴스에서 호출할 수 있는 메서드
- 클래스 내부에서 정의하지만, static 키워드를 쓰지 않으면 인스턴스 메서드가 된다.
특징
- 보통 인스턴스의 속성(this)를 사용하거나 변경하는데 사용된다.
- 생성된 객체마다 별도로 작동한다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `안녕하세요, 저는 ${this.name}이고, 나이는 ${this.age}살이에요.`;
}
}
const minho = new Person("민호 싸장님", 28);
console.log(minho.greet()); // 안녕하세요, 저는 민호 싸장님이고, 나이는 28살이에요.
구분 특징 호출 방식 사용 목적
생성자 | 클래스 인스턴스를 초기화함 | new 키워드로 호출 | 초기값 설정 |
스태틱 메서드 | 클래스에 직접 속하며 인스턴스와 관계없음 | ClassName.method() | 유틸리티, 공통 기능 |
인스턴스 메서드 | 생성된 인스턴스에서 호출 가능 | instance.method() | 인스턴스별로 동작하는 기능 |
- 생성자: 객체 초기화용! (constructor)
- 스태틱 메서드: 클래스 자체에서 호출! (static)
- 인스턴스 메서드: 객체 만들어야 호출 가능! (this 사용)
ES5이전엔 이렇게 상속 받아야 했음.
- Zero 생성자가 호출됨.
- Human.apply(this, arguments)가 실행돼서:
- this는 Zero의 인스턴스.
- arguments는 Zero에 전달된 모든 인자.
- 결과적으로 Human의 속성이 Zero의 인스턴스에 복사됨.
function Human(type, firstName, lastName) {
this.type = type;
this.firstName = firstName;
this.lastName = lastName;
}
var Zero = function (type, firstName, lastName) {
Human.apply(this, arguments); // Human 생성자 실행
};
const zero = new Zero("human", "Minho", "Shin");
console.log(zero); // Zero { type: 'human', firstName: 'Minho', lastName: 'Shin' }
!https://prod-files-secure.s3.us-west-2.amazonaws.com/d76682c0-0f4f-40ea-a410-86c0df396285/541d9002-f391-4bcc-a6f5-771fa46a3814/스크린샷_2025-01-11_오전_9.37.25.png
ES6 이후 버전에서는?
요즘은 class와 extends를 사용해 더 간단하게 상속을 구현할 수 있다.
class Human {
constructor(type, firstName, lastName) {
this.type = type;
this.firstName = firstName;
this.lastName = lastName;
}
}
class Zero extends Human {
constructor(type, firstName, lastName) {
super(type, firstName, lastName); // 부모 생성자 호출
}
}
const zero = new Zero("human", "Minho", "Shin");
console.log(zero); // Zero { type: 'human', firstName: 'Minho', lastName: 'Shin' }
- super()를 사용하면 부모 클래스의 생성자를 호출하고, this를 초기화한다..
- apply 같은 복잡한 문법을 쓸 필요가 없다.
- Human.apply(this, arguments)는 부모 생성자의 속성을 자식에 복사하기 위한 방법!
- this: 현재 인스턴스(Zero의 인스턴스).
- arguments: Zero에 전달된 모든 인자.
- 요즘은 ES6의 super()로 더 간단하게 쓸 수 있다.
Promise,async/await
- Promise : 내용이 실행은 되었지만 결과를 아직 반환하지 않은 객체
- Then을 붙이면 결과를 반환함
- 실행이 완료되지 않았으면 완료된 후에 Then 내부 함수가 실행 됨
Resolve(성공리턴값) -> then으로 연결
Reject(실패리턴값) -> catch로 연결
Finally 부분은 무조건 실행 됨
Promise.all
allSettled로 실패한 것만 추려낼 수 있음
async function findAndSaveUSer(User){
let user = await Users.findOne({})
user.name = 'zero'
user = await user.save()
user = await Users.findOne({gender : 'm'})
}
여기서 await 코드를 쉽게 말하면 오른쪽부터 실행되는 것이다.
let user = await Users.findOne({})
- Promise ( Users.findOne({}) )
- then (await)
- 결과값 (user)
다른 await 함수들도 똑같다.
await 함수는 항상 Promise를 반환한다?
이게 무슨 말이냐면 await 을 쓰면 항상 변수에 값이 담겨서 나온다는 거다.
resolve(성공),Rejected(실패) 중에 하나가 나온다.
await은 "Pending" 상태가 끝날 때까지 기다린 다음,
- Resolved → 값을 반환.
- Rejected → 오류를 던짐.
const result = await Promise.resolve("라멘집 최고!");
// 이 코드는 아래와 같이 된다.
const result = "라멘집 최고!";
'Back-End > Node.js' 카테고리의 다른 글
Node.js교과서 PART3 (0) | 2025.02.13 |
---|---|
Node.js 교과서 PART2 (2-1) (0) | 2025.02.13 |
Node.js 교과서 PART2 (1) (0) | 2025.01.19 |
Node.js 교과서 PART1 (0) | 2025.01.18 |
다시 시작하는 Node.js, 새로 시작하는 CS (0) | 2025.01.11 |