JS(Section 13. 프로토타입)

짜스의 하루 ·2024년 4월 26일

I. 프로토타입 prototype
자바스크립트는 프로토타입 기반의 객체지향 프로그래밍을 지원하는 언어

모든 객체는 prototype이라는 속성을 가지고 있다. 이 속성은 객체를 생성한 생성자 함수의 프로토타입 객체를 가리킨다. 생성자 함수로부터 생성된 모든 객체는 해당 생성자 함수의 프로토타입 객체를 공유한다. 이는 객체들 간에 메서드와 속성을 공유하게 해주며, 객체를 생성한 후에도 프로토타입 객체를 수정하여 객체들에 대한 변경사항을 반영할 수 있게 해준다.

⭐ 자바스크립트의 모든 객체는 Prototype을 가짐

  • 빈 객체임에도 위의 메서드들이 사용 가능한 것은 프로토타입 때문

프로토 타입 속을 살펴보면,toString메서드와 valueOf 메서드가 속해있다는 것을 확인할 수 있다.

II. Object - 모든 것의 조상
Object는 자바스크립트에서 모든 객체의 조상이자 기본 객체이다. 모든 객체는 Object의 인스턴스이고, 이 말은 모든 객체는 Object가 제공하는 메서드와 속성을 상속받는다는 것을 의미한다.

자바스크립트에서 객체를 생성할 때 기본적으로 객체 리터럴을 사용하거나 생성자 함수를 사용한다. 예를 들어, 객체 리터럴을 사용하여 객체를 생성하면 내부적으로는 Object 생성자 함수가 호출되어 객체가 생성된다.

  • obj 객체는 객체 리터럴을 사용하여 생성되었지만, 이 객체는 Object의 인스턴스임을 확인할 수 있다.

💡 프로토타입 체인

  • 특정 객체에 호출된 프로퍼티가 없다면 프로토타입을 거슬러 올라감
  • 예: Array에는 valueOf가 없지만 그 프로토타입인 Object에는 있으므로 호출 가능

프로토타입 체인의 핵심 개념은 모든 객체가 프로토타입이라는 다른 객체에 연결되어 있으며, 이를 통해 상위 객체의 속성과 메서드를 하위 객체에서 상속할 수 있다는 것이다. 객체에서 속성이나 메서드를 찾을 때 해당 객체의 프로토타입 체인을 따라 올라가며 검색하게 된다.

  • const child = Object.create(parent);parent 객체를 프로토타입으로 가지는 새로운 객체인 child를 생성한다. 이렇게 하면 child 객체는 parent 객체의 속성과 메서드를 상속받는다. 이것이 프로토타입 기반 상속의 한 형태이다.

  • 위 코드에서 Person 함수는 생성자 함수로서 객체를 생성하는 역할을 한다. Person.prototype에 sayName 메서드를 추가하여 모든 Person 객체가 이 메서드를 상속하도록 한다.
  • 이렇게 하면 person1 객체에서 sayName 메서드를 호출할 때 자신의 프로토타입 체인을 따라가면서 sayName 메서드를 찾을 수 있다. 따라서 person1.sayName()을 호출하면 'My name is 이서연'이 출력된다.

II. 코드로 프로토타입에 접근하기

  1. proto 접근자 사용 - Object.prototype의 프로퍼티
    ⚠️ Deprecated - 사라질 기능, 사용 권장되지 않는다.

💡같은 종류는 프로토타입 공유 확인
안의 내용은 달라도, 같은 종류의 타입을 프로토타입으로 비교할 때, true가 출력되는 것을 확인할 수 있다.

2 . Object.getPrototypeOf

  • 수정할 때는 Object.setPrototypeOf 사용
  • proto 대신 이 기능을 사용할 것

3 . ⭐ 생성자 함수에서는 prototype으로 프로토타입 접근 가능
--> 즉 function으로 선언된 함수들

  • 생성자 함수에서는 Person.prototype과 같이 .prototype으로 접근 가능하다.

IV. 인스턴스 vs 프로토타입 프로퍼티

  • PyoChicken이라는 생성자 함수를 정의하고 있다. 이 생성자 함수는 name과 no라는 두 개의 매개변수를 받아서 객체를 생성한다.

  • 객체가 생성될 때마다 name과 no 속성이 할당되며, introduce 메서드를 갖는다. introduce 메서드는 객체의 속성을 활용하여 해당 치킨집의 소개문을 반환한다.

  • 그런 다음, 프로토타입을 통해 새로운 기능을 추가한다. PyoChicken.prototype.introEng 메서드는 영어로 소개하는 메서드를 추가한다. 이 메서드는 해당 치킨집의 이름을 사용하여 영어로 소개문을 반환한다.

  • 따라서 chain1 객체와 새로운 PyoChicken 인스턴스를 생성하여 introEng 메서드를 호출하면, 해당 치킨집의 영어로 된 소개문을 출력한다.

  • console.log(chain1)을 출력해보니, PyoChicken 자체에는 생성자 함수로 정의된 name, no, introduce를 정의되어 있고, prototype에는 introEng가 추가되어 있는 것을 확인할 수 있다.

💡 따라서 메모리 사용을 최소화하려면 아래와 같이 작성

PyoChicken이라는 생성자 함수를 정의하고, 이 생성자 함수는 name과 no라는 두 개의 매개변수를 받아서 객체를 생성한다.
그런 다음, 공통된 요소들은 프로토타입 프로퍼티로 --> PyoChicken.prototype 객체에 titleEng, introduce, introEng와 같은 속성과 메서드를 추가한다.
PyoChicken 생성자 함수를 사용하여 객체를 생성하고, introEng 메서드를 호출하여 해당 치킨집의 소개를 출력한다.

💡 프로토타입 레벨의 함수를 인스턴스 레벨에서 덮어쓰기 가능
이렇게 프로토타입에 정의한 introduce 함수를 덮어쓸 수 있음을 확인할 수 있다.

⭐ 클래스에도 적용 가능
클래스를 정의하고 클래스 내에 메서드를 추가하면, 이 메서드들은 클래스의 프로토타입에 할당된다.
--> 이것은 클래스의 모든 인스턴스가 이러한 메서드를 공유할 수 있도록 한다.
이렇게 prototype으로 메서드를 추가할 수 있다.
기본적으로는 이런식으로 작성하면 된다!
Dog클래스 안에 적용한 bark()메서드가 프로토타입 속에 속해져 있는 것 또한 확인할 수 있다.


프로토타입과 상속

실무에서는 함수보다는 class를 주로 사용하기 떄문에 자주 사용할 일은 없지만, class도 프로토타입으로 구성되어 있기 때문에 , 어떻게 진행되는지 알아두면 좋을 것이다.

이 코드를 살펴보면, 중복되는 것이 상당히 많아보인다.
여기서, Eagle이 Bird로부터 상속받도록 만들려면 어떻게 해야 할까?

I. 프로토타입으로 상속하기
⭐ Object.create 메서드 : 주어진 것을 프로토타입으로 갖는 객체를 생성

  • Bird와 Eagle이라는 생성자 함수를 사용하여 새와 독수리 객체를 만들고, 여기서 Eagle은 Bird를 상속받는다.
  • Eagle.prototype = Object.create(Bird.prototype);는 Eagle 객체가 Bird 객체를 상속받게 한다. 이렇게 함으로써 Eagle 객체는 Bird 객체의 속성과 메서드를 상속받게 된다.

다만 Eagle.prototype = Bird.prototype;와 다르다!!
Eagle.prototype = Bird.prototype;를 사용하면 Eagle과 Bird가 같은 프로토타입을 공유하게 된다. Eagle.prototype의 변경이 Bird.prototype에도 영향을 미치게 되므로, 하위 객체인 Eagle과 상위 객체인 Bird의 프로토타입이 서로 연결되어 버그가 발생할 수 있다.

  • Eagle의 프로토타입을 살펴보면, 프로토타입의 이름은 Bird로 Bird를 상속 받으며, Eagle prototype에 정의한 hunt 메서드와, Bird에서 상속받은 fly메서드가 잘 들어가 있는 것을 확인할 수 있다.
  • 상속을 먼저 하고 자체 프로토타입 프로퍼티 입력이 이루어져야 한다!

또한 상속관계를 살펴보면 eagle은 bird를 상속 받고 있다 --> true가 출력되는 것을 확인할 수 있다!

II. 부모의 생성자 활용하기

  • 생성자에서 중복되는 부분 위임
  • class에서는 constructor에서 super 사용

  • Bird.call(this, name, sound);는 Bird 객체의 생성자 함수를 호출하여 현재 Eagle 객체의 this 컨텍스트에 name과 sound를 설정한다. 이를 통해 Eagle 객체의 name과 sound 속성을 설정할 수 있다.

III. 클래스로 구현
⭐ 클래스 역시 프로토타입을 기반으로 구현됨

클래스와 프로토타입

  • 클래스의 메서드는 프로토타입으로 들어가게 됨
  • extends - 프로토타입 상속도를 만든다.

  • Eagle 클래스는 Bird 클래스를 상속받고 있다. super(name, sound);를 통해 Bird 클래스의 생성자를 호출하여 name과 sound를 설정하고, this.prey = prey;를 통해 Eagle 클래스만의 속성인 prey를 설정한다.

  • 이렇게 함으로써 Eagle 객체는 Bird 객체의 fly 메서드를 상속받고, Eagle 클래스만의 hunt 메서드를 갖게 된다. 이것은 클래스와 상속을 사용하여 코드를 보다 간결하고 명확하게 만들어준다.
    Eagle의 프로토타입을 살펴보면, Bird가 상속된 것을 확인할 수 있다.

IV. Mixin - Object.assign으로 조립하기
Object.assign() 메서드는 하나 이상의 소스 객체로부터 대상 객체로 속성을 복사한다. 즉, 객체에 하나 이상의 속성을 추가하거나 갱신할 때 사용된다,
다양한 속성을 정의한 객체들이 있다.
이후, 세가지 동물들의 클래스를 만들었다.

이후, 동물들의 특성에 맞게 객체들을 추가시켜 보겠다.

Object.assign (Owl.prototype, flyer, hunter);
Object.assign (FlyingFish.prototype, flyer, swimmer);
Object.assign (PolarBear.prototype, runner, swimmer, hunter);

이 코드의 의미는 Owl.prototype에 flyer 객체와 hunter 객체의 속성을 복사할게~ 하는 의미이다.
이후, 각각의 프로토타입을 살펴보면, 추가한 속성들이 모두 들어가 있는 것을 확인할 수 있다.

profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글