[BB-JS] 6. 객체 지향 프로그래밍

본 글은 자바스크립트 공부를 위해 프론트엔드 개발자를 위한 자바스크립트 프로그래밍를 정리한 글입니다.

들어가며

  • 객체지향(Object-oriented: OO) 언어는 일반적으로 클래스를 통해 같은 프로퍼티와 메서드를 가지는 객체를 여러 개 만든다는 특징이 있음
  • ECMAScript는 클래스라는 개념이 없음
  • ECMA-262는 객체를 프로퍼티의 순서 없는 컬렉션이며 각 프로퍼티는 원시 값이나 객체, 함수를 포함한다라고 정의
  • 객체는 순서가 없는 값의 배열
  • 객체는 이름-값 쌍의 그룹이며 각 값은 데이터나 함수가 될 수 있음
  • 모든 객체는 참조 타입을 바탕으로 생성되며, 바탕이 되는 타입은 네이티브 타입일 수도 있고 개발자가 정의한 타입일 수 있음

객체에 대한 이해

  • 객체를 만드는 가장 단순한 방법은 Object의 인스턴스를 만들곡 여기에 프로퍼티와 메서드를 추가하는 방법
  • 최근에는 객체를 만들 때 객체 리터럴 패턴을 더 많이 씀
  • 프로퍼티 타입(ES5)
    • ECMA-262 5판에서는 프로퍼티의 특징을 내부적으로만 유효한 속성에 따라 설명
    • 명세에서는 이들 속성이 자바스크립트 엔진 내부에서 구현하는 것으로 정의했으므로 이들 속성을 자바스크립트에서 직접적으로 접근할 수 있는 방법은 없음
    • [[Enumerable]]처럼 속성 이름을 대괄호로 감싸서 내부 속성임을 나타냄
    • 데이터 프로퍼티
      • 데이터 값에 대한 단 하나의 위치를 포함하여 이 위치에서 값을 읽고 씀
      • [[Configurable]]
        • 해당 프로퍼티가 delete를 통해 샂게하거나, 프로퍼티의 속성을 바꾸거나, 접근자 프로퍼티로 변환할 수 있음을 나타냄
        • 기본 값은 true
      • [[Enumerable]]
        • for-in 루프에서 해당 프로퍼티를 반환함을 나타냄
        • 기본 값은 true
      • [[Writable]]
        • 프로퍼티의 값을 바꿀 수 있음을 나타냄
        • 기본 값은 true
      • [[Value]]
        • 프로퍼티의 실제 데이터 값을 포함
        • 프로퍼티의 값을 읽는 위치이며 새로운 값을 쓰는 위치
        • 기본 값은 undefined
    • 접근자 프로퍼티
      • 데이터 값이 들어 있지 않고 대신 getter 함수와 setter 함수로 구성(둘 모드 꼭 필요한 건 아님)
      • 접근자 프로퍼티를 읽을 떄는 getter 함수가 호출되며 유효한 값을 반환할 책임은 이 함수에 있음
      • 접근자 프로퍼티를 쓸 때는 새로운 값과 함께 setter 함수를 호출하며 이 함수가 데이터를 어떻게 사용할지 결정
      • [[Configurable]]
        • 해당 프로퍼티가 delete를 통해 샂ㄱ제하거나, 프로퍼티의 속성을 바꿀 수 이썩나, 데이터 프로퍼티로 바꿀 수 있음을 나타냄
        • 기본 값은 true
      • [[Enumerable]]
        • for-in 루프에서 해당 프로퍼티를 반환함을 나타냄
        • 기본 값은 true
      • [[Get]]
        • 프로퍼티를 읽을 때 호출할 함수
        • 기본 값은 undefined
      • [[Set]]
        • 프로퍼티를 바꿀 때 호출할 함수
        • 기본 값은 undefined
    • Object.defineProperty()(ES5)
      • 기본 프로퍼티 속성을 변경할 수 있는 메서드
      • 매개변수
        • 프로퍼티를 추가하거나 수정할 객체
        • 프로퍼티 이름
        • 서술자(내부 속성 이름과 1:1로 대응
          • 데이터 프로퍼티
            • configurable(기본 값은 false)
            • enumerable(기본 값은 false)
            • writable(기본 값은 false)
            • value
          • 접근자 프로퍼티
            • configurable(기본 값은 false)
            • enumerable(기본 값은 false)
            • get(기본 값은 undefined)
            • set(기본 값은 undefined)
          • 일부 또는 정부를 바꿔서 대응하는 속성 값을 바꿀 수 있음
      • wratieable, configurablefalse로 설정하면, 새로운 값을 할당 혹은 수정하려 시도하면 스트릭트 모드가 아닐 떄는 무시되고 스트릭트 모드에서는 에러를 발생
      • Object.defineProperty()를 여러 번 호출 할 수 있지만 configurablefalse로 지정하면 제한이 생김
      • gettersetter는 필수 값이 아니며, 지정하지 ㅇ낳으면 읽기 전용 혹은 쓰기 전용이 되며, 이떄 수정하거나 읽으려고하면 스트릭트 모드가 아닐 때는 무시되거나 undefined를 반환하고 스트릭트 모드에서는 에러를 발생
      • 접근자 프로퍼티에 대한 __defineGetter__()__defineSetter__() 비표준 메서드가 있음
      • IE8부터 지원을 하지만 제대로 구현되지 않았으므로 사용하지 않기를 권장
  • 다중 프로퍼티 정의(ES5)
    • 객체에서 프로퍼티 여러개를 동시에 수정해야 할 가능성이 높음
    • Object.defineProperties()(ES5)
      • 여러 프로퍼티를 한 번에 정의
      • 매개변수
        • 프로퍼티를 추가하거나 수정할 객체
        • 프로퍼티 이름이 추가 및 수정할 프로퍼티 이름과 대응하는 객체
  • 프로퍼티 속성 읽기(ES5)
    • Object.getOwnPropertyDescriptor()(ES5)
      • 원하는 프로퍼티의 서술자 프로퍼티를 읽을 수 있음
      • 매개변수
        • 읽어올 프로퍼티가 포함된 객체
        • 서술자를 가저올 프로퍼티 이름
      • 반환 값
        • 프로퍼티 성격에 따라 아래의 프로퍼티들을 포함하는 객체를 반환
        • 데이터 프로퍼티
          • configurable
          • enumerable
          • writable
          • value
        • 접근자 프로퍼티
          • configurable
          • enumerable
          • get
          • set

객체 생성

  • Object 생성자나 객체 리터럴을 이용해 객체를 생성하면 같은 인터페이스를 가진 객체를 여러 개 만들 때는 중복된 코드를 많이 발생하는 것이 단점
  • 팩터리 패턴
    • 팩터리 패턴은 특정 객체를 생성하는 과정을 추상화하는 것
    • ECMAScript에는 클래스를 정의할 수 있는 방법이 없으므로 특정 인터페이스의 객체를 생성하는 과정을 함수로 추상화
    • 다양한 매개변수를 가지고 이 함수를 호출해도 항상 동일한 개수의 프로퍼티와 메서드를 가진 객체를 반환
    • 팩터리 패턴을 쓰면 비슷한 객체를 여러 개 만들 때의 코드 중목 문제는 해결할 수 있지만 생성한 객체가 어떤 타입인지 알 수 없다는 문제는 해결되지 않음
  • 생성자 패턴
    • 생성자는 특정한 타입의 객체를 만드는데 쓰임
    • 커스텀 생성자를 만들어서 원하는 타입의 객체에 필요한 프로퍼티와 메서드를 직접 정의할 수 있음
    • 생성자 함수는 항상 대문자로 시작하고 생성자 아닌 함수는 소문자로 시작하는 표기법이 관례(생성자 또한 단순히 함수일 뿐이므로)
    • contructor 프로퍼티는 객체의 타입을 파악하려는 의도였지만, 타입을 알아내려는 목적으로는 instanceof 연산자가 더 안전한 것으로 간주
    • 생성자를 집접 만들면 인스턴스 타입을 쉽게 식별할 수 있는데 이는 팩터리 패턴에 비해 장점
    • 함수로서의 생성자
      • 생성자 함수와 다른 함수의 차이는 어떻게 호출하는지 여부
      • 생성자는 결국 함수일 뿐이며, 함수가 자동으로 생성자처럼 동작하게 만드는 특별한 문법 같은 것은 없음
      • new 연산자와 함께 호출한 함수는 생성자처럼 동작
      • new 연산자 없이 호출할 경우 프로퍼티와 메서드는 window 객체에 추가
      • call()(또는 apply())를 사용해서 생성자를 다른 객체의 스코프에서 호출할 수 있음
    • 생성자의 문제점
      • 인스턴스마다 메서드를 생성함
      • 함수 이름이 같더라도 인스턴스가 다르면 다른 함수
      • 함수 정의를 생성자 밖으로 내보내면 이런 제한을 우회
      • 이는 함수 중복을 막을 수 있지만, 일부 객체에서만 쓰이는 함수를 전역에 놓음으로서 전역 스코프를 어지럽히는 단점
  • 프로토타입 패턴
    • 모든 함수는 prototype 프로퍼티를 가짐
    • prototype 프로퍼티는 해당 참조 타입의 인스턴스가 가져야 할 프로퍼티와 메서드를 담고 있는 객체
    • prototype 객체는 생성자를 호출할 때 생성되는 객체의 프로토타입
    • 프로토타입의 프로퍼티와 메서드는 객체 인스턴스 전체에서 공유되는 장점이 있음
    • 프로토타입은 어떻게 동작하는가
      • 함수가 생성될 때마다 prototype 프로퍼티 역시 특정 규칙에 따라 생성
      • 기본적으로 모든 프로토타입은 자동으로 constructor 프로퍼티를 갖으며, 이 프로퍼티는 해당 프로토타입이 프로퍼티로 소속된 함수를 가리킴
      • 다음에는 생성자에 따라 각종 프로퍼티와 메서드가 프로토타입에 추가
      • 커스텀 생성자를 정의하면 해당 프로토타입은 단지 constructor 프로퍼티만 가지며 다른 메서드는 Object에서 상속
      • 생성자를 호출해서 인스턴스를 생성할 때마다 해당 인스턴스 내부에는 생성자의 프로토타입을 가리키는 포인터가 생성
      • ES5에서는 이 포인터를 [[Prototpye]]이라 부르며, 일부 브라우저에서 __proto__라는 프로퍼티로 접근 가능한 경우를 제외하면 접근할 수 없음
      • 인스터스(ex, person1, person2)와 직접 연결되는 것은 생성자의 프로토타입(Person.prototype)이지 생성자 자체(Person)가 아님
      • isPrototypeOf()
        • [[Prototype]]은 구현 환경에 따라 접근 불가능할 수도 있지만 객체 사이에 프로토타입 연결이 존재하는지는 이 메서들르 통해 알 수 있음
      • Object.getPrototypeOf()(ES5)
        • [[Prototype]]의 값을 반환
      • constructor 프로퍼티는 프로토타입에만 존재하며 객체 인스턴스에서는 프로토타입을 통해 접근
      • 객체 인스턴스에서 프로토타입에 있는 값을 읽을 수는 있는만 수정은 불가능함
      • 프로토타입 프로퍼티와 같은 이름의 프로퍼티를 인스턴스에 추가하면 해당 프로퍼티는 인스턴스에 추가되며 프로토타입까지 올라가지 않음
      • 객체 인스턴스에 프로퍼티를 추가하면 해당 프로퍼티는 프로토타입에 존재하는 같은 이름의 프로퍼티를 가림
      • 인스턴스에 프로퍼티가 있으면 프로토타입에 존재하는 같은 이름의 프로토퍼티에 대한 접근이 차단
      • delete 연산자는 인스턴스 프로퍼티를 완전히 삭제하여 prototype 프로퍼티에 다시 접근할 수 있게 함
      • hasOwnProperty()
        • 프로퍼티가 인스턴스에 존재하는지 프로토타입에 존재하는지 확인
        • Object로 부터 상속한 것
        • 해당 프로퍼티가 객체 인스턴스에 존재할 때만 true를 반환
      • ES5의 Object.getOwnPropertyDescriptor() 메서드는 인스턴스 프로퍼티에만 동작
    • 프로토타입과 in 연산자
      • in 연산자에는 두가지 쓰임이 있음
        • 그 자체로 사용하는 경우 in 연산자는 주어진 이름의 프로퍼티를 객체에서 접근할 수 있을 때, 해당 프로퍼티가 인스턴스에 존재하든 프로토타입에 존재하든 모두 true를 반환
          • hasOwnProperty()in 연산자를 조합해서 객체 프로퍼티가 프로토타입에 존재하는지 확인할 수 있음
        • for-in루프를 사용할 떄는 객체에서 접근할 수 있고 나열(enumerate) 가능한 프로퍼티를 반환하는데, 인스턴스 프로퍼티와 프로토타입 프로퍼티가 모두 포함
          • 인스턴스 프로퍼티 중 나열 불가능한 prototype 프로퍼티([[Enumerable]]false로 지정된 프로퍼티)를 가리고 있는 프로퍼티 역시 for-in 루프에서 반환되는데, 개발자가 지정한 프로퍼티는 항상 나열 가능하도록 한 규칙 떄문(IE8이하에서는 적용되지 않음)
          • Obejct.keys()(ES5)
            • 객체 인스턴스에서 나열 가능한 프로퍼티의 전체 목록을 얻을 수 있음
            • 매개변수
              • 객체
            • 반환 값
              • 나열 가능한 프로퍼티 이름을 문자열로 포함하는 배열
          • Object.getOwnPropertyNames()(ES5)
            • 나열 가능 여부와 관계없이 인스턴스 프로퍼티 전체 목록을 얻을 수 있음
    • 프로토타입의 대체 문법
      • 모든 프로퍼티와 메서드를 담은 객체 리터럴로 프로토타입을 덮어써서 반복을 줄이고 프로토타입에 기능을 더 가독성있게 캡슐화하는 패턴이 있음
      • contructor 프로퍼티가 생성자를 가리키지 않는다는 단점이 있음
      • 기본 prototype 객체를 완전히 덮어쓰는데, 결과적으로 contructor 프로퍼티는 함수 자체가 아니라 완전히 새로운 객체의 생성자(Object 생성자)와 같음
      • instanceof 연산자는 올바르게 작동함
      • contructor의 값이 중요하다면 적절한 값을 직접 지정할 수 있지만, 리터럴로 지정한다면 [[Enumerable]] 속성이 true로 지정되기 때문에 Object.defineProperty()를 쓰는 편이 좋음(네이티브 costructor 프로퍼티는 기본적으로 나열 불가능한 프로퍼티)
    • 프로토타입의 동적 성질
      • 프로토타입에서 값을 찾는 작업은 적시(런타임) 검색이므로 프로토타입이 바뀌면 그 내용이 즉시 인스턴스에도 반영
      • 프로토타입이 바뀌기 전에 빠져나온 인스턴스도 바뀐 내용을 반영
      • 인스턴스와 프로토타입 사이의 느슨한 연결 덕분
      • 프로퍼티와 메서드를 언제든 프로토타입에 추가할 수 있고 이들을 즉시 객체 인스턴스에서 사용할 수 있긴 하지만, 전체 프로토타입을 덮어썼을 때에는 다르게 동작할 수 있음
      • [[Prototype]] 포인터는 생성자가 호출할 떄 할당되므로 프로토타입을 다른 객체로 바꾸면 생성자와 원래 프로토타입 사이의 연결이 끊어짐
      • 인스턴스는 프로토타입을 가리키는 포인터를 가질 뿐 생성자와 연결된 것이 아님
      • 생성자의 프로토타입을 바꾸면 그 이후에 생성한 인스턴스는 새로운 프로토타입을 참조하지만, 그 이전에 생성한 인스턴스는 바꾸기 전의 프로토타입을 참조
    • 네이티브 객체 프로토타입
      • 네이티브 참조 타입(Object, Array, String 등)의 메서드 역시 생성자의 프로토타입에 정의되어 있음
      • 네이티브 객체의 프로토타입을 통해 기본 메서드를 참조할 수 있고 새 메서드를 정의할 수 있음
      • 네이티브 객체의 프로토타입도 커스텀 객체의 프로토타입과 마찬가지로 수정할 수 있고 메서드도 언제든지 추가할 수 있음
      • 네이티브 객체 프로토타입을 수정할 수 있긴 하지만 배포하는 코드에서는 충돌이 발생할 수 있으므로 피해야함
    • 프로토타입의 문제점
      • 초기화 매개변수를 생성자에 전달할 수 없게 하므로 모든 인스턴스가 기본적으로 같은 프로퍼티값을 갖게 됨
      • 공유라는 성질이 프로토타입의 주요 문제
        • 프로토타입에 존재하는 프로퍼티는 모두 인스턴스에서 공유됨
        • 함수에는 이상적
        • 프로퍼티가 참조 값을 포함할 경우 문제
        • 참조한 프로퍼티를 모든 인스턴스가 공유함
  • 생성자 패턴과 프로토타입 패턴의 조합
    • 커스텀 타입을 정의할 때 가장 널리 쓰이는 방법
    • 생성자 패턴으로 인스턴스 프로퍼티를 정의하고 프로토타입 패턴으로 메서드와 공유 프로퍼티를 정의하는 방법
    • 모든 인스턴스는 자신만의 인스턴스 프로퍼티를 가질 수 있으며 참조 방식을 통해 메서드는 공유하므로 메모리는 절약할 수 있음
    • 생성자에 매개 변수를 전달할 수도 있으므로 두 패턴의 장점만 취한 패턴
    • 생성자/프로토타입 패턴은 ECMAScript에서 커스텀 참조 타입을 정의할 때 가장 널리 사용되는 방법
  • 동적 프로토타입 패턴
    • 생성자와 프로토타입의 구분이 혼한스러울 수 있음
    • 모든 정보를 생성자 내부에 캡슐화하여 혼란을 해결하면서도, 필요한 경우에는 프로토타입을 생성자 내부에서 초기화하여 생성자와 프로토타입을 모두 쓰는 장점을 취하려는 접근법
    • 반드시 필요한 메서드가 있느냐에 따라 프로토타입을 초기화할지 여부를 결정(생성자에서 if문을 통해 프로토타입을 초기화)
    • 동적 프로토타입 패턴을 사용할 때는 객체 리터럴을 통해 프로토타입을 덮어쓸 수 없음
  • 기생 생성자 패턴(parasitic constructor)
    • 다른 패턴이 실패할 떄 폴백으로 사용
    • 일반적인 생성자처럼 보이지만 사실 다른 객체를 생성하고 반환하는 동작을 래퍼 생성자로 감싸는 것
    • new 연산자를 써서 함수를 생성자로 호출하는 점을 제외하면 팩터리 패턴과 완전히 동일
    • 생성자가 값을 반환하지 않을 때는 기본적으로 새 객체 인스턴스를 반환지만, 생성자 마지막에 return문을 추가함으로써 생성자를 호출했을 떄 반환되는 값을 오버라이드할 수 있음
    • 반환된 객체와 생성자, 또는 생성자의 프로토타입 사이에 아무 연결고리가 없음
    • 반환된 객체는 생성자와 아무 상관도 없다는 듯 존재
    • instanceof 연산자로는 이 객체의 타입을 알 수 없음
    • 다른 패턴으로 해결 가능하다면 이 패턴 사용을 지양
  • 방탄 생성자 패턴
    • 공용 프로퍼티가 없고 메서드가 this를 참조하지 않는 객체를 가리켜 방탄(durable) 객체라 함(이 용어는 더글락스 크록포드가 처음 사용)
    • 방탄 객체는 thisnew의 사용을 금지하는 보안 환경, 매시업 애플리케이션 등에서 데이터를 써드파티 애플리케이션으로부터 보호하는데 어울림
    • 방탄 생성자는 기생 생성자 패턴과 비슷한 패턴으로 만드는 생성자인데 두가지 차이점이 있음
      • 생성된 객체의 인스턴스 메서드가 this를 참조하지 않음
      • 생성자를 new 연산자를 통해 호출하는 경우가 없음
    • 방탄 객체 인스턴스 사이의 연결은 존재하지 않으므로 instanceof는 동작하지 않음

상속

  • 객체지향 언어의 상속
    • 메서드 시그너처만을 상속하는 인터페이스 상속
    • 실제 메서드를 상속하는 구현 상속
  • ECMAScript 함수에는 시그너처가 없으므로 인터페이스 상속은 불가능하며, 구현상속만 지원하고 대개 프로토타입 체인을 사용
  • 프로토타입 체인
    • ECMA-262는 프로토타입 체인을 ECMAScript의 우선적 상속 방법으로 설명
    • 프로토타입 체인의 기본 아이디어는 프로토타입 개념을 이용해 두 가지 참조 타입 사이에서 프로퍼티와 메서드를 상속한다는 것
    • 하위 타입의 prototype은 상위 타입의 인스턴스이며 상위 타입의 인스턴스 프로퍼티를 가지고 있음
    • 프로토타입 체인은 프로토타입 검색 메커니즘을 확장
      • 프로퍼티를 읽으려 하면 먼저 인스턴스에서 해당 프로퍼티를 검색
      • 프로토타입 체인에 의해 상속을 구현했다면 프로토타입 체인을 따라 계속 올라가면서 검색
    • 기본 프로토타입
      • 모든 참조 타입은 기본적으로 프로토타입 체인을 통해 Object를 상속
      • 함수의 기본 프로토타입은 Object의 인스턴스이므로 함수의 내부 프로토타입 포인터는 Object.prototype를 카기림
    • 프로토타입과 인스턴스 사이의 관계
      • 프로토타입과 인스턴스의 관계는 instanceof 연산자와 isPropertyOf() 메서드를 사용
      • instanceof 연산자는 인스턴스 생성자가 프로토타입 체인에 존재할 때 true를 반환
      • isPrototypeOf() 메서드는 체인에 존재하는 각 프로토타입에 존재하며, 체인에 존재하는 인스턴스에서 true를 반환
    • 메서드
      • 하위 타입에서 상위 타입의 메서드를 오버라이드하거나 상위 타입에 존재하지 않는 메서드를 정의해야 할 때는 프로토타입이 할당된 다음 필요한 메서드를 프로토타입에 추가해야 됨
      • 객체 리터럴을 써서 프로토타입 메서드를 만들면 체인을 덮어쓰는 결과가 되므로 프로토타입 체인과 함께 사용할 수 없음
    • 프로토타입 체인의 문제
      • 프로토타입 프로퍼티에 들어 있는 참조 값이 모든 인스턴스에 공유
      • 프로토타입으로 상속을 구현하면 프로토타입이 다른 타입의 인스턴스가 되므로 처음에 인스턴스 프로퍼티였던 것들이 프로토타입 프로퍼티로 바뀜    * 하위 타입 인스턴스를 만들 때 상위 타입 생성자 매개변수를 전달할 수 없으며, 객체 인스턴스에 영향을 미치지 않고 상위 타입 생성자에 매개변수를 전달할 방법이 없음
  • 생성자 훔치기(constructor stealing, 위장 객체(object masquerading), 전통적 상속(classical inheritance))
    • 프로토타입과 참조 값에 얽인 상속 문제를 해결하고자 사용한 테크닉
    • 하위 타입 생성자 안에서 상위 타입 생성자를 호출
    • call()(혹은 apply())메서드를 사용해서 상위 타입 생성자를 새로 생성한 하위 타입의 인스턴스 컨텍스트에서 호출
    • 이 방법은 상위 타입 생성자 함수에 들어 있는 객체 초기화 코드를 전체 하위 타입 객체에서 실행하는 효과가 있음
    • 모든 인스턴스가 자신만의 참조 프로퍼티를 갖게 됨
    • 매개변수 전달
      • 생성자 훔치기 패턴은 하위 타입의 생서자 안에서 상위 타입의 생성자에 매개변수를 전달할 수 있는데 이는 생성자 훔치기 패턴이 프로토타입 체인보다 나은 점 중 하나
    • 생성자 훔치기 패턴의 문제
      • 생성자 훔치기 패턴만 사용하면 커스텀 타입에 생성자 패턴을 쓸 때와 같은 문제가 발생
      • 메서드를 생성자 내부에서만 정의해야 하므로 함수 재사용이 불가능
      • 상위 타입의 프로토타입에 정의된 메서드는 하위 타입에서 접근할 수 없는 문제
  • 조합 상속(가상의 전통적 상속(pseudoclassical inheritance))
    • 프로토타입 체인과 생성자 훔치기 패턴을 조합해 두 패턴의 장점만을 취하려는 접근법
    • 프로토타입 체인을 써서 프로토타입에 존재하는 프로퍼티와 메서드를 상속하고 생성자 훔치기 패턴으로 인스턴스 프로퍼티를 상속하는 것
    • 프로토타입에 메서드를 정의해서 함수를 재사용할 수 있고, 각 인스턴스가 고유한 프로퍼티를 가질 수도 있음  * 프로토타입 체인과 생성자 훔치기 패턴의 단점을 모두 해결하여 자바스크립트에서 자주 쓰이는 상속 패턴
    • intanceofisPrototypeOf()에서도 올바른 결과를 반환
  • 프로토타입 상속
    • 더글러스 크록포드가 엄격히 정의된 생성자를 쓰지 않고도 상속을 구현하는 방법을 소개
    • 프로토타입을 써서 새 객체를 생성할 때 반드시 커스텀 타입을 정의할 필요가 없다는 데서 출발
    • 다른 객체의 기반이 될 기반 객체를 만들고 이를 통해 객체의 사본 역할을 할 객체를 만듬
    • 원시 값을 프로퍼티로 가지며, 프로토타입에는 참조 값 프로퍼티가 들어있는 객채를 만듬
    • Object.create()(ES5)
      • 프로토타입 상속의 개념을 공시적으로 수용한 메서드
      • 매개변수
        • 다른 객체의 프로토타입이 될 객체
        • 새 객체에 추가할 프로퍼티를 담은 객체(옵션)
    • 프로토타입 상속으로 만든 객체는 다른 객체와 비슷하게 동작하지만 생성자를 따로 만들 필요는 없다는 점에서 유용
    • 프로토타입 패턴과 마찬가지로 참조 값을 포함하는 프로퍼티들은 모두 그 값을 공유 유의
  • 기생 상속
    • 프로토타입 상속과 밀접히 연관된 인기 있는 패턴으로 크록포드가 만듬
    • 기생 생성자나 팩터리 패턴과 유사
    • 상속을 담당할 함수를 만들고, 어떤 식으로든 이 객체를 확장해서 반환
    • 기생 상속 패턴은 객체를 주로 고려할 때 사용할 패턴이지 커스텀 타입과 생성자에 어울리는 패턴은 아님
    • 기생 상속을 이용해 객체에 함수를 추가하면 생성자 패턴과 비슷한, 함수 재사용과 관련된 비효율 문제가 생김
  • 기생 조합 상속
    • 조합 상속의 상위 타입 생성자가 항상 두 번 호출되는 비효율적인 면을 개선
      • 한 번은 하위 타입의 프로토타입을 생성하기 위해, 다른 한번은 하위 타입 생성자 내부에서 호출
      • 하위 타입의 프로토타입은 상위 타입 객체의 인스턴스 프로퍼티를 모두 상속하는데, 하위 타입 생성자가 실행되는 순간 모두 덮어쓰므로 별 의미가 없음
    • 기생 조합 상속은 생성자 훔치기를 통해 프로퍼티 상속을 구현하지만 메서드 상속에는 프로토타입 체인을 혼용
    • 하위 타입의 프로토타입을 할당하기 위해 상위 타입의 생성자를 호출할 필요는 없으며 필요한 것은 상위 타입의 프로토타입 뿐
    • 기생 상속을 써서 상위 타입의 프로토타입으로 부터 상속한 다음 결과를 하위 타입의 프로토타입에 할당
      • 상위 타입의 프로토타입을 복제
      • contructor프로퍼티를 prototype에 할당해서 프로토타입을 덮어쓸 때 기본 contructor프로퍼티가 사라지는 현상을 대비
      • 하위 타입의 프로토타입에 새로 생성한 객체를 할당
    • 상위 타입 생성자를 단 한번만 호출하므로 하위 타입 프로토타입에 불필요하고 사용하지 않는 프로퍼티를 만들지 않는다는 점에서 효과적
    • 프로토타입 체인이 온전히 유지되므로 instaceofisPrototypeOf() 메서듣도 정삭 작동
    • 참조 타입에서 가장 효율적인 상속 패러다임으로 평가
  • 관련 글 참조

SmileCat

SmileCat
How do you define yourself?

[Openlayers] Render Event 정리

## 이벤트### [Map](http://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html)| event | module | note || :--: | -- | -- || [postcompose](...… Continue reading