11월 29일 객체지향 학습 일지 <프로토타입>

객체지향 프로그래밍이란

실세계에 존재하고 인지하고 있는 객체를 소프트웨어 세계에서 표현하기 위해 객체의 핵심적인 개념 또는 기능만을 추출하는 추상화를 통해 모델링하려는 프로그래밍 패러다임

클래스 기반 vs 프로토타입 기반

객체지향 프로그래밍 언어도 클래스 기반 프로그래밍과 프로토타입 기반의 프로그래밍으로 나눠집니다. 자바스크립트는 프로토타입 기반의 객체지향 프로그래밍을 지원합니다.

클래스 기반 언어

클래스 기반 언어는 클래스로 객체의 자료구조와 기능을 정의하고 생성자를 통해 인스턴스를 생성합니다.

클래스는 같은 종류의 집단에 속하는 속성와 행위를 정의합니다. 이는 OOP의 기본적인 사용자 정의 데이터타입이라고 할 수 있습니다.

객체지향에서는
하지만 결국 클래스는 new 연산자를 통한 인스턴스화 과정이 필요합니다.

모든 인스턴스는 오직 클래스에서 정의된 범위 내에서만 작동하며 런타임에 그 구조를 변경할 수 없습니다.

프로토타입 기반 언어

자바스크립트는 멀티-패러다임 언어로 함수형, 명령형, 객체지향 (프로토타입기반) 언어 입니다.

자바스크립트에서는 원시타입을 제외한 모든 값이 객체입니다. 객체를 생성하기 위해서는 아래와 같은 방법을 사용합니다.

1. 생성자

object() 생성자함수

생성자 함수

객체 리터럴

ES6 부터는 클래스가 도입되었지만 새로운 객체지향 모델을 제공하는 것은 아니며 class도 사실 함수이고 기존 프로토타입 기반 패턴의 문법 설탕입니다.

생성자 함수를 이용한 객체 생성

function Person(name){
	this.name = name;
  
  this.setName = (name) => {
  	this.name = name;
  }
  
  this.getName = () => {
  	return this.name;
  }
}

const developer = new Person('jiwon');
const killer = new Person('jiwon2');

console.log(developer.getName());

생성자 함수내에 프로퍼티와 메서드를 정의하고 new 연산자로 인스턴스를 생성합니다.

이런 방식으로 구현을 하면 인스턴스가 늘어날 수록 같은 메소드를 불필요하게 모두 각각 가지고 있어야하는 메모리낭비로 이어질 수 있습니다.

이와 같은 문제를 해결하기 위해서는 프로토타입에 대해서 이해하고 있어야합니다.

프로토타입이란?

자바스크립트의 모든 객체는 프로토타입이라는 객체를 가지고 있습니다. 모든 객체는 그들의 프로토타입으로부터 property와 method를 상속받습니다. 이 때 상속되는 정보를 제공하는 객체 즉 부모객체를 프로토타입 객체 또는 프로토타입이라고 합니다.

자바스크립트의 모든 객체는 [[Prototype]] 이라는 internal slot을 가집니다.

internal slot은 객체와 관련된 내부 상태와 내부 동작을 정의한 것입니다.

[[Prototype]] 의 값은 null 또는 객체이고, 상속 구현에 사용됩니다.

[[Prototype]]의 값은 프로토타입 객체이고 __proto__ 를 통해 접근할 수 있습니다.

var jiwon = {
    name : 'Park jiwon',
    age : 26
}
console.log(jiwon.hasOwnProperty('name'));
console.dir(jiwon);

jiwon이라는 객체는 __proto__ 프로퍼티로 자신의 부모객체인 Object.prototype을 가리키고 있습니다.

[[Prototype]](__proto__) , prototype 속성 차이

함수도 객체이기 때문에 [[Prototype]] 인터널 슬롯을 가집니다. 그런데 함수객체는 일반객체와 다르게 prototype 속성도 소유하게 됩니다.


[prototype 속성 유무]

즉 [[Prototype]] 은 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯이고, 객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체(Prototype object)를 가리키며 함수의 경우에는 Function.prototype을 가리킵니다.
Person.__proto__ === Function.prototype

그리고 prototype 속성은 함수객체만 가진 프로퍼티이고 함수객체가 생성자로 사용될 때 이 함수를 통해 생설될 객체의 부모역할을 하는 프로토타입 객체를 가리킵니다.

이렇게 해서는 이해가 안갑니다.

function Person(){};


Person이라는 함수가 정의되면 Person 함수 prototype속성은 프로토타입 객체를 참조하고, 프로토타입 객체의 멤버인 constructor 속성은 Person함수를 참조하는 구조가 됩니다. 그리고 이 두개의 객체는 서로 연관되어있고 서로를 알아야합니다.

function Person(){}
var jiwon = new Person();
var tom = new Person();


자바스크립트에서는 원시타입을 제외하고는 모두 객체입니다. 사용자가 정의한 함수도 객체이고,new 키워드를 사용하여 생성된 것도 객체입니다. 객체 안에는 __proto__ 속성이 있습니다.
이 속성은 객체가 만들어지기 위해 사용된 원형인 프로토타입 객체를 숨은 링크로 참조합니다.

주의 해야할 것이 prototype 속성과, [[Prototype]]은 결국 프로토타입 객체를 가리키지만 관점의 차이가 있습니다.

정리하자면
[[Prototype]]

  • 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯
  • 객체의 입장에서 자신의 부모역할을 하는 프로토타입 객체를 가리키며 함수 객체의 경우 Function.prototype을 가리킴

prototype 속성

  • 함수 객체만 가지고 있음.
  • 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 프로토타입 객체를 가리킴

constructor 프로퍼티


프로토타입 객체는 constructor 프로퍼티를 갖고 이 프로퍼티는 객체의 입장에서 자신을 생성한 객체를 가리킵니다.
Person() 생성자 함수에 의해 생성된 jiwon이라는 객체가 있습니다. 이때 jiwon이라는 객체의 입장에서 자신을 생성한 객체는 Person() 생성자 함수고, jiwon 객체의 프로토타입 객체는 Person.prototype 입니다. 즉 Person.prototype.constructor는 Person() 을 가리킵니다.

Prototype Chain

자바스크립트는 특정 객체의 프로퍼티나 메소드에 접근하려고 할 때 해당 객체에 접근하고자하는 프로퍼티나 메소드가 없다면 [[Prototype]] 이 가리키는 링크를 따라 프로토타입 객체의 프로퍼티나 메소드를 차례로 검색하고 이를 프로토타입 체인이라 합니다.

function Person(){};
const jiwon = new Person();
const tom = new Person();
Person.prototype.bark = () => "멍멍";

console.log(jiwon.bark())
console.log(tom.bark())


jiwon과 tom에는 bark()라는 메서드가 없습니다. 따라서 [[Prototype]] 이 가리키는 링크를 따라 프로토타입 객체의 메서드를 검색해서 찾은 것 입니다.

마지막으로


이제 Person 생성자 함수의prototype 속성이 가리키는 prototype object로 이동시킨 getName, setName 메소드는 프로토타입 체인에 의해 모든 인스턴스가 참조할 수 있습니다.
프로토타입 객체는 상속할 것들이 저장되는 장소라고 할 수 있습니다.

출처

좋은 웹페이지 즐겨찾기