본문으로 바로가기

6. 객체지향 프로그래밍 (1)

category language/JavaScript 2019. 11. 29. 16:47

객체지향 언어로서 클래스 기반의 언어와 프로토타입 기반의 언어를 간단하게나마 구분하는 것이 필요.


  1. 클래스 기반의 언어
  • 클래스로 객체의 기본적인 형태와 기능을 정의하고, 생성자로 인스턴스를 만들어서 사용할 수 있다
  • 클래스에 정의된 메서드로 여러 가지 기능을 수행할 수 있다.
  • Java, C++ 등
  • 모든 인스턴스가 클래스에 정의된 대로 같은 구조이고 보통 런타임에 바꿀 수 없다.

  1. 프로토타입 기반의 언어
  • 객체의 자료구조, 메서드 등을 동적으로 바꿀 수 있다.

—> 정적 타입의 언어와 동적 타입의 언어의 차이와 거의 비슷하게 보임.


정확성, 안정성, 예측성 등의 관점에서 클래스 기반 언어가 프로토타입 기반의 언어보다 좀 더 나은 결과를 보장한다.

프로토타입 기반의 언어는 동적으로 자유롭게 객체의 구조와 동작 방식을 바꿀 수 있다는 장점이 있다.

자바스크립트는 프로토타입 기반의 언어!


6.1 클래스, 생성자, 메서드

자바스크립트는 거의 모든 것이 객체이고, 특히 함수 객체로 많은 것을 구현해낸다. 클래스, 생성자, 메서드도 모두 함수로 구현이 가능하다.


예제 6-1

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

var me = new Person("zzoon");
console.log(me.getName());  // (출력값) zzoon

me.setName("iamhjoo");
console.log(me.getName());  // (출력값) iamhjoo

 

var me = new Person(“zzoon”);

이라는 형태는 기존 객체지향 프로그래밍 언어에서 한 클래스의 인스턴스를 생성하는 코드와 매우 유사하다. 함수 Person이 클래스이자 생성자의 역할을 한다.


클래스 및 생성자의 역할을 하는 함수가 있고, 사용자는 new 키워드로 인스턴스를 생성하여 사용할 수 있다.


하지만 이 예제의 Person 함수의 구현은 바람직하지 못하다.

Person을 생성자로 하여 여러 개의 객체를 생성한다고 가정해보자.


var me = new Person("me");
var you = new Person("you");
var him = new Person("him");

 

이와 같이 객체를 생성하여 사용하면 겉으로는 별 문제 없이 작동하는 것을 볼 수 있다.

하지만 각 객체는 자기 영역에서 공통적으로 사용할 수 있는 setName() 함수와 getName() 함수를 따로 생성하고 있다. 이는 불필요하게 중복되는 영역을 메모리에 올려놓고 사용함을 의미하고 자원 낭비를 가져온다.


따라서 앞의 문제를 해결하려면 다른 방식의 접근이 필요한데, 여기서 활용할 수 있는 자바스크립트의 특성이 함수 객체의 프로토타입이다.


예제 6-2

function Person(arg) {
    this.name = arg;
}

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

Person.prototype.setName = function(value) {
    this.name = value;
}

var me = new Person("me");
var you = new Person("you");
console.log(me.getName());
console.log(you.getName());

 

이 예제에서 생성된 객체들은 각자 따로 함수 객체를 생성할 필요 없이 setName()getName() 함수를 프로토타입 체인으로 접근할 수 있게 된다.


이와 같이 자바스크립트에서 클래스 안의 메서드를 정의할 때는 프로토타입 객체에 정의한 후, new로 생성한 객체에서 접근할 수 있게 하는 것이 좋다.

다음은 더글라스 크락포드가 메서드를 정의하는 방법을 소개하면서 제시한 함수이다.

Function.prototype.method = function(name, func) {
	if (!this.prototype[name])
		this.prototype[name] = func;
	}
}

 

이 함수를 이용한다면 예제 6-2는 다음과 같은 형태가 된다.


예제 6-3

Function.prototype.method = function(name, func) {
    this.prototype[name] = func;
}

function Person(arg) {
    this.name = arg;
}

Person.method("setName", function(value {
    this.name = value;
}));

Person.method("getName", function() {
    return this.name;
});

var me == new Person("me");
var you = new Person("you");
console.log(me.getName());
console.log(you.getName());

 

cf) 더글라스 크락포드는 함수를 생성자로 사용하여 프로그래밍하는 것을 추천하지 않는다. 그 이유는 생성된 함수는 new로 호출될 수 있을 뿐만 아니라, 직접 호출도 가능하기 때문이다. 여기서 문제는 new로 호출될 때와 직접 호출될 때의 this바인딩되는 객체가 달라진다는 것이다. 크락포드는 이러한 문제 때문에, 일단 생성자로 사용되는 함수는 첫 글자를 대문자로 표기할 것을 권고하고 있다.


#책/인사이드자바스크립트