클래스와 생성자, 프로토타입

Development Javascript

클래스와 생성자, 프로토타입

클래스의 개요

자바스크립트는 C++, 자바, C#이 제공하는 것과 같은 실제 클래스를 지원하지 않는다. 대신 모조 클래스로 정의할 수 있다.
모조 클래스는 프로토타입 객체나 생성자 함수를 사용하여 구현할 수 있다.

생성자

다음과 같이 new연산자와 함께 사용되도록 설계된 함수를 생성자 함수라고 하거나 간단하게 생성자라고 부른다.

new array = new Array(10);
var today = new Date();

생성자는 새로운 객체를 초기화하고, 객체에 있는 프로퍼티 중에서 사용되기 전에 미리 할당되어야 하는 프로퍼티들의 초기값을 할당한다.

function Rectangle(w, h) {
    this.width = w;
    this.height = h;
}

var rect1 = new Rectangle(2, 4);
var rect2 = new Rectangle(8.5, 11);
  • 생성자의 이름은 첫문자를 대문자로 해서 new Rectangle(1,2)로 사용하는것이 더욱 직관적이다.
  • 생성자 함수에는 일반적으로 반환값이 없다.
  • 생성자 함수는 this키워드가 가리키는 객체를 초기화시킬 뿐 아무런 값도 반환하지 않는다.

프로토타입과 상속

Rectangle 객체로 표현된 사각형의 넓이를 계산하고 싶다면 아래와 같은 형식으로 사용한다.

function computeAreaOfRectangle(r) {
    return r.width * r.height;
}

위와같은 형식은 객체지향적인 방법이 아니라서 아래와 같이 메서드를 사용하는것이 좋다.

var r = new Rectangle(8.5, 11);
r.area = function() {
    return this.width * this.height;
}
var a = r.area();

아래 코드는 함수를 생성자 내부에서 연결시키는 방법이다.

function Rectangle(w, h) {
    this.width = w;
    this.height = h;
    this.area = function()
    {
        return this.width * this.height;
    }
}
var r = new Rectangle(8.5, 11);
var a = r.area();

한 클래스에 속하는 객체들이 공유하게끔 만들어진 메서드에 이르반적인 프로퍼티를 사용하는것은 비효율적이다.
자바스크립트의 모든 객체는 프로토타입이라고 불리는 또 다른 객체를 내부적으로 참조할 수 있다.
객체는 자신의 프로토타입에 있는 프로퍼티들을 상속받는다.
모든 함수에는 prototype이라는 프로퍼티가 있는데 이것은 함수가 정의될때부터 자동적으로 생성되고 초기화 된다.

// 생성자 함수는 각 인스턴스의 프로퍼티가 다른값이 되도록 초기화한다.
function Rectangle(w, h) {
    this.width = w;
    this.height = h;
}

// 프로토타입 객체는 각 인스턴스들이 공유해야하는 프로퍼티나 메서드를 정의한다.
Rectangle.prototype.area = function() { return this.width * this.height; }

// 생성자 객체 초기화 (r이라는 객체로 사용할 수 있다.)
var r = new Rectangle(2,3);

상속받은 프로퍼티의 읽기와 쓰기

  • 한개의 프로토타입 프로퍼티는 여러개의 객체들이 상속받을 수 있기 때문에 자바스크립트에서는 프로퍼티 값을 읽거나 쓸 때 비대칭성을 의무적으로 지키게 하고있다.
  • 객체 o의 프로퍼티인 p를 읽을 때 자바스크립트는 o에 p라는 이름을 가진 프로퍼티가 있는지 검사한다. 만약 없다면 o의 프로토타입 객체에 p라는 프로퍼티가 있는지 검사한다.
  • 프로퍼티의 상속은 프로퍼티를 쓸 때가 아닌 읽을때만 일어난다.
  • 프로토타입의 프로퍼티들은 클래스의 모든 객체가 공유하기 때문에, 모든 객체가 같이 사용하는 프로퍼티들을 정의해놓는 것이 이해하기 쉽다.
  • 기본값을 사용하지 않는 일부 객체들만 그들이 원하는 값이 되도록 재정의 할 수 있다. (기본값을 연산하여 새로운 프로퍼티를 만들 수 있는 유연함을 특성으로 가지고 있다.)

내장형 타입의 확장

  • String이나 Date같은 내장형 클래스에도 프로토타입이 있다.
  • String객체가 사용할 수 있는 새로운 매서드를 한개 정의하는 예
String.prototype.endWith = function(c) {
    return (c == this.charAt(this.length-1));
}
  • 만약 다른 프로그래머가 자신의 코드를 읽거나 관리해야 한다면, 전혀 들어보지도 못한 메서드 때문에 혼란스러울 수도 있다.
  • 자바스크립트의 낮은레벨에 해당하는 프레임워크를 만들어 다른 프로그래머들이 사용하게 하려는 목적이 아니라면 내장형 타입의 프로토타입 객체를 건드리지 않는것이 좋다.
  • Object.prototype에는 어떤 프로토타입도 추가해서는 안된다.
  • Object.prototype에 프로토타입을 추가하면 자바스크립트의 모든 객체를 볼 수 없다.
  • 내장형 네이티브 클래스의 프로토타입을 확장하는 것이 안전하고 유용한 경우가 한가지가 있다.
  • 오래되었거나 호횐이 되지 않는 자바스크립트가 표준 메서드를 포함하고 있지 않으면 새로운 메서드를 추가할 수 있다.
    예를들어 IE4와 5에서는 Function.apply()라는 메서드가 빠져 있는데 직접 만들어줄수도 있다.

자바스크립트의 클래스 시뮬레이션

  • 객체지향 프로그램 언어들은 공통적으로 데이터 타입을 엄격히 검사하며 클래스 기반의 상속을 지원한다.
  • 자바스크립트는 객체를 자주 사용한다는 점과 프로토타입 기반의 상속을 지원한다.
  • 비록 자바스크립트가 클래스 기반의 객체지향 언어가 아니긴 하지만 자바나 C++같은 클래스 기반의 언어가 지원하는 기능을 흉내낼 수 있다.
  • 자바스크립트의 객체는 프로퍼티의 개수에 제한이 없으며, 동적으로 추가할 수 있다.
  • 자바스크립트와 클래스 기반의 객체지향 언어들은 모두 한 클래스에 속하는 여러개의 객체가 있을 수 있다. 이런 객체를 클래스의 인스턴스라고 한다.
  • 자바에서는 클래스의 이름을 만들 때 첫 글자는 대문자로 시작하게 하고, 객체의 이름은 소문자로 짓는것이 일반적인 방법이다. 자바스크립트도 클래스의 이름은 Rectangle과같이 정하고 인스턴스는 rect과같이 이름을 구분해서 정한다.

인스턴스 프로퍼티

  • 한 클래스에 속하는 객체가 열 개 있다면 인스턴스 프로퍼티 사본이 열 개 만들어진다.
  • Rectangle 클래스에서 width프로퍼티는 인스턴스 프로퍼티다. r이 Rectangle 클래스의 인스턴스라면 r의 width는 r.width으로 참조된다.
  • 인스턴스 프로퍼티는 생성자 함수가 생성하고 초기화시키는 프로퍼티라고 할 수 있다.

인스턴스 메서드

  • 인스턴스 메서드는 특정한 객체나 인스턴스가 호출한다. 예를들어 Rectangle 클래스의 area() 메서드는 하나의 인스턴스 메서드다. a = r.area();
  • 인스턴스 메서드는 메서드 호출한 객체나 인스턴스를 참조하기 위해 this키워드를 사용한다.
  • 각 인스턴스 메서드는 클래스의 모든 인스턴스가 공유한다.

인스턴스 메서드와 this

자바스크립트의 메서드에서 프로퍼티를 사용할 때 자신의 객체를 표현하는것은 this를 사용해야한다. return this.width * this.height;

this키워드를 계속 붙이는게 불편하다면 with문장을 사용하면 된다.

Rectangle.prototype.area = function()
{
    with(this)
    {
        return width * height;
    }
}

클래스 프로퍼티

  • 자바에서 클래스 프로퍼티란 클래스의 각 인스턴스가 아닌 클래스 자체과 연관되어 있는 프로퍼티를 말한다.
  • 클래스 프로퍼티는 클래스의 인스턴스가 몇 개나 생성되어있는지 상관없이 한 개만 존재한다.
  • 1*1 사각형을 저장해 두기 위해 Rectangle.UNIT이라는 클래스 프로퍼티를 만들고 싶다면...
Rectangle.UNIT = new Rectangle(1,1);

클래스 메서드

  • 클래스 메서드는 특정 인스턴스를 통해 호출되지 않고, 클래스 자체를 통해 호출된다.
  • Date.parse() 메서드는 클래스 메서드의 한 예이다.
  • 클래스 프로퍼티와 마찬가지로 클래스 메서드도 전역에서 접근할 수 있다.

예제소스