
제로베이스 자바스크립트 기초개념 클래스 부분 정리
축약된 부분이 존재할 수 있습니다.
클래스라는 것에 대해서 배워보자
// 객체 리터럴
const thw = {
name: "200원",
age: 200,
getBirthYear() {
const year = new Date().getFullYear();
return year - this.age;
},
};
const hhm = {
name: "황현민",
age: 19,
getBirthYear() {
const year = new Date().getFullYear();
return year - this.age;
},
};
console.log(thw.getBirthYear());
console.log(hhm.getBirthYear());
console.log(thw.getBirthYear === hhm.getBirthYear); // false
이렇게 객체 두 개의 동일한 함수를 놓고 사용하게 되면 두 개의 함수가 같지 않다고 판단하여 메모리에 두 개가 할당이 된다. 하지만 내용은 같기에 비효율적이라고 볼 수 있다.
const thw = {
name: "200원",
age: 200,
getBirthYear() {
const year = new Date().getFullYear();
return year - this.age;
},
};
const hhm = {
name: "황현민",
age: 19,
};
console.log(thw.getBirthYear());
// 함수의 this.age의 this가 hhm을 가리키게 됨
console.log(thw.getBirthYear.call(hhm));
// console.log(thw.getBirthYear === hhm.getBirthYear); // false
그럴 때, 이런식으로 사용하게 되면 메모리에 함수는 하나만 존재하게 되니 좀 더 효율적이라고 볼 수 있다.
하지만 이 부분도 계속 thw객체에서 함수를 불러와야하는 행위를 해야하기에 이때 클래스를 활용해 볼 수 있다.
// 프로토타입
function User(name, age) {
this.name = name;
this.age = age;
}
User.prototype.getBirthYear = function () {
const year = new Date().getFullYear();
return year - this.age;
};
const thw = new User("thw", 200);
const hhm = new User("hhm", 19);
console.log(thw);
console.log(hhm);
console.log(thw.getBirthYear());
console.log(hhm.getBirthYear());
console.log(thw.getBirthYear() === hhm.getBirthYear());
이런식으로 프로토타입을 이용해서 기존의 방법을 개선할 수 있다.
그럼에도 단점이 존재하는데, User부분이 function으로 되어있어서 함수인지 클래스인지 헷갈릴수 있다.
그래서 이것을 자바스크립트의 최신문법으로 class로 바꿀 수 있다.
// 프로토타입
class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
getBirthYear() {
const year = new Date().getFullYear();
return year - this.age;
}
}
const thw = new User("thw", 200);
const hhm = new User("hhm", 19);
console.log(thw);
console.log(hhm);
console.log(thw.getBirthYear());
console.log(hhm.getBirthYear());
console.log(thw.getBirthYear() === hhm.getBirthYear());
이런식으로 prototype을 class로 바꿔서 사용할 수도 있다.
값을 얻거나 지정할 떄 사용하는 함수
// class
class User {
constructor(first, last) {
this.first = first;
this.last = last;
this.fullName = `${first} ${last}`;
}
}
const thw = new User("200", "원");
// Get
console.log(thw.first);
//Set
thw.fullName = "황 현민";
console.log(thw);
이런식으로 하게되면 fullName을 바꾸게 될 때, first와 last는 안바껴서 불편할 수 있다. 또 다른 구조라면 더 불편할 수도 있다.
이럴 때 클래스의 Getter와 Setter라는 개념이 사용된다.
// class
class User {
constructor(first, last) {
this.first = first;
this.last = last;
}
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
set fullName(value) {
const names = value.split(" ");
this.first = names[0];
this.last = names[1];
}
}
const thw = new User("200", "원");
// Get
console.log(thw.fullName);
//Set
thw.fullName = "황 현민";
console.log(thw);
이런식으로 Getter와 Setter를 사용해서 함수를 속성처럼 사용할 수 있다.
정적 메소드(static method)는 주로 클래스의 유틸리티(보조) 함수를 만들 때 사용됩니다.
인스턴스와는 연결되지 않으며 , 클래스 자체에서 호출해야 합니다.
// 첫 번째 방식이 클래스의 생성자를 이용해서 인스턴스를 만드는 방식이고
// 이 생성자 방식을 좀 더 쉽게 만든 것이 기호를 사용해서 인스턴스를 만드는 두 번째의 리터럴 방식이다.
const fruits = new Array("Apple", "Banana", "Cherry");
// const fruits = ["Apple", "Banana", "Cherry"];
// fruits.includes("Apple");
// fruits.filter(item => item);
// fruits.push("orange");
// 프로토타입 함수의 그 클래스의 모든 인스턴스에서 사용이 가능하다.
Array.prototype.abc = function () {
console.log(this);
return this.map((item) => item.slice(0, 1).toLowerCase());
};
const newFruits = fruits.abc();
console.log(newFruits);
console.log(Array.isArray(fruits));
// fruits.isArray()가 없는 이유를 이제 알겠나?
// 모든 데이터 형식의 isArray()를 넣게 되면 낭비가 심하기 때문이다.
// 누가봐도 객체인데 객체.isArray()??를 하는 것이 이상하기 때문이다.
// 이러하여 정적 메소드를 사용해서 보조하는 기능을 만드는 것 같다.
console.log(Array.isArray(newFruits));
const user = { name: "200원" };
console.log(Array.isArray(user));
// user.isArray()
위 코드를 보며 prototype 함수와 정적 메소드의 차이를 확인할 수 있다.
그럼 실제로 정적 메소드를 어떻게 만들 수 있을까?
class User {
constructor(first, last) {
// this 키워드는 클래스로 생성된 인스턴스라고 생각하면 된다.
this.firstName = first;
this.lastName = last;
}
static isUser(user) {
return user instanceof User;
}
}
const thw = new User("200", "원");
const hhm = new user("황", "현민");
const hhh = {
name: "황황현",
age: 100,
};
console.log(User.isUser(thw));
console.log(User.isUser(hhm));
console.log(User.isUser(hhh));
이런식으로 정적메소드를 만들어서 사용할 수 있다.
클래스의 속성과 메소드를 다른 클래스에게 확(Extends)해서 재사용하는 기능을 말합니다.
class A {
constructor(a) {
this.a = a;
}
}
class B extends A {
constructor(a, b) {
// super를 사용하게 되면 부모 클래스의 생성자에 접근해서 값을 넣어준다.
super(a);
this.b = b;
}
}
const a = new A(1);
const b = new B(1, 2);
// a의 prototype이 Object라는 것은 a도 부모 클래스로 object를 상속받고 있다는 것이다.
console.log(a);
// b의 prototype은 A클래스로 부모 클래스로 A클래스를 상속받고 있다는 것이다.
console.log(b);
// A클래스에서 만들었기에 A클래스의 인스턴스가 맞음
console.log(a instanceof A); // true
// B클래스에서 만들었지만 A클래스의 확장 버전이기 때문에 A클래스의 인스턴스라고 볼 수 있음
console.log(b instanceof A); // true
// A클래스는 B라는 클래스의 상위 클래스이기 때문에 B라는 클래스의 인스턴라고 볼 수 없다.
console.log(a instanceof B); // false
// B클래스에서 만들었기에 Bs클래스의 인스턴스가 맞음
console.log(b instanceof B); // true
console.log(a instanceof Object); // true
console.log(b instanceof Object); // true