'어떤 대상'
➡ 컴퓨터, 폰, 책, 옷, 사람, 자동차 ... 등등
👀눈에 보이는 무엇이든 객체가 됨✨
객체 = 속성 + 행동 🙆♀️
💡 속성 : 객체의 특징이나 상태
🧸 행동 : 객체의 동작, 기능, 행위 등
객체 지향 프로그래밍 관점에서 프로그램이란 객체들을 모아둔 것이고
➡ 객체들이 서로 상호 작용 하는 과정을 프로그래밍 하는 것😎
ex ) 노트북 ↔ 사람
키보드를 누르는 행동, 글자를 보여주는 행동
👉 '노트북' & '사람'이 상호작용 해야만 이루어짐🤜💥🤛
객체들의 (속성 & 행동을 코드로 적어둔) 집합체
1 2 3 4 5 6 7 8 9 10 11 | class Notebook(색상, 해상도, 무게, 디스플레이) { this.색상 = 색상; this.해상도 = 해상도; this.무게 = 무게; this.디스플레이 = 디스플레이; this.화면켜짐 = function() {화면 켜기}; this.키보드입력 = function() {키보드 입력받기}; } var galaxyBook = new Notebook('네이비', '2560x1600', '1.2kg', '15인치'); var macBook = new Notebook('스페이스그레이', '2560x1600', '1.8kg', '16인치'); | cs |
💊
한 객체에서 비슷한 역할을 하는 속성,
메서드를 캡슐처럼 한 곳(클래스)에 담는 것
클래스 == 캡슐
장점 : 객체를 계속해서 생성하지 않아도 되기에 '재사용 가능'
목적 : '정보 은닉'
👉 정보 숨기는 것👻
객체의 구체적인 정보(변수, 메서드)를 외부에
노출시키지 않고 접근할 수 없게 보호하는 방법😯💡
캡슐화를 통해 정보 은닉하면
그 정보는 오직 객체 내의 함수 내부에서만 접근 가능✅
ES6 이후엔 #을 사용해 클래스 내부에서만
접근 가능한 프라이빗 필드를 정의할 수 있음
▶ 특징 : 클래스 외부에서 접근 불가능❌
오직 클래스 내부에서만 접근 가능⭕
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Person { #age; // private 필드 선언 constructor(name, age) { this.name = name; this.#age = age; } getAge() { return this.#age; // 클래스 내부에서 접근 가능 } setAge(newAge) { if (newAge > 0) { this.#age = newAge; } } } const person = new Person('Alice', 30); console.log(person.name); // 'Alice' console.log(person.getAge()); // 30 console.log(person.#age); // Error: private 필드에 직접 접근 불가 | cs |
클로저 사용하여 변수나 메서드를 외부에서 접근할 수 있도록 만드는 방법
이 방식은 클래스 이전의 JS에서 많이 사용 되었으며 여전히 유용🙆♀️
▶ 특징 : 내부 변수는 외부에서 직접 접근할 수 없고
내부 함수에서만 접근 가능✅
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function Person(name, age) { let _age = age; // private 변수 this.name = name; this.getAge = function() { return _age; // 클로저를 통해 접근 가능 }; this.setAge = function(newAge) { if (newAge > 0) { _age = newAge; // 클로저를 통해 수정 가능 } }; } const person = new Person('Bob', 40); console.log(person.name); // 'Bob' console.log(person.getAge()); // 40 console.log(person._age); // undefined, 외부에서 접근 불가 | cs |
심볼 사용해 객체의 고유한 속성 만들어
외부에서 직접 접근하기 어렵게 만드는 방법
심볼은 객체 내에서 접근 가능하지만
외부에서 직접 그 키를 알기 어려워 일종의 비공개 필드 만들 수 있음
▶ 특징 : 심볼 사용해 외부에서 속성 탐색하기 어렵게 만들지만
완전한 정보 은닉은 아님❌
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | const _age = Symbol('age'); // Symbol로 고유한 속성 생성 class Person { constructor(name, age) { this.name = name; this[_age] = age; // Symbol 속성 } getAge() { return this[_age]; // 클래스 내부에서 Symbol 속성 접근 가능 } } const person = new Person('Charlie', 50); console.log(person.name); // 'Charlie' console.log(person.getAge()); // 50 console.log(person[_age]); // 직접 접근이 어려움 (완전히 은닉되진 않음) | cs |
모듈 패턴은 클로저 & 즉시 실행 함수 표현식(IIFE) 활용해
변수와 메서드를 모듈처럼 캡슐화 하는 방법
특정 함수나 객체 내에서마 접근할 수 있는 비공개 상태 유지 가능
▶ 특징 : 비공개 함수나 메서드는
모듈 내부에서만 접근 가능하며 외부에선 노출❌
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | const PersonModule = (function() { let _age = 0; // private 변수 return { setAge(newAge) { if (newAge > 0) { _age = newAge; } }, getAge() { return _age; // 내부에서 접근 가능 } }; })(); PersonModule.setAge(35); console.log(PersonModule.getAge()); // 35 console.log(PersonModule._age); // undefined, 외부에서 접근 불가 | cs |
복잡한 문제 ➡ 단순화 시키는 작업 🤭
객체들의 공통된 특징들만 뽑아내는 기법 ❗
🤔프로그래밍에서 추상화 어떻게 구현❓
👉 가장 필요하다고 생각하는 부분만 묶어두면 됨🧵
( 객체들이 공통적으로 갖고 있는 속성이나 메서드가 될 수 있음 )
객체 & 클래스의 관점
👉 각 객체들은 구체적인 값 부여되어 실제하는 개념,
클래스는 객체들이 가져야할 특성이나 기능들을 정의해둔 추상적인 개념
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | // 추상 클래스 class Car { constructor(make, model) { this.make = make; // 제조사 this.model = model; // 모델 } // 추상 메서드 (구현하지 않고 서브클래스에서 구현하도록 강제) start() { throw new Error('이 메서드는 서브클래스에서 구현해야 합니다.'); } } // 서브클래스: 전기차 class ElectricCar extends Car { start() { return `${this.make} ${this.model} 전기차가 시작 되었습니다.`; } } // 서브클래스: 스포츠카 class SportsCar extends Car { start() { return `${this.make} ${this.model} 스포츠카가 시작 되었습니다.`; } } // 객체 생성 const tesla = new ElectricCar('테슬라', '모델 S'); const ferrari = new SportsCar('페라리', '488 GTB'); console.log(tesla.start()); // 테슬라 모델 S 전기차가 시작 되었습니다. console.log(ferrari.start()); // 페라리 488 GTB 스포츠카가 시작 되었습니다. | cs |
부모 클래스의 속성과 기능을 그래로 이어받아 사용할 수 있게 하고
기능의 일부분을 변경해야 할 경우 상속 받은 자식 클래스에서
해당 기능만 다시 수정(정의)하여 사용할 수 있게 하는 것 ❗
▶ 장점 : 코드 재사용하기에 중복 제거🔥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // 기본 클래스: Animal class Animal { constructor(name) { this.name = name; // 동물의 이름 } speak() { return `${this.name}가 소리를 냅니다.`; } } // 서브클래스: Dog class Dog extends Animal { speak() { return `${this.name}가 멍멍합니다!`; } } // 서브클래스: Cat class Cat extends Animal { speak() { return `${this.name}가 야옹합니다!`; } } // 객체 생성 및 메서드 호출 const dog = new Dog('바둑이'); const cat = new Cat('냥이'); console.log(dog.speak()); // 바둑이 가 멍멍합니다! console.log(cat.speak()); // 냥이 가 야옹합니다! | cs |
Overriding(오버라이딩) : 부모클래스 메서드를 자식 클래스에서 재정의하는 것
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // 부모 클래스: Animal class Animal { // 기본 메서드 speak() { return '동물이 소리를 냅니다.'; } } // 자식 클래스: Dog class Dog extends Animal { // 부모 클래스의 speak 메서드를 오버라이드 speak() { return '강아지가 멍멍합니다!'; // 오버라이딩된 메서드 } } // 자식 클래스: Cat class Cat extends Animal { // 부모 클래스의 speak 메서드를 오버라이드 speak() { return '고양이가 야옹합니다!'; // 오버라이딩된 메서드 } } // 객체 생성 const dog = new Dog(); const cat = new Cat(); // 메서드 호출 console.log(dog.speak()); // 강아지가 멍멍합니다! (오버라이딩된 메서드 호출) console.log(cat.speak()); // 고양이가 야옹합니다! (오버라이딩된 메서드 호출) | cs |
Overloading(오버로딩) : 같은 이름으로 다양한 매개변수, 리턴타입의 메소드를 여러개 정의하는 것
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Animal { // 메서드: speak (오버로딩) speak(a, b) { // 매개변수의 개수에 따라 다른 동작 수행 if (typeof a === 'string' && typeof b === 'undefined') { return `${a}가 소리를 냅니다.`; // 단일 문자열 입력 } else if (typeof a === 'string' && typeof b === 'string') { return `${a}와 ${b}가 함께 소리를 냅니다.`; // 두 개의 문자열 입력 } else { return '유효하지 않은 입력입니다.'; // 잘못된 입력 처리 } } } // 객체 생성 const animal = new Animal(); // 메서드 호출 console.log(animal.speak('고양이')); // 고양이가 소리를 냅니다. (단일 입력) console.log(animal.speak('고양이', '강아지')); // 고양이와 강아지가 함께 소리를 냅니다. (두 개의 입력) console.log(animal.speak(5)); // 유효하지 않은 입력입니다. (잘못된 입력) | cs |