JavaScript/함수

[JavaScript]함수로 클래스 만드는 방법

DevStory 2022. 11. 9.

클래스 기반의 언어와 프로토타입 기반의 언어

ES6부터 JavaScript에서 class 키워드를 사용하여 클래스를 정의할 수 있지만, C++, C#, Java와 같은 클래스 기반의 언어에서 사용하는 클래스와 100% 동일하게 동작하지 않습니다.

 

따라서, JavaScript에서 class 키워드를 사용하여 클래스를 정의하는 문법을 이해하기 전에 클래스 기반의 언어와 프로토타입 기반의 언어에 대해 간단하게 구분할 수 있어야 하고 class 키워드가 도입되기 전에 JavaScript에서 클래스를 어떻게 정의했는지 알아야 할 필요가 있습니다.

 

클래스 기반의 언어는 클래스로 객체의 기본적인 형태와 기능(필드와 메서드)을 정의하고 new 키워드와 생성자로 객체를 생성할 수 있습니다.

 

다음 예제는 클래스 기반의 언어인 C#에서 클래스를 정의하고 객체를 생성하는 방법입니다.

// CSharpClass라는 이름의 클래스 정의
public class CSharpClass
{
  // 필드
  private string name;

  // 생성자
  public CSharpClass(string name)
  {
    this.name = name;
  }

  // get 프로퍼티
  public string getName()
  {
    return this.name;
  }

  // set 프로퍼티
  public void setName(string name)
  {
    this.name = name;
  }

  // 메서드
  public void printValue()
  {
    Console.WriteLine(this.name);
  }
}

class Program
{
  static void Main(string[] args)
  {
    // CSharpClass 클래스의 객체 생성
    CSharpClass cSharp = new CSharpClass("Hi");

    // 객체를 사용하여 클래스에 정의된 printValue() 메서드 호출
    cSharp.printValue();
  }
}

[실행 결과]

Hi

클래스 기반의 언어에서는 클래스 정의 후 애플리케이션을 실행하면, 클래스에 정의된 형태와 기능(필드와 메서드)을 변경할 수 없습니다. 즉, 프로그램 실행 도중 CSharpClass 클래스의 printValue() 메서드의 로직을 변경하거나 새로운 필드를 추가할 수 없습니다.

 

반면에 JavaScript와 같은 프로토타입 기반의 언어는 프로그램 실행 도중 클래스에 정의된 메서드의 로직을 변경할 수 있습니다.(객체에 프로퍼티를 추가하는 것이므로 덮어 씌운다는 의미가 정확하겠네요.)

 

다음 예제는 JavaScript에서 class 키워드를 사용하여 User 클래스 정의 및 User 클래스의 객체를 생성하고 User 클래스에 정의된 show() 메서드의 로직을 변경합니다.

class User {
  show() {
    console.log('show!');
  }
}

var user = new User();

// User 클래스의 show() 메서드가 무의미함...
user.show = function() {
  console.log('Hi');
};

user.show();

[실행 결과]

Hi

클래스 기반의 언어는 프로그램 실행 도중 클래스에 정의된 형태와 기능을 변경할 수 없으므로 프로토타입 기반의 언어보다 정확하게 동작하고 안전하다는 장점이 있지만, 유동적이지 않다는 단점이 존재합니다.

 

반대로 프로토타입 기반의 언어는 프로그램 실행 도중 클래스에 정의된 메서드의 로직을 변경할 수 있으므로 클래스 기반의 언어보다 유동적이지만, 실행 결과를 예측할 수 없으므로 불안전하다는 단점이 존재합니다.

 

따라서, JavaScript에서 class 키워드를 사용하여 클래스를 정의해도 클래스 기반의 언어에서 사용하는 클래스와 100% 동일하게 동작하지 않다는 것입니다.

 

다음은 JavaScript에서 함수를 사용하여 클래스를 정의하고 객체를 생성하는 방법을 설명합니다. 프로토타입과 new 연산자에 대한 이해가 부족하다면, 내용이 어려울 수 있습니다.


함수로 클래스 만드는 방법

JavaScript 함수를 사용하여 클래스를 정의하는 예제입니다.

// 함수로 클래스 정의(클래스이자 생성자 역할을 동시에 함)
function User(name) {
  // 필드 정의 및 초기화
  this.name = name;
  
  // get 프로퍼티
  this.getName = function() {
    return this.name;
  }

  // set 프로퍼티
  this.setName = function(name) {
    this.name = name;
  }
  
  // 메서드
  this.show = function() {
    console.log(this.name);
  }
}

var user = new User('John');
user.show();

[실행 결과]

John

클래스 기반의 언어와 유사하게 User()라는 함수는 클래스이자 생성자 역할을 수행하고 User() 함수 내부에 name이라는 필드와 메서드를 정의하였습니다. User 클래스의 객체는 new 키워드를 사용하여 생성합니다.

 

이 예제는 정상적으로 실행되지만 getName(), setName(), show() 메서드를 공통적으로 사용하는 것이 아니라 객체마다 사용하고 있으므로 메모리를 불필요하게 사용하며, 원하지 않는 동작을 유발합니다.

var user1 = new User('John');
var user2 = new User('Bob');
var user3 = new User('Jim');

세 개의 객체를 생성했을 때, 그림으로 표현하면 다음과 같습니다.


클래스의 메서드를 정의하는 방법

위에서 보여준 문제를 해결하려면 프로토타입을 활용합니다.

 

다음 예제는 User 함수 객체의 prototype 프로퍼티에 메서드를 정의하였습니다.

function User(name) {
  this.name = name;
}

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

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

User.prototype.show = function() {
  console.log(this.name);
};

var user1 = new User('John');
var user2 = new User('Bob');
var user3 = new User('Jim');

user1.show();
user2.show();
user3.show();

[실행 결과]

John
Bob
Jim

User 클래스의 객체를 생성하면 메서드를 객체마다 가지는 것이 아니라 프로토타입 체인으로 접근하므로 메모리를 효율적으로 사용합니다. 세 개의 객체를 생성하고 프로토타입을 접근하는 과정을 그림으로 표현하면 다음과 같습니다.


정리

  • JavaScript는 프로토타입 기반의 언어이므로 클래스를 정의하면 클래스 기반의 언어와 동일하게 동작하지 않습니다.
  • 프로토타입을 활용하여 메서드를 정의하면 객체는 프로토타입 체인으로 메서드를 호출합니다.
반응형

댓글