클래스 개념 - Class Concept

Evan Lee ㅣ 2022. 7. 1. 01:38

new 연산자와 생성자 함수(Constructor function)

보통 객체를 만들때 객체 리터럴로 만드는데,  그러다보면 유사하지만 value값이 다르거나 유사한 객체를 만드려면 일일이 만들어줘야 할 경우가 생깁니다. 

const jeongmin = {
  firstName : 'Jeongmin',
  lastName : 'Lee',
  getFullName: function(){
    return `${this.firstName} ${this.lastName}`
  }
}
const evan = {
  firstName : 'Evan',
  lastName : 'Park',
  getFullName: function(){
    return `${this.firstName} ${this.lastName}`
  }
}

예를 들어 위에 코드 처럼 

이렇게 두가지면 괜찮지만 가짓수가 많아지면 좀 많이 귀찮아지겠죠 ? 그래서 생성자 함수를 만들어서 사용을 하는데

일반 함수와 다른점은 두가지가 있습니다.

1. 함수 이름 첫 글자는 대문자로 시작합니다.
2. 반드시 'new' 연산자를 붙여 실행합니다. 
function User(first, last){
  this.firstName = first
  this.lastName = last
}

const jm = new User('Jeongmin', 'Lee');
const ep = new User('Evan', 'Park');

console.log(jm);  // User{firstName: 'Jeongmin', lastName: 'Lee'}
console.log(ep);  // User{firstName: 'Evan',     lastName: 'Park'}

하지만 이렇게 생성자 함수를 만들어서 출력을 해보았지만 출력값이 이상합니다.

네 생성자 함수를 호출하게 되면 this가 암시적으로 만들어지고, this를 반환하게 되고 이게 곧 함수 자체의 정보를 뜻합니다. 

그리고 그 정보들을 참조하게 되는 변수들을 인스턴스라고 부르는데 이게 jm, ep 겠네요. 

 

function User(first, last){
  this.firstName = first
  this.lastName = last
}

User.prototype.getFullName = function () {
  return `${this.firstName} ${this.lastName}`
}

const jm = new User('Jeongmin', 'Lee');
console.log(jm.getFullName()); // Jeongmin Lee

 

우리가 원하는 출력을 원하면 prototype을 통해서 메소드를 하나 만들어줘야합니다. 그걸 적용을 해보면 

 

원하는 생성자 함수에 이런식으로 prototype을 통한 메소드를 할당해주면 메소드가 호출 될 때마다 메모리를 하나씩만 먹기 때문에, 

이가 메모리 관리 측면에서 더 효율적이라고 합니다.

 

 

this 

일반(Normal) 함수는 호출 위치에서 따라 this 정의!
화살표(Arrow) 함수는 자신이 선언된 함수 범위에서 this 정의!
const jeongmin = {
  name: 'Evan',
  normal: function(){
    console.log(this.name);
  },
  arrow: () => {
    console.log(this,name);
  }
}
jeongmin.normal() // Evan
jeongmin.arrow()  // undefined

 

또 다른 예시 

 

const timer = {
  name : 'Jeongmin!!',
  timeout: function(){
   setTimeout(function () {
     console.log(this.name)
   }, 2000)
  }
}
timer.timeout(); // undefined

const timer = {
  name : 'Jeongmin!!',
  timeout: function(){
   setTimeout(()  => {
     console.log(this.name)
   }, 2000)
  }
}
timer.timeout(); // Jeongmin!!

보통 타이머 함수를 사용할때는 콜백함수로 arrow function을 추천한다고 합니다. 보통 저렇게 객체네에서 수행할 확률이 높기 때문이라고 하네요. 

 

ES6 Classes

function User(first, last){
  this.firstName = first
  this.lastName = last
}
User.prototype.getFullName = function () {
  return `${this.firstName} ${this.lastName}`
}


// ES6 class 문법 적용시


class User {
  constructor(first, last){
    this.firstName = first
    this.lastName = last
  }
  getFullName(){
    return `${this.firstName} ${this.lastName}`
  }
}

 

상속(확장) - Inheritance(Extension)

class Coffee{
  constructor(size, shot){
    this.size = size
    this.shot = shot
  }
}
class americano extends Coffee {
  constructor(size,shot){
    super(size,shot)
  }
}
const myamericano = new americano('grande',3)
console.log(myamericano); // {"size": "grande","shot": 3
}

class latte extends Coffee{
  constructor(size,shot, add){
    super(size, shot)
    this.add = add
  }
}
const mylatte = new latte('tall',1,'milk')
console.log(mylatte); //{"size": "tall","shot": 1,"add": "milk"}

Coffee 라는 클래스를 자식 클래스들이 상속을 받아 별다른 추가 없이 부모클래스의 기능을 그대로 가져와서 사용이 가능하다.

이때 super라는 함수가 부모클래스로 실행될 수 있게 부모클래스에서 요구하는 인수들을 생성자 함수 선언시 넣어준다.