[ JS ] - 클래스

200원짜리개발자·2024년 6월 13일

FrontEnd

목록 보기
25/29
post-thumbnail

제로베이스 자바스크립트 기초개념 클래스 부분 정리
축약된 부분이 존재할 수 있습니다.

클래스

클래스라는 것에 대해서 배워보자

개요

// 객체 리터럴
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로 바꿔서 사용할 수도 있다.

Getter & Setter

값을 얻거나 지정할 떄 사용하는 함수

// 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
profile
고3, 프론트엔드

0개의 댓글