본문 바로가기
Study

20. JavaScript 클래스 이해하기 | 웹 개발 기초

by 구구 구구 2024. 7. 20.
반응형

사이버펑크 스타일, dall-e

 

JavaScript Using Classes: 객체 지향 프로그래밍의 새로운 접근

JavaScript에서 클래스를 사용하여 객체 지향 프로그래밍을 구현하는 방법을 알아봅니다. 클래스 선언, 인스턴스 메서드, 정적 속성, 상속과 확장 등 다양한 주제를 다룹니다.

 

01. 클래스 선언 및 생성

1) 클래스 선언 방법

JavaScript에서 클래스는 class 키워드를 사용하여 선언합니다. 클래스 선언은 ES6(ECMAScript 2015)에서 도입되었으며, 이는 JavaScript의 객체 지향 프로그래밍 패러다임을 더욱 쉽게 사용할 수 있게 해줍니다. 클래스 선언은 다음과 같은 형식을 따릅니다.

class Person {
  // 클래스 본문
}
            

위 예시에서는 Person이라는 이름의 클래스를 선언했습니다. 클래스 본문 내부에 생성자, 메서드, 필드 등을 정의할 수 있습니다. 클래스 선언은 함수 선언과 유사하지만, 클래스는 인스턴스를 생성할 수 있는 템플릿 역할을 합니다.

2) 생성자를 통한 객체 생성

클래스 선언에서 생성자는 constructor 키워드를 사용하여 정의합니다. 생성자는 클래스로부터 객체를 생성할 때 호출되는 특별한 메서드입니다. 생성자를 통해 객체의 초기 상태를 설정할 수 있습니다.

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

// 인스턴스 생성
const person1 = new Person('Alice', 30);
const person2 = new Person('Bob', 25);

console.log(person1.name); // Alice
console.log(person2.age);  // 25
            

위 예시에서 Person 클래스는 nameage를 매개변수로 받는 생성자를 정의합니다. this 키워드를 사용하여 인스턴스의 속성을 설정합니다. new 키워드를 사용하여 Person 클래스의 인스턴스를 생성하고, 생성된 인스턴스의 속성에 접근할 수 있습니다.

 

02. 인스턴스 메서드 및 필드

1) 인스턴스 메서드 정의

클래스 내에서 메서드를 정의하면, 해당 메서드는 클래스의 모든 인스턴스에서 사용할 수 있습니다. 이러한 메서드를 인스턴스 메서드라고 합니다. 인스턴스 메서드는 this 키워드를 사용하여 인스턴스의 속성에 접근할 수 있습니다.

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  // 인스턴스 메서드 정의
  greet() {
    return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
  }
}

const person1 = new Person('Alice', 30);
console.log(person1.greet()); // Hello, my name is Alice and I am 30 years old.
            

위 예시에서 greet 메서드는 Person 클래스의 인스턴스 메서드로 정의되었습니다. 이 메서드는 인스턴스의 nameage 속성을 사용하여 인사말을 반환합니다.

2) 비공개 필드와 그 활용 방법

비공개 필드는 # 기호를 사용하여 정의하며, 클래스 외부에서 접근할 수 없습니다. 이는 클래스 내부의 구현 세부 사항을 숨기고, 캡슐화를 통해 데이터를 보호할 수 있게 해줍니다.

class Person {
  // 비공개 필드 정의
  #ssn;

  constructor(name, age, ssn) {
    this.name = name;
    this.age = age;
    this.#ssn = ssn;
  }

  // 비공개 필드 접근 메서드
  getSsn() {
    return this.#ssn;
  }
}

const person1 = new Person('Alice', 30, '123-45-6789');
console.log(person1.name);   // Alice
console.log(person1.getSsn()); // 123-45-6789
            

위 예시에서 #ssn은 비공개 필드로 정의되었습니다. 이는 클래스 외부에서 직접 접근할 수 없으며, getSsn 메서드를 통해서만 접근할 수 있습니다. 비공개 필드를 사용하면 중요한 데이터를 보호할 수 있으며, 클래스의 내부 구현을 감추어 외부 코드와의 의존성을 줄일 수 있습니다.

 

03. 정적 속성

1) 정적 메서드와 필드의 정의

정적 메서드와 필드는 클래스 자체에 속하는 메서드와 필드를 의미합니다. 이는 인스턴스가 아닌 클래스 이름을 통해 직접 접근할 수 있습니다. 정적 메서드는 static 키워드를 사용하여 정의하며, 정적 필드도 마찬가지로 static 키워드를 사용합니다.

class MathUtil {
  // 정적 필드
  static PI = 3.14159;

  // 정적 메서드
  static add(a, b) {
    return a + b;
  }
}

console.log(MathUtil.PI); // 3.14159
console.log(MathUtil.add(2, 3)); // 5
            

위 예시에서 MathUtil 클래스는 PI라는 정적 필드와 add라는 정적 메서드를 정의합니다. 인스턴스를 생성하지 않고 클래스 이름을 통해 직접 접근할 수 있습니다.

2) 정적 속성의 활용 사례

정적 속성은 보통 유틸리티 함수나 상수를 정의할 때 사용됩니다. 인스턴스 간에 공유되는 데이터나 기능을 제공하는 데 유용합니다.

class DateUtil {
  // 현재 날짜를 반환하는 정적 메서드
  static getCurrentDate() {
    return new Date().toLocaleDateString();
  }

  // 특정 연도가 윤년인지 확인하는 정적 메서드
  static isLeapYear(year) {
    return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
  }
}

console.log(DateUtil.getCurrentDate()); // 현재 날짜 출력 (예: 2024-07-17)
console.log(DateUtil.isLeapYear(2024)); // true
console.log(DateUtil.isLeapYear(2023)); // false
            

위 예시에서 DateUtil 클래스는 현재 날짜를 반환하는 getCurrentDate 메서드와 윤년 여부를 확인하는 isLeapYear 메서드를 정의합니다. 이러한 정적 메서드는 특정 기능을 제공하며, 인스턴스를 생성하지 않고도 사용할 수 있습니다.

 

04. 상속과 확장

1) 클래스 상속의 개념

클래스 상속은 기존 클래스의 속성과 메서드를 새로운 클래스가 물려받아 사용하는 개념입니다. 이를 통해 코드 재사용성을 높이고, 공통된 기능을 공유할 수 있습니다. 부모 클래스의 기능을 자식 클래스가 확장하거나 재정의할 수 있습니다.

2) extends 키워드 사용법

JavaScript에서 클래스 상속은 extends 키워드를 사용하여 구현됩니다. extends 키워드는 자식 클래스가 부모 클래스를 상속받을 때 사용됩니다. 자식 클래스는 부모 클래스의 모든 속성과 메서드를 상속받으며, 필요에 따라 새로운 속성이나 메서드를 추가할 수 있습니다.

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    return `${this.name} makes a sound.`;
  }
}

class Dog extends Animal {
  speak() {
    return `${this.name} barks.`;
  }
}

const dog = new Dog('Rex');
console.log(dog.speak()); // Rex barks.
            

위 예시에서 Animal 클래스는 name 속성과 speak 메서드를 가집니다. Dog 클래스는 Animal 클래스를 상속받아 speak 메서드를 재정의(오버라이드)합니다. Dog 클래스의 인스턴스인 dogspeak 메서드를 호출하여 "Rex barks."를 출력합니다.

3) 상속을 통한 코드 재사용

상속을 통해 코드 재사용성을 높일 수 있습니다. 부모 클래스의 기능을 재사용하고, 자식 클래스에서 필요한 부분만 확장하거나 수정할 수 있습니다.

class Shape {
  constructor(color) {
    this.color = color;
  }

  describe() {
    return `A ${this.color} shape.`;
  }
}

class Circle extends Shape {
  constructor(color, radius) {
    super(color);
    this.radius = radius;
  }

  area() {
    return Math.PI * this.radius ** 2;
  }

  describe() {
    return `A ${this.color} circle with radius ${this.radius}.`;
  }
}

const circle = new Circle('red', 5);
console.log(circle.describe()); // A red circle with radius 5.
console.log(circle.area()); // 78.53981633974483
            

위 예시에서 Shape 클래스는 color 속성과 describe 메서드를 가집니다. Circle 클래스는 Shape 클래스를 상속받아 radius 속성을 추가하고, area 메서드와 describe 메서드를 재정의합니다. 이를 통해 Circle 클래스는 부모 클래스의 기능을 재사용하면서, 추가적인 속성과 메서드를 정의할 수 있습니다.

 

05. 비공개 필드와 메서드

1) 비공개 필드의 선언과 사용

비공개 필드는 클래스 외부에서 접근할 수 없는 필드로, 클래스 내부의 구현 세부 사항을 숨기고 캡슐화를 통해 데이터를 보호하는 데 사용됩니다. 비공개 필드는 # 기호를 사용하여 선언합니다.

class BankAccount {
  // 비공개 필드 선언
  #balance;

  constructor(initialBalance) {
    this.#balance = initialBalance;
  }

  // 비공개 필드 접근 메서드
  getBalance() {
    return this.#balance;
  }

  // 비공개 필드 수정 메서드
  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
    }
  }

  withdraw(amount) {
    if (amount > 0 && amount <= this.#balance) {
      this.#balance -= amount;
    }
  }
}

const account = new BankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
account.withdraw(200);
console.log(account.getBalance()); // 1300
console.log(account.#balance); // SyntaxError: Private field '#balance' must be declared in an enclosing class
            

위 예시에서 BankAccount 클래스는 비공개 필드 #balance를 선언하고, getBalance, deposit, withdraw 메서드를 통해서만 접근할 수 있게 합니다. 외부에서는 직접 접근할 수 없으며, 오직 공개된 메서드를 통해서만 조작할 수 있습니다.

2) 비공개 메서드 활용 사례

비공개 메서드는 클래스 내부에서만 호출할 수 있는 메서드로, 클래스 내부의 복잡한 작업을 숨기고 외부 인터페이스를 간결하게 유지하는 데 사용됩니다.

class Employee {
  #name;
  #age;
  
  constructor(name, age) {
    this.#name = name;
    this.#age = age;
  }

  // 비공개 메서드 선언
  #calculateRetirementAge() {
    return 65 - this.#age;
  }

  // 공개 메서드에서 비공개 메서드 호출
  getRetirementInfo() {
    return `${this.#name} has ${this.#calculateRetirementAge()} years until retirement.`;
  }
}

const employee = new Employee('John Doe', 40);
console.log(employee.getRetirementInfo()); // John Doe has 25 years until retirement.
console.log(employee.#calculateRetirementAge()); // SyntaxError: Private field '#calculateRetirementAge' must be declared in an enclosing class
            

위 예시에서 Employee 클래스는 #calculateRetirementAge라는 비공개 메서드를 사용하여 직원의 은퇴까지 남은 기간을 계산합니다. 이 메서드는 클래스 내부의 getRetirementInfo 메서드에서만 호출할 수 있으며, 외부에서는 접근할 수 없습니다.

 

06. 클래스 사용의 장점과 단점

1) 클래스 사용의 장점

클래스는 객체 지향 프로그래밍의 기본 단위로, 코드의 재사용성, 유지보수성, 가독성을 높이는 데 기여합니다.

  • 캡슐화: 클래스는 비공개 필드와 메서드를 통해 데이터와 메서드를 캡슐화할 수 있습니다. 이는 데이터 보호와 코드의 모듈화를 돕습니다.
  • 상속: 클래스 상속을 통해 공통된 기능을 부모 클래스에 정의하고, 자식 클래스에서 필요한 부분만 확장하거나 수정할 수 있습니다. 이를 통해 코드의 재사용성과 유지보수성을 높일 수 있습니다.
  • 다형성: 객체 지향 프로그래밍의 중요한 개념인 다형성을 지원합니다. 동일한 인터페이스를 통해 서로 다른 클래스의 객체를 처리할 수 있어 코드의 유연성이 증가합니다.
class Animal {
  speak() {
    console.log('Animal makes a sound');
  }
}

class Dog extends Animal {
  speak() {
    console.log('Dog barks');
  }
}

class Cat extends Animal {
  speak() {
    console.log('Cat meows');
  }
}

const animals = [new Dog(), new Cat()];
animals.forEach(animal => animal.speak()); 
// Dog barks
// Cat meows
            

2) 객체 지향 프로그래밍

객체 지향 프로그래밍(OOP)은 데이터를 객체라는 단위로 묶어 처리하는 프로그래밍 패러다임입니다. OOP의 주요 원칙에는 캡슐화, 상속, 다형성, 추상화가 있습니다.

  • 캡슐화: 데이터와 메서드를 하나의 단위로 묶고, 데이터 은닉을 통해 외부로부터 보호합니다.
  • 상속: 기존 클래스의 특성을 새로운 클래스가 물려받아 재사용할 수 있게 합니다.
  • 다형성: 동일한 메서드나 속성을 다양한 클래스에서 다른 방식으로 구현할 수 있게 합니다.
  • 추상화: 중요한 정보를 중심으로 객체의 특징을 정의하고, 불필요한 세부 사항은 숨깁니다.

객체 지향 프로그래밍은 복잡한 시스템을 보다 직관적이고 관리하기 쉽게 설계할 수 있게 해줍니다. JavaScript는 프로토타입 기반의 언어이지만, 클래스 문법을 통해 객체 지향 프로그래밍의 장점을 보다 쉽게 활용할 수 있습니다.

위에서 설명한 비공개 필드와 메서드, 상속, 정적 속성 등은 모두 객체 지향 프로그래밍의 핵심 요소들로, JavaScript에서 이를 적절히 활용하면 더 견고하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.


관련된 다른 글도 읽어보시길 추천합니다

 

2024.07.12 - [AI] - 17. JavaScript 배열과 타입 배열의 모든 것 | 웹 개발 기초

 

17. JavaScript 배열과 타입 배열의 모든 것 | 웹 개발 기초

JavaScript Indexed Collections: 배열과 타입 배열의 모든 것 01. 배열1) 배열의 정의와 역할배열은 JavaScript에서 가장 중요한 데이터 구조 중 하나로, 여러 개의 값을 하나의 변수로 묶어 관리할 수 있게

guguuu.com

2024.07.12 - [Study] - 16. JavaScript 정규 표현식 완벽 가이드 | 웹 개발 기초

 

16. JavaScript 정규 표현식 완벽 가이드 | 웹 개발 기초

JavaScript 정규 표현식 완벽 가이드: 기본부터 활용까지 01. 서론1) JavaScript 정규 표현식 소개JavaScript 정규 표현식(Regular Expressions, RegEx)은 문자열 내 특정 패턴을 찾고, 일치시키며, 추출하거나 교

guguuu.com

2024.07.11 - [Study] - 15. JavaScript 텍스트 포맷팅 | 웹 개발 기초

 

15. JavaScript 텍스트 포맷팅 | 웹 개발 기초

JavaScript 텍스트 포맷팅 가이드 01. JavaScript 문자열1) JavaScript에서 텍스트 포맷팅의 중요성JavaScript에서 텍스트 포맷팅은 웹 애플리케이션과 사용자 간의 상호작용을 향상시키는 중요한 역할을 합

guguuu.com


읽어주셔서 감사합니다

공감은 힘이 됩니다

 

:)

반응형

TOP

Designed by 티스토리