우테코 1주차 야구게임과 관련하여 자바스크립트의 클래스를 이해하고 사용하기 위해 공부 중 정리한 것들을 모아서 올림.
코딩을 시작함에 있어 어떤 것을 만들지 적고 시작하자. (package baseball;)
클래스, 함수의 이름을 정했다면 그 이름 답게 작동해야한다.
add(number1, number2) <- 메소드의 시그니쳐, 아이덴티파이라고
클래스를 사용하여 인스턴스를 만들었을 때 각각의 인스턴스는 서로 영향을 주지 않는다.
teacher , cal 인스턴스에서 클래스에서 선언된 변수를 바꾼다해도 teacher의 값과 cal의 값은 다르다.
객체지향 ?
1. 기능을 가지고 있는 클래스를 인스턴스화(=객체)한다.
2. 필요한 기능을 (역할에 맞는) 각 인스턴스가 수행하게 한다.(의인화)
3. 각 결과를 종합한다.
기능 목록을 작성 후 어떤 이름을 쓸까? 어떤 이름의 클래스 하에 있을까? 생각 -> 정리가됨
그런 후에 기본적인 뼈대를 작성해보자!
클래스에서 다른 클래스의 기능을 가져온다는 것을 객체지향에서는 협력한다고 한다.
출처([10분 테코톡] 가브리엘의 클래스와 객체)
class Car {
constructor(name) { //생성자
this.name = name;
this.position = 0;
}
move() { //메소드
this.position += 1;
}
honk() { //메소드
console.log(`${this.name} : ${'빵'.repeat(this.position)}`;
}
}
const car = new Car('가브리엘');
// 클래스 앞에 new를 붙여주면 인스턴스화가 가능하다.
클래스 내부에는 생성자 메서드, 프로토타입 메서드, 정적 메서드 3가지가 올 수 있다.
contructor라는 특수 키워드로 지정이 되있어서 1개 이하만 올 수 있고 이름 변경이 불가능하다.
추가로 암묵적으로 this를 반환하고 있기 때문에 return이 불가능하다.
move() 메서드는 사실 FunctionCar.prototype.move = function () {}처리된다.
특별한 명시가 없으면 프로토타입에 저장된다.
class Car {
constructor(name, date) {
this.name = name;
this. date = date;
}
static createCar() {
//this는 Car입니다.
return new this('가브리엘',new Date());
}
static staticMethod() {
console.log(this === Car);
}
}
car.staticMethod(); // true
const car = Car.createCar();
console.log(car); // Car {name: '가브리엘', date : 2023-02-21T18:03:43}
메서드 앞에 static을 입력하면 정적 메서드가 된다.
정적 메서드는 프로토타입이 아닌 클래스 함수 자체에 설정 되며, 인스턴스를 생성하지 않아도 호출할 수 있게된다.
어떤식으로 사용 되는가?
클래스에서 인스턴스를 생성하지 않고 클래스 내부의 메서드에서 this를 반환하는 식에서 new를 안쪽에서 붙혀주는 방식으로 스스로를 생성하게 해서 팩토리 메서드로 활용하는 방식이다.
접근자 프로퍼티로 get과 set 키워드를 제공한다.
class Car {
constructor(name, date) {
this.name = name;
this. date = date;
}
get name() {
return this._name
}
set name(newName) {
this._name = newName;
}
}
const car = new Car('가브리엘');
console.log(car); // Car {_name: '가브리엘', position : 0}
console.log(car.name); //가브리엘
car.name = '엘리브가';
console.log(car.name); //엘리브가
position과 달리, name 변수는 _name으로 관ㄹ리된다. 왜일까?
객체를 생성하고나서 인터셉터가 있으면 그냥 name이 아니라 underscore를 붙히는게 한 때 권장이 됬다.
constructor의 영향도 있다.
생성자를 생성하면서 바로 변수로 저장되는 것이 아니라 생성자 함수도 setter로 접근하려는 시도 때문에 이름을 겹치게 할 수가 없었다.
underscore가 없다면? 오류가난다.
왜냐? setter 내부의 this.name도 자기 자신을 호출하려고 시도하기 때문에
생성자 내부의 this.name도 setter를 건들고 setter내부의 this.name도 자기 자신을 건드는 거기 때문에 callstack 오류가 난다.
게터 세터를 활용하는 이유가 은닉화이기 때문에 변수 앞에 #을 붙혀서 은닉화할 수 있다.
class Car {
#name = '';
constructor(name, date) {
this.name = name;
this. date = date;
}
get name() {
return this.#name
}
set name(newName) {
this.#name = newName;
}
}
const car = new Car('가브리엘');
console.log(car); // Car {} 은닉화 중이라 안보임
console.log(car.name) // 가브리엘
프로토타입 상속과 클래스 상속은 명백하게 다른 개념이다.
prototype - 자바스크립트의 객체에 기본적으로 상속을 해주기 위함
classes - 상속을 통해 기존 클래스를 확장하여 새로운 클래스로 정의하기 위함
상속을 하는 부모 클래스, 받는 자식클래스가 계층구조로 이루어져 있다.
Class Vehicle {
constructor(name) {
this.name = name;
this.position = 0;
}
move() {
this.position += 1;
}
}
Class Car extends Vehicle {
honk() {
console.log(`${this.name} : ${'빵'.repeat(this.position)}`);
}
}
const car = new Car('가브리엘');
console.log(car); // Car { name: '가브리엘', position: 0}
car.move()
car.move()
car.move()
console.log(car); // Car {name : '가브리엘', position: 3}
car.honk(); // 가브리엘 : 빵빵빵
console.log(car instanceof Car); //true
console.log(car instanceof Vehicle) //true
Car 클래스에서 정의한 적이 없지만 다 알고있다.
car 인스턴스는 Car의 인스턴스이자 Vehicle의 인스턴스이다.
생성자 메서드에서 super 키워드를 호출하면 수퍼(부모)클래스에 있는 생성자를 호출한다.
Class base {
constuctor(a, b) {
this.a = a;
this.b = b;
}
}
class Derived extends base {
constructor(a,b,c) {
super(a,b)
this.c = c;
}
}
const derived = new Derived(1, 2, 3);
console.log(derived); // Derived { a: 1, b: 2, c: 3 }
자식 클래스에 constructor가 없으면 암묵적으로 contructor에 super가 활성화 되어 부모클래스의 constructor에 전달된다.
super 키워드는 오직 자식만 사용할 수 있다.
메서드가 바인딩된 객체(수퍼클래스의 prototype 프로퍼티에 바인딩 된 프로토타입)여야 참조가 가능
class Base {
constructor(name) {
this.name = name;
}
sayHi() {
return `Hi${this.name}`;
}
}
class Derived extends Base {
sayHi() {
return `${super.sayHi()}`;
}
}
const derived = new Derived('가브리엘');
console.log(derived.sayHi()); // Hi가브리엘
new 키워드 -> 자식 -> 부모 -> 인스턴스가 전달 후 위에서 아래로 다시 흐르며 반환해준다.