250301 TIL #622 OOP in JavaScript

김춘복·2025년 3월 1일
0

TIL : Today I Learned

목록 보기
625/627

Today I Learned

오늘은 자바스크립트에서 객체지향 프로그래밍으로 코드를 작성하는 방법에 대해 정리했다.


OOP in JavaScript

객체 & 클래스

js에서 객체는 속성(properties)과 메서드(methods)를 가진 데이터 구조
ES6부터는 클래스 문법이 도입되어 객체 생성을 좀 더 직관적으로 할 수 있다.

  • 자바랑 다르게 명시적 인터페이스나 추상 클래스는 없고 간접적으로만 구현이 가능하다.

  • class 키워드로 클래스 정의 - constructor 메서드에서 초기화 - 클래스 내부 메서드 정의 - new 연산자로 인스턴스 생성

// ES6 이전: 생성자 함수 사용
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    console.log(`안녕하세요, 제 이름은 ${this.name}이고 ${this.age}살입니다.`);
  };
}

// -------------------------------------------------------------

// ES6 이후: 클래스 문법 사용
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  greet() {
    console.log(`안녕하세요, 제 이름은 ${this.name}이고 ${this.age}살입니다.`);
  }
}

const person = new Person('김춘복', 6);
person.greet(); // 출력: 안녕하세요, 제 이름은 김춘복이고 6살입니다.

프로토타입 기반 상속

js는 프로토타입 기반 언어다.
모든 객체는 프로토타입이라는 다른 객체를 참조하며, 이를 통해 속성과 메서드를 상속받는다.

  • 생성자 함수 정의 - 프로토타입에 메서드 추가 - new 연산자로 인스턴스 생성

  • 프로토타입 체인
    객체가 속성이나 메서드를 찾을 때 자신의 프로토타입을 따라 상위 프로토타입으로 연결되는 구조로, 이를 통해 여러 단계의 상속이 가능하다.
    (자바는 단일 상속만 지원)

// 프로토타입 체인 예제
const animal = {
  eat: function() {
    console.log('먹는 중...');
  }
};

const dog = Object.create(animal);
dog.bark = function() {
  console.log('멍멍!');
};

const puppy = Object.create(dog);
puppy.play = function() {
  console.log('놀고 있어요!');
};

puppy.eat(); // 출력: 먹는 중... (animal로부터 상속)
puppy.bark(); // 출력: 멍멍! (dog로부터 상속)
puppy.play(); // 출력: 놀고 있어요! (자체 메서드)

캡슐화

데이터와 메서드를 하나의 단위로 묶어서 외부에서 접근할 수 없도록 보호하는 개념
js에서는 자바처럼 접근제어자로 완전한 캡슐화는 지원하지 않았지만, 클로저나 심볼을 이용해 구현이 가능했다.

class Person {
  constructor(name, age) {
    // 클로저를 활용한 프라이빗 변수
    const _name = name;
    const _age = age;
    
    // 게터 메서드
    this.getName = function() {
      return _name;
    };
    
    this.getAge = function() {
      return _age;
    };
    
    // 세터 메서드
    this.setName = function(newName) {
      _name = newName;
    };
    
    this.setAge = function(newAge) {
      if (newAge > 0) {
        _age = newAge;
      }
    };
  }
  
  // 공개 메서드
  introduce() {
    console.log(`안녕하세요, 제 이름은 ${this.getName()}이고, ${this.getAge()}살입니다.`);
  }
}

const person = new Person('홍길동', 30);
person.introduce(); // "안녕하세요, 제 이름은 홍길동이고, 30살입니다."
console.log(person._name); // undefined - 직접 접근 불가
  • ES2022부터 정식으로 지원되는 프라이빗 필드를 사용하면 진정한 캡슐화를 구현할 수 있다.
    참고 사이트 : joyhong-91
class User {
  #email; // 프라이빗 필드 선언
  #password;
  
  constructor(email, password) {
    this.#email = email;
    this.#password = password;
  }
  
  getEmail() {
    return this.#email;
  }
  
  setEmail(newEmail) {
    if (newEmail.includes('@')) {
      this.#email = newEmail;
    } else {
      throw new Error('유효하지 않은 이메일 형식입니다.');
    }
  }
  
  #validatePassword(password) {
    return password.length >= 8;
  }
  
  changePassword(oldPassword, newPassword) {
    if (oldPassword === this.#password && this.#validatePassword(newPassword)) {
      this.#password = newPassword;
      return true;
    }
    return false;
  }
}

const user = new User('user@example.com', 'password123');
console.log(user.getEmail()); // 'user@example.com'
// console.log(user.#email); // SyntaxError: Private field '#email' must be declared in an enclosing class

상속

한 클래스가 다른 클래스의 속성과 메서드를 물려받는 개념
js에서는 프로토타입 기반 상속과 클래스기반 상속 모두 지원

// 클래스 기반 상속
class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name}이/가 소리를 냅니다.`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // 부모 클래스의 생성자 호출
    this.breed = breed;
  }
  
  speak() {
    console.log(`${this.name}이/가 멍멍 소리를 냅니다.`);
  }
  
  fetch() {
    console.log(`${this.name}이/가 물건을 가져옵니다.`);
  }
}

const dog = new Dog('멍멍이', '골든 리트리버');
dog.speak(); // 출력: 멍멍이이/가 멍멍 소리를 냅니다.
dog.fetch(); // 출력: 멍멍이이/가 물건을 가져옵니다.

다형성

동일한 인터페이스를 통해 다양한 객체 타입에 접근할 수 있는 능력
js에서는 메서드 오버라이딩이 그 예시

class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name}이/가 소리를 냅니다.`);
  }
}

class Dog extends Animal {
  speak() {
    console.log(`${this.name}이/가 멍멍 소리를 냅니다.`);
  }
}

class Cat extends Animal {
  speak() {
    console.log(`${this.name}이/가 야옹 소리를 냅니다.`);
  }
}

// 다형성 활용
function makeAnimalSpeak(animal) {
  animal.speak();
}

const dog = new Dog('멍멍이');
const cat = new Cat('야옹이');

makeAnimalSpeak(dog); // 출력: 멍멍이이/가 멍멍 소리를 냅니다.
makeAnimalSpeak(cat); // 출력: 야옹이이/가 야옹 소리를 냅니다.
profile
Backend Dev / Data Engineer

0개의 댓글

관련 채용 정보