본문 바로가기
Programming Language/JavaScript

8. 프로토 타입(Proto type)

by Ray 2021. 1. 24.

JavaScript는 프로토타입 기반 객체지향 프로그래밍 언어이다.

프로토타입 기반 객체지향 언어에서는 클래스 없이 객체 생성 가능

 

JavaScript의 모든 객체는 자신의 부모 객체와 연결되어 있다.

⇒ 마치 상속처럼 부모 객체의 프로퍼티와 메소드를 사용할 수 있다.

⇒ 이러한 부모 객체를 '프로토 타입 객체'라고 한다.

 

프로토 타입 객체는 생성자 함수에 의해 생성된 각각의 객체에 공유 프로퍼티를 제공하기 위해 사용

  • JavaScript의 모든 객체는 [[Prototype]]라는 인터널 슬롯을 가진다.
  • [[Prototype]]의 값은 null 또는 객체(부모 객체)이며, 상속을 위해 사용된다.
  • [[Prototype]] 객체의 프로퍼티는 get 접근을 위해 상속되어 자식 객체의 프로퍼티처럼 사용
  • set 접근은 허용하지 않는다.
  • [[Prototype]]의 값은 프로토 타입이며, _ proto _ accessor property로 접근 가능
  • 프로토타입은 객체 생성시 결정되며, 동적으로 변경할 수 있다.

 

[[Prototype]] vs prototype 프로퍼티

모든 객체는 [[Prototype]] 인터널 슬롯을 갖는다.

함수도 객체이기에 [[Prototype]] 인터널 슬롯을 갖으나, 일반 객체와는 다르게 prototype 프로퍼티도 갖는다.

 

[[Prototype]]

  • 함수를 포함한 모든 객체가 갖고있는 인터널 슬롯
  • 객체의 입장에서 자신의 부모객체를 가리키며, 함수 객체의 경우 Function.prototype를 가리킴

prototype 프로퍼티

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

 

constructor 프로퍼티

  • 프로토 타입 객체는 constructor 프로퍼티를 갖으며, 이는 객체의 입장에서 자신을 생성한 객체를 가리킨다

ex)

function Person(name) {

this.name = name;

}

 

var foo = new Person('Lee');

 

// Person() 생성자 함수에 의해 생성된 객체를 생성한 객체는 Person() 생성자 함수이다. console.log(Person.prototype.constructor === Person);

 

// foo 객체를 생성한 객체는 Person() 생성자 함수이다.

console.log(foo.constructor === Person);

 

// Person() 생성자 함수를 생성한 객체는 Function() 생성자 함수이다.

console.log(Person.constructor === Function);

 

Prototype chain

: JavaScript에서 해당객체에 찾고 있는 프로터티나 메소드가 없다면, [[Prototype]]이 가리키는 부모 객체의 프로퍼티나 메소드를 차례대로 검색하는 것

 

 

객체 리터럴로 생성된 객체의 prototype chain

  • 객체 리터럴은 결국 Object() 생성자 함수의 객체 생성을 단순화 한것

⇒ 객체 리터럴로 객체를 생성한 경우, 프로토타입 객체는 Object.prototype이다.

ex)

var person = {

   name: 'Lee',

   gender: 'male',

   sayHello: function(){

      console.log('Hi! my name is ' + this.name);

      }

    };

 

console.dir(person);

 

console.log(person.__proto__=== Object.prototype); // ① true

console.log(Object.prototype.constructor === Object); // ② true

console.log(Object.__proto__=== Function.prototype); // ③ true

console.log(Function.prototype.__proto__=== Object.prototype); // ④ true

 

 

 

 

 

생성자 함수로 생성된 객체의 prototype chain

  • 함수를 정의하는 3가지 방법 모두 결국 Function() 생성자 함수를 통해 함수 객체를 생성

⇒ 모든 함수 객체의 prototype 객체는 Function.prototype.

⇒ 생성자 함수도 함수 객체이므로 생성자 함수의 portotype 객체 역시 Function.prototype

▶ 객체 리터럴방식이나 생성자 함수 방식이나 결국은 모든 객체의 부모 객체인 Object.prototype에서 prototype chain이 끝나게 됨.

 

객체 생성 방식에 따른 prototype 객체

객체 생성 방식 엔진의 객체 생성 인스턴스트 prototype 객체
객체 리터럴 Object() 생성자 함수 Object.prototype
Object() 생성자 함수 Object() 생성자 함수 Object.prototype
생성자 함수 생성자 함수 생성자 함수이름.Function.prototype

 

원시 타입(Primitive data type)의 확장

  • 원시 타입은 객체가 아니므로 프로퍼티나 메소드를 가질수 없다.
  • 객체의 프로토타입 객체 Object.prototype에 메소드를 추가하면 원시 타입, 객체 모두 메소드를 사용할 수 있다.
  • Javascript는 표준 내장 객체의 프로토타입 객체에 개발자가 정의한 메소드의 추가를 허용한다.

ex)

var str = 'test';

 

String.prototype.myMethod = function() {

  return 'myMethod';

 }

 

console.log(str.myMethod()); // myMethod

console.dir(String.prototype); // [String: ''] { myMethod: [Function] }

 

console.log(str.__proto__=== String.prototype); // ① true

console.log(String.prototype.__proto__=== Object.prototype); // ② true

console.log(String.prototype.constructor === String); // ③ true

console.log(String.__proto__=== Function.prototype); // ④ true

console.log(Function.prototype.__proto__=== Object.prototype); // ⑤ true

프로토타입 객체의 변경

  • 프로토 타입은 객체가 생성될 때 결정되며, 결정된 프로토 타입객체를 임의로 변경할 수 있다.
  • 부모 객체를 동적으로 변경할 수 있다는 것이며, 이를 이용해 상속을 구현할 수 있다.

프로토타입 객체를 변경하면

  • 변경 이전에 생성된 객체 : 기존 프로토 타입 객체를 [[Prototype]]에 바인딩
  • 변경 이후에 생성된 객체 : 변경된 프로토 타입 객체를 [[Prototype]]에 바인딩

ex)

function Person(name) {

this.name = name;

}

var foo = new Person('Lee');

 

// 프로토타입 객체의 변경

Person.prototype = { gender: 'male' };

 

var bar = new Person('Kim');

 

console.log(foo.name); // 'Lee'

console.log(bar.name); // 'Kim'

console.log(foo.gender); // undefined

console.log(bar.gender); // 'male'

console.log(foo.constructor); // ① Person(name)

console.log(bar.constructor); // ② Object()

 

② : Person() 생성자 함수의 Prototype 프로퍼티가 가리키는 프로토타입 객체를 일반 객체로 변경하면서 Person.prototype.constructor 프로퍼티도 삭제

⇒ 프로토타입 체인에 의해 bar.constructor의 값은 프로토타입 체이닝에 의해 Object.prototype.constructor 즉 Object() 생성자 함수가 된다.

 

프로토타입 체인 동작 조건

  • 객체의 프로퍼티를 참조할 때, 해당 객체에 프로퍼티가 없는 경우 동작

  • 객체의 프로퍼티에 값을 할당하는 경우, 프로토타입 체인이 동작하지 않는다.

    ⇒ 객체에 해당 프로퍼티가 있는 경우, 값을 재할당하고

    해당 프로퍼티가 없는 경우는 해당 객체에 프로퍼티를 동적으로 추가하기 때문

    ex)

    function Person(name) {

      this.name = name;

     }

     

     

     

     

    Person.prototype.gender = 'male'; // ①

     

     

    var foo = new Person('Lee'); var bar = new Person('Kim');

    console.log(foo.gender); // ① 'male'

    console.log(bar.gender); // ① 'male'

     

     

    // 1. foo 객체에 gender 프로퍼티가 없으면 foo 객체에 프로퍼티 동적 추가

    // 2. foo 객체에 gender 프로퍼티가 있으면 해당 프로퍼티에 값 할당

    foo.gender = 'female'; // ②

    console.log(foo.gender); // ② 'female'

    console.log(bar.gender); // ① 'male'

'Programming Language > JavaScript' 카테고리의 다른 글

7. 스코프  (0) 2021.01.24
6. 객체  (0) 2021.01.24
5. 함수  (0) 2021.01.24
4. 제어문  (0) 2021.01.24
3. 연산자  (0) 2021.01.24