JavaScript(객체지향-2)

박정호·2022년 4월 1일
0

JS

목록 보기
8/24
post-thumbnail

만약 부모라는 객체의 내용을 가져다쓰고 싶으면 다음과 같이 생성자를 만들고, 새로운 오브젝트형으로 생성시켜줬어야 했다.

function 부모(){
	this.name = 'kim',
   this.age = 50
}
var 자식 = new 부모();

하지만 ES5부터는 Object.create()라는 문법이 있다. ES6부터는 class.

Object.create()

사용법은 쉽다. Object.create는 말그대로 객체생성이라는 뜻이고, 괄호안에는 부모오브젝트를 작성한다. 따라서, 자식 객체에서 부모의 age 속성을 사용할 수 있다.

var 부모 = { name : 'Kim', age : 50 };
var 자식 = Object.create(부모);
console.log(자식.age); //50

이때 자식 객체를 출력해보면,

console.log(자식);

다음과 같이 자식 자체의 객체는 비어있으므로 {}처럼 빈객체가 출력된다. 그리고 부모의 prototype 물려받았으므로 사용이 가능하다.

만약 자식의 age를 변경하면?

var 부모 = { name : 'Kim', age : 50 };
var 자식 = Object.create(부모);
자식.age  = 20;
console.log(자식.age); //20 나옴

오브젝트 자료형에서 특정 자료를 꺼낼때 순서가 있다는 것을 항상 명심!
자식.age를 출력하려 한다면?
1. 자식이라는 object가 직접 age를 가지고 있으면 그 값을 출력(위의 코드에서는 가지고 있으므로 20을 출력)
2. 자식에게 없다면 부모 prototype 안에 age가 있다면 그 값을 출력(age:50)
3. 부모에도 없다면 그 부모의 객체의 prototype에서 찾게 된다.

자식의 자식 또한 생성 가능.

var 부모 = { name : 'Kim', age : 50 };
var 자식 = Object.create(부모);
자식.age  = 20;
var 손자 = Object.create(자식);
console.log(손자.age);

이제 손자라는 객체는 부모와 자식의 속성을 모두 물려받은 것이고, 손자.age를 출력하면 손자의 부모인 자식의 prototype에 존재하는 age = 20 을 가져오게 된다.

이때 손자라는 객체를 출력한다면,

console.log(손자);

class

ES2015에서 도입된 클래스는 생성자의 기능을 대체. class 표현식을 사용하면, 생성자와 같은 기능을 하는 함수를 훨씬 더 깔끔한 문법으로 정의 가능.
class를 사용하는 가장 큰 이유는 재사용성이다.
작은 사이트의 경우 잘 만든 Function하나로도 충분히 개발이 용이할수 있지만, 좀 더 복잡한 사이트를 만들게 될 경우 Class의 장점을 더 잘 알 수 있을 것이다.

참고: [김평범's OrdinaryCode]

특징

  • 클래스는 함수의 한 종류이다. 단, 다음과 같이 함수와 같은 형식의 동작은 하지 않는다.
class Person {
  console.log('hello');
} // 에러: Unexpected token
  • 클래스는 객체가 아니다.
  • 클래스는 함수로 호출될 수 없습니다.
  • 클래스 선언은 let과 const처럼 블록 스코프
  • 클래스는 호이스팅(hoisting)이 일어나지 않는다.
  • 클래스의 메소드 안에서 super 키워드를 사용 가능.

기본 틀은 다음과 같다.

class 부모 {
  constructor(){
    this.name = 'Kim'
  }
}
var 자식 = new 부모();

만약 상속가능한 함수를 추가하려면?

방법1. contructor()안에 추가하는 법

class 부모 {
  constructor(){
    this.name = 'Kim';
    this.sayHi = function(){ console.log('hello') }
  }
}
var 자식 = new 부모();

다음과 같은 코드 출력시

console.log(자식);
console.log(부모);
console.log(부모.prototype);
자식.sayHi();


방법2. 클래스 내의 메서드 형식으로 추가하는 법(이 방법의 경우 해당 메서드는 자동적으로 부모.prototype에 저장된다.)

class 부모 {
  constructor(){
    this.name = 'Kim';
  }
  sayHi(){ 
    console.log('hello') 
  }
}
var 자식 = new 부모();

다음과 같은 코드 출력시

console.log(자식);
console.log(부모);
console.log(부모.prototype);
자식.sayHi();


방법3. .prototype을 이용해 추가하는법(2번과 같은 맥락)

부모.prototype.sayHi = function(){} 

방법1의 경우 자식이 직접 부모의 함수를 가지게 되는 경우이고, 방법2와 방법3은 부모 prototype에 추가되는 것이다.

Object.getPrototypeOf()

_proto__키워드와 비슷한 역할을 하는 함수이다. Object라는 가장 큰 부모안에 있는 내장함수라고 할 수 있다. 괄호안에 자식 오브젝트를 넣으면 부모의 prototype을 알 수 있는 기능이다.

다음과 같이 출력하면, console.log(부모.prototype) 과 같은 뜻이다.

console.log(Object.getPrototypeOf(자식))

클래스 내의 constructor안에 파라미터 추가하기

생성자 함수를 생성했을 때 파라미터 값을 넘기는 것과 완전히 일치하다. 자식은 부모 안에 constructor함수에 파라미터를 전달해야 하므로 다음과 같은 코드를 작성하면 된다.

class 부모 {
  constructor(이름, 나이){
    this.name = 이름;
    this.age = 나이;
  }
}
var 자식 = new 부모('Park', 30);

prototype 내에 함수 여러개 추가하기

다음과 같이 작성하면 끝~~

class 부모 {
  constructor(이름, 나이){
    this.name = 이름;
    this.age = 나이;
  }
  sayHi(){
    console.log('안녕');
  }
  sayHello(){
    console.log('안녕하세요');
  }
}
var 자식 = new 부모('Park');

extends / super

다음과 같이 할어버지라는 class가 존재한다.

class 할아버지{
  constructor(name){
    this.성 = 'Kim';
    this.이름 = name;
  }
}

만약 할아버지 클래스의 속성들을 복사하여 새로운 클래스를 생성하고 싶다면?
물론 하드코딩하면 그대로 복사 붙여넣기 하면 될 것이다. 하지만, 코드가 길어질 경우 하드코딩이 더 귀찮아지는 일이기 때문에 상속 기능을 사용하면 편리하다.

다음과 같이 extends 이용하여 할아버지 클래스의 속성을 아버지 클래스에서 그대로 가져다 쓰겠다는 말이고, 자식은 아버지 클래스로부터 새로운 오브젝트를 생성한다. 이때, 자식이 할아버지의 속성을 가지고 가는 것과 마찬가지 인 것이다.

class 할아버지{
  constructor(name){
    this.성 = 'Kim';
    this.이름 = name;
  }
}
class 아버지 extends 할아버지{
}
var 자식 = new 아버지('민수');
console.log(자식); //{성: 'Kim', 이름: '민수'}

만약 아버지 클래스에도 새로운 속성을 추가하고 싶다면?

똑같이 생성자를 만들어주고 속성을 추가하면 된다. 이때, super()함수를 통해서 할아버지 클래스의 namse 파라미터를 똑같이 명시해줘야 속성을 정확히 상속 받을 수 있다.

class 할아버지{
  constructor(name){
    this.성 = 'Kim';
    this.이름 = name;
  }
}
class 아버지 extends 할아버지{
  constructor(name){
    super(name);
    this.나이 = 50;
  }
}
var 자식 = new 아버지('민수');
console.log(자식);

따라서 자식을 출력하면, 자식은 할아버지의 성,이름 속성을, 아버지의 나이 속성을 상속 받아 다음과 같이 출력된다.

할아버지 클래스에 메소드를 추가하려면?

자식이 sayHi 함수를 사용하기 위해서는 다음과 같은 절차 실행!
1. 자식 오브젝트에 sayHi 메서드가 존재하는가 (X)
2. 없으면 아버지.prototype에 sayHi가 메서드가 존재하는가 (X)
3. 없으면 할아버지.prototype에 메서드가 존재하는가 (O)

class 할아버지{
  constructor(name){
    this.성 = 'Kim';
    this.이름 = name;
  }
  sayHi(){
    console.log('안녕 나는' + this.name)
  }
}
class 아버지 extends 할아버지{
  constructor(name){
    super(name);
    this.나이 = 50;
  }
}
var 자식 = new 아버지('민수');
자식.sayHi(); // 안녕 나는 민수

class간에 함수를 상속하고 싶다면?

위에서 본 할아버지 클래스의 sayHi()를 아버지 클래스에서도 사용하고 싶다면...
즉, 아버지 클래스에 새로운 메서드(prototype)를 만들고 할아버지 클래스의 메서드를 활용하고 싶은 것이다. 그렇다면 super()을 통해서 부모 클래스의 prototype에 접근하면 된다.

class 할아버지{
  constructor(name){
    this.성 = 'Kim';
    this.이름 = name;
  }
  sayHi(){
    console.log('안녕 나는 할아버지)
  }
}
class 아버지 extends 할아버지{
  constructor(name){
    super(name);
    this.나이 = 50;
  }
   sayHi2(){
    console.log('안녕 나는 아버지');
    super.sayHi();
  }
}
var 자식 = new 아버지('민수');

정리) super의 2가지 용도

1. 자식 클래스 내에서 부모클래스의 생성자 역할(constructor 안에서 쓰면 부모 class의 constructor)
2. 자식 클래스에서 부모 클래스의 메소드 접근 역할 (prototype 함수 안에서 쓰면 부모 class의 prototype)

instanceof

  • instanceof 연산자를 사용하면 객체가 특정 클래스에 속하는지 아닌지를 확인 가능
  • instanceof는 상속 관계도 확인가능

Class의 객체 확인

class Rabbit {}
let rabbit = new Rabbit();
// rabbit이 클래스 Rabbit의 객체인가요?
alert( rabbit instanceof Rabbit ); // true

생성자함수의 객체 확인

// 클래스가 아닌 생성자 함수
function Rabbit() {}
alert( new Rabbit() instanceof Rabbit ); // true

내장함수의 확인

let arr = [1, 2, 3];
alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true

참고:https://ko.javascript.info/instanceof

응용
조건)
(1) 한살먹기 함수는 강아지 class로부터 생성된 오브젝트가 사용하면 콘솔창에 에러를 출력해주어야합니다.
(2) 한살먹기 함수는 고양이 class로 부터 생성된 오브젝트가 사용하면 현재 가지고있는 age 속성에 1을 더해주는 기능을 실행해야합니다.

다음의 코드에서는 Dog클래스로부터 새로운 객체를 생성한 강아지는 age라는 속성을 갖고 있지 않다. 반면 Cat클래스로부터 새로운 객체를 생성한 고양이는 age라는 속성을 가지고 있다.
이때, Dog 클래스의 한살먹기 함수의 동작은 this.age++ 로 age의 값을 가질 경우 수행되므로, 강아지.한살먹기()를 수행할 경우 age에 대한 값은 출력되지 않는다. 따라서, 한살먹기 함수는 Cat을 상속받은 객체만 사용 가능하다는 조건을 줄 수 있는데, 이때 instanceof()를 사용할 수 있고, a instanceof b는 a가 b로부터 생성된 객체인지 아닌지 true/false로 알려주는 경우를 말한다. 따라서, this(인스턴스)가 Cat 클래스에 상속되었으면 true이므로 this.age++가 동작한다.

class Dog {
  constructor(타입, 칼라){
    this.type = 타입;
    this.color = 칼라;
  }
  한살먹기(){
    if( this instanceof Cat) {
    this.age++
    }
  }
}
class Cat extends Dog {
  constructor(타입, 칼라, 나이){
    super(타입, 칼라);
    this.age = 나이;
  }
}
let 강아지 = new Dog('진돗개', 'brown');
let 고양이 = new Cat('코숏', 'white', 5);
강아지.한살먹기(); //에러 출력
고양이.한살먹기(); // age에 인자값으로 준 5가 +1 되어 6이 된다.
profile
기록하여 기억하고, 계획하여 실천하자. will be a FE developer (HOME버튼을 클릭하여 Notion으로 놀러오세요!)

0개의 댓글