15. class

조뮁·2022년 8월 4일
0

JS중급

목록 보기
15/18
post-thumbnail

비슷한 모양의 객체를 생성하기 위한 두 가지 방법

1. 생성자 함수

const User = function(name, age){
  this.name = name;
  this.age = age;
  this.showName = function(){
    console.log(this.name);
  }
}
const mike = new User('Mike', 30);

  • mike : 객체 내부에 showName 존재

2. class

// class 사용
class User2 {
  // constructor : 객체를 만들어주는 생성자 메소드
  // new 를 통해 호출하면 자동으로 실행됨
  constructor(name, age){
    this.name = name;
    this.age = age;
  }
  // 클래스 내에 정의한 메소드는 User2의 prototype에 저장됨.
  // 
  showName(){
    console.log(this.name);
  }
}
const tom = new User2('Tom', 13);

  • prototype 내부에 showName 존재
mike.showName();  // Mike
tom.showName();  // Tom
  • showName 사용방법은 동일

생성자 함수로 class와 동일하게 객체 생성하기

const User = function(name, age){
  this.name = name;
  this.age = age;
}

// User생성자 함수로 생성하는 객체에 showName 프로퍼티를 추가해줌 
User.prototype.showName = function(){
  console.log(this.name);
}

const jane = new User('Jane', 12);

jane.showName();  // Jane


생성자함수와 class 차이

1. 함수 호출 시 규칙

// 생성자함수
const User = function(name, age){
  this.name = name;
  this.age = age;
}
User.prototype.showName = function(){
  console.log(this.name);
}
const mike = new User('Mike', 30);
console.log(mike);  // undefined



// class
class User2 {
  constructor(name, age){
    this.name = name;
    this.age = age;
  }
  showName(){
    console.log(this.name);
  }
}
const tom = User2('Tom', 13);
console.log(tom)  // error! Uncaught TypeError: Class constructor User2 cannot be invoked without 'new'
  • 생성자함수는 new 없이 호출해도 error가 발생하지 않지만, class는 new 없이 호출하면 타입 에러 발생
    • User함수는 return문이 없어서 아무것도 반환하지 않기 때문에 undefined 반환됨 -> error임을 즉시 알아차릴 수 없음

  • User2의 constuctor는 class라고 명시되어 있음
    • new 없이 호출하면 error 발생
    • constructor = class 임을 알 수 있음

2. for in 문 사용

// 생성자함수
const User = function(name, age){
  this.name = name;
  this.age = age;
}
User.prototype.showName = function(){
  console.log(this.name);
}
const mike = new User('Mike', 30);
for(const p in mike){
  console.log(p)
}
// "name"
// "age"
// "showName"


// class
class User2 {
  constructor(name, age){
    this.name = name;
    this.age = age;
  }
  showName(){
    console.log(this.name);
  }
}
const tom = new User2('Tom', 13);

for(const p in tom){
  console.log(p)
}
// "name"
// d"age"
  • for in 문은 prototype에 포함된 프로퍼티를 모두 보여줌 -> 객체가 가지고 있는 프로퍼티인지를 판별하기 위해 hasOwnProperty()를 사용했어야함.
  • class의 메소드는 for in문에서 제외됨

상속

  • 생성자함수 : prototype을 이용하여 상속 구현
  • class : extends 키워드 사용
class Car {
  constructor(color){
    this.color = color;
    this.wheels = 4;
  }
  // class내부에서 선언한 메소드는 __proto__ 내부로 들어감
  drive(){
    console.log('부릉');
  }
  stop(){
    console.log('멈춰!');
  }
}

// Car를 상속하여 Bmw 생성
class Bmw extends Car {
  // class내부에서 선언한 메소드는 __proto__ 내부로 들어감
  park(){
    console.log('주차');
  }
}

const z4 = new Bmw('blue');
z4.drive();  // 부릉


  • 부모 클래스를 상속받을 때 부모 클래스와 동일한 메소드가 존재한다면 instance의 메소드가 덮어씌워짐
class Car {
  constructor(color){
    this.color = color;
    this.wheels = 4;
  }
  drive(){
    console.log('부릉');
  }
  stop(){
    console.log('멈춰!');
  }
}

// Car를 상속하여 Bmw 생성
class Bmw extends Car {
  park(){
    console.log('주차');
  }
  // Car와 동일한 메소드를 추가한 상태에서 Car 상속
  stop(){
    console.log('STOP!!');
  }
}


const z4 = new Bmw('blue');
z4.stop()  // STOP!!

메소드 오버라이딩

  • super.메소드() 와 같이, 부모 클래스에서 정의된 메소드를 사용하는 것

super()

  • 부모 메소드를 그대로 사용하면서 확장할 때 사용하는 키워드
class Car {
  constructor(color){
    this.color = color;
    this.wheels = 4;
  }
  drive(){
    console.log('부릉');
  }
  stop(){
    console.log('멈춰!');
  }
}

// Car를 상속하여 Bmw 생성
class Bmw extends Car {
  park(){
    console.log('주차');
  }
  // Car와 동일한 메소드를 추가한 상태에서 Car 상속
  stop(){
    super.stop();
    console.log('STOP!!');
  }
}


const z4 = new Bmw('blue');
z4.stop()  
// 멈춰! 
// STOP!!
// instance의 메소드부터 탐색됨

생성자(constructor) overriding

class Car {
  constructor(color){
    this.color = color;
    this.wheels = 4;
  }
  drive(){
    console.log('부릉');
  }
  stop(){
    console.log('멈춰!');
  }
}

// Car를 상속하여 Bmw 생성
class Bmw extends Car {
  constructor() {
    this.navigation = 1;
  }
  park(){
    console.log('주차');
  }
}

const z4 = new Bmw('blue'); 
// error!
// VM39:17 Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor at new Bmw
  • constructor에서 this를 사용하기 전에, super constructor(=부모 생성자)를 먼저 호출해야함
  • constructor는 빈 객체는 생성하고, this는 이 빈 객체를 가르킴
    • extends로 만든 자식 클래스(Bmw)는 빈 객체가 만들어지고 this에 할당하는 작업을 건너뛰기 때문에, super(); 키워드로 부모 클래스의 constructor를 실행해줘야함.
class Car {
  constructor(color){
    this.color = color;
    this.wheels = 4;
  }
  drive(){
    console.log('부릉');
  }
  stop(){
    console.log('멈춰!');
  }
}

// Car를 상속하여 Bmw 생성
class Bmw extends Car {
  constructor() {
    super();
    this.navigation = 1;
  }
  park(){
    console.log('주차');
  }
}

const z4 = new Bmw('blue');
console.log(z4);
/* Bmw {color: undefined, wheels: 4, navigation: 1}
color: undefined
navigation: 1
wheels: 4
...
*/
  • color는 undefined임 -> 자식 클래스의 constuctor에 동일한 인수를 받아줘야함.
class Car {
  constructor(color){
    this.color = color;
    this.wheels = 4;
  }
  drive(){
    console.log('부릉');
  }
  stop(){
    console.log('멈춰!');
  }
}

// Car를 상속하여 Bmw 생성
class Bmw extends Car {
  constructor(color) {
    super(color);
    this.navigation = 1;
  }
  park(){
    console.log('주차');
  }
}

const z4 = new Bmw('blue');
console.log(z4);

/*
Bmw {color: 'blue', wheels: 4, navigation: 1}
color: "blue"
navigation: 1
wheels: 4
*/

js 동작 원리

class Bmw extends Car() {
  park() {
    console.log('주차');
  }
}
  • 자식 클래스 내부에 constructor가 없으면, js는 다음과 같이 동작한다.
class Bmw extends Car() {

  constructor(...args){
    super(...args);
  }
  
  park() {
    console.log('주차');
  }
}
  • constructor가 있는 것처럼 행동하기 때문에, 자식 생성자는 무조건 부모 생성자를 호출하게됨.
  • 자식 생성자에 constructor가 있다면, 항상 super()를 이용하여 호출하고, this.property로 할당해줘야함.
class Car {
  constructor(color){  (3) 
    this.color = color;
    this.wheels = 4;
  }
  drive(){
    console.log('부릉');
  }
  stop(){
    console.log('멈춰!');
  }
}

class Bmw extends Car() {

  constructor( (1) ){
    super( (2) );
  }
  
  park() {
    console.log('주차');
  }
}
  • 변수값을 (1) 에서 (2) 로 넘겨줘야 (3)까지 전달되어 부모클래스 메소드가 정상적으로 실행될 수 있음.

0개의 댓글