JavaScript 객체지향 프로그래밍 프로토타입

    2018-04-23 16:57:17 작성

    프로토타입

    모든 함수prototype 프로퍼티를 갖습니다.
    이것은 prototype Object를 가리키며
    Prototype Object는 함수를 원형으로 만들어질 다른 객체가 참조할 Object가 됩니다.
    모든 객체는 constructor 프로퍼티를 갖는데 Prototype Object의 constructor는 객체를 생성한 생성자 함수를 가리킵니다.

    다른 객체가 함수를 원형으로 만들어질때 Prototype Object를 참조하는 Prototype Link를 갖게 됩니다.
    이 Link를 ECMA-262 5판에서는 [[prototype]]이라 부릅니다.

    • 프로토타입 패턴

      다음은 위의 예제의 객체 사이의 관계와 순서를 살펴 봅니다.

      객체들 사이의 관계
      1. Person 함수가 생성됩니다.
      2. Person 함수의 Prototype Object가 생성됩니다.
      3. Person 함수의 prototype 속성이 Prototype Object를 가리킵니다.
      4. Prototype Object의 constructor가 Person 함수를 가리킵니다.
      5. Person.prototype 포인터로 참조하여 Prototype Object에 속성 및 메서드를 정의합니다.
      6. person1 객체를 Person의 Prototype Object로 부터 생성합니다.
      7. person1 의 Prototype Link [[prototype]] 이 Person의 Prototype Object를 가리킵니다
      8. person2 객체를 Person의 Prototype Object로 부터 생성합니다.
      9. person2 의 Prototype Link [[prototype]] 이 Person의 Prototype Object를 가리킵니다

      위에서 보듯이 Prototype Object 이 객체가 자바스크립트에서 이야기 하는 Prototype입니다.
      [[prototype]]에 접근할 수 있는 표준이 없기에 그림에서 보듯이,
      prototype 객체에 접근할 수 있는 유일한 방법은 생성자 함수의 prototype 프로퍼티 뿐입니다.

      [[prototype]]을 크롬 사파리 파이어폭스는 __proto__ 라는 프로퍼티를 지원하여 접근할 수 있습니다.

    • 객체 사이의 [[prototype]]연결 확인 방법

      다음 두가지 방법으로 확인 가능합니다. 사용법은 간단하니 예제를 보세요

      • prototype.isPrototypeOf()
      • Object.getPrototypeOf()
    • 프로토타입 동작방식의 이해

      객체 인스턴스에서 프로토타입에 있는 값을 읽을 수 있지만 수정은 불가능합니다.
      객체 인스턴스에 같은 이름의 속성을 추가하면 해당 속성은 인스턴스에 추가 되며 프로토타입까지 올라가지 않습니다.

    • 인스턴스에 프로퍼티 존재 확인 방법

      다음 2가지 방법이 있습니다.

      hasOwnProperty() 해당 프로퍼티가 인스턴스에 존재하면 true를 반환
      in 연산자 해당 프로퍼티를 접근할 수 있으면 true를 반환

      hasOwnProperty와 in 연산자를 조합하면 해당 프로퍼티가 프로토타입에 존재 하는지 알 수 있습니다.
      다음 예제는 hasPrototypeProperty(instanceObj, propertyName) 함수를 만들어 확인할 수 있게 합니다.

    • 프로토타입과 for-in

      for - in 루프를 사용할 때에는 객체에서 접근 가능한 프로퍼티([[Enumerable]]이 true)를 모두 반환 합니다.
      여기에는 인스턴스 프로퍼티와 프로토타입 프로퍼티 모두 포함됩니다.

    • 인스턴스 프로퍼티 목록

      인스턴스프로퍼티 목록을 보려면 다음 2가지 방법이 있습니다.

      Object.keys(obj) 매개변수로 전달받은 객체의 인스턴스에서 정의된 접근 가능한 프로퍼티 이름을 배열로 반환
      Object.getOwnPropertyNames(obj) 매개변수로 전달받은 객체의 인스턴스에서 정의된 모든 프로퍼티 이름을 배열로 반환
    • 프로토타입 대체 문법

      이전까지 Person.prototype을 각 속성마다 기입해야 했습니다.
      prototype도 객체 이기 때문에 객체 리터럴 표기법으로 기존의 prototype 객체를 덮어쓸 수 있습니다.
      이때 중요한것은 ptototype Object의 constructor 속성을 생성자 함수와 연결 하고, [[Enumerable]] 속성을 false로 지정해야 합니다
      사용자가 만든 프로퍼티는 기본적으로 [[Enumerable]] 속성이 true 입니다. 이렇게 하면 위에서 생성한 Person 함수와 동일합니다.

    • 프로토타입의 동적 속성

      생성자 함수로 생성한 객체는 생성되어 질 때 [[prototype]] 포인터가 결정이 됩니다.
      위의 예제처럼 prototype Object를 객체리터럴로 덮어 쓰게 되면
      덮어쓰기 이전에 생성한 객체는 덮어쓰기 이전의 prototype Object 객체를 가리키고 있으므로 문제가 발생할 수 있습니다.

      프로토타입 할당
      버튼을 클릭하여 객체 연결관계를 살펴 보세요.
      1. Person 객체를 생성합니다.
      2. Person 객체의 ①prototype Object가 생성되고 Person과 연결됩니다.
      3. ①prototype Object로 부터 person1 객체를 생성합니다.
      4. ①prototype Object에 sayHi 메서드를 정의합니다.
      5. Person함수의 prototype 속성이 새로운 리터럴객체를 가리키게 합니다.
        이 객체가 Person의 ②Prototype Object가 됩니다.
      6. ②Prototype Object로 부터 person2 객체를 생성합니다.
    • 자바스크립트 내장 객체 프로토타입

      자바스크립트 내장객체(Object, Array, String 등)도 프로토타입 패턴으로 구현되어있으므로 잘 이해 해야합니다.
      내장객체의 프로토타입을 통행 기본 메서드를 참조 할수 있고 새 메서드도 정의할 수 있습니다.

      표준 JavaScript 객체의 프로토타입을 수정하지 마십시오.

    • 프로토타입 패턴의 문제점

      프로토타입 패턴의 문제점은 초기화 매개변수를 생성자에 전달할 수 없다는 문제점과
      프로토타입에 존재 하는 모든 프로퍼티는 모든 인스턴스에서 공유 된다는 점입니다.

      person1의 [[prototype]] 과 person2의 [[prototype]]은 같은 prototype 객체를 가리키기 때문에
      person1에서 prototype 프로퍼티를 변경하면 그 변환가 person2에도 바로 반영이 됩니다.
      이러한 특성때문에 프로토타입은 생성자 패턴과 조합해서 사용합니다.