-
자바스크립트 객체지향 기본기코드잇 부스트 2024. 6. 3. 23:26
자바스크립트 객체지향 기본기
1. 객체와 클래스
객체 지향 프로그래밍이란?
구성:
- 프로퍼티(property): 변수
- 메소드(method): 함수
*절차 지향 프로그래밍(Process-Oriented Programming, POP):
데이터 구조와 이에 수반하는 동작들을 분리하는 컴퓨터 프로그래밍의 패러다임
객체 만들기 1-1: Object-Literal
const user = { email: 'chris123@google.com', birthdate: '1992-03-21', buy(item) { console.log(`${this.email} buys ${item.name}`); }, };
- 중괄호를 쓰고 그 안에 프로퍼티와 메소드를 나열하는 것
객체 만들기 1-2: Factory function
function createUser(email, birthdate) { const user = { email, birthdate, buy(item) { console.log(`${this.email} buys ${item.name}`); }, }; return user; } const user1 = createUser('a@email.com', '1999-09-01'); const user2 = createUser('b@email.com', '1998-07-02'); const user3 = createUser('c@email.com', '1990-11-24');
- 객체를 생성해서 리턴하는 함수
객체 만들기 2: Constructor function
- constructor function 내에서 생성할 객체를 가리킨다.
- new 키워드를 앞에 붙여서 함수를 호출해야 정상적으로 작동한다.
- 리턴문을 작성하지 않아도 생성한 객체를 자동으로 리턴한다.
- 함수의 첫 문자를 대문자로 지정하는 것을 권장한다.
function User(email, birthdate) { this.email = email; this.birthdate = birthdate; this.buy = function (item) { console.log(`${this.email} buys ${item.name}`); }; } const user1 = new User('a@email.com', '1999-09-01'); const user2 = new User('b@email.com', '1998-07-02'); const user3 = new User('c@email.com', '1990-11-24');
- 함수 안에서 this를 활용해 객체를 생성하고 리턴하는 특별한 함수
객체 만들기 3: Class(ES2015)
class를 생성하기 위한 템플릿
- this 키워드는 Class 내에서 생성할 객체를 가리킨다.
- 프로퍼티는 constructor() 안, 메소드나 getter는 constructor() 바깥에 작성한다.
- 세 가지 방법(Declaration, unnamed expression, named expression)으로 Class 객체를 만들 수 있다.
- Hoisting을 허용하지 않는다.
// Class 선언식(declaration) class User1 { constructor(email, birthdate) { this.email = email; this.birthdate = birthdate; } buy(item) { console.log(`${this.email} buys ${item.name}`); } } const user1 = new User('a@email.com', '1999-09-01');
// Class 표현식(expression) // unnamed const User = class { constructor(email, birthdate) { this.email = email; this.birthdate = birthdate; } buy(item) { console.log(`${this.email} buys ${item.name}`); } } const user1 = new User('a@email.com', '1999-09-01');
// Class 표현식(expression) // named const User = class UserClassName { constructor(email, birthdate) { this.email = email; this.birthdate = birthdate; } buy(item) { console.log(`${this.email} buys ${item.name}`); } } const user1 = new User('a@email.com', '1999-09-01'); User.name // "UserClassName"
2. 객체 지향 프로그래밍의 4개의 기둥
추상화(abstraction)
- 어떤 구체적인 것을 원하는 방향으로 간략화해서 나타내는 것.
- (기능을 명시하고 구현은 생략한다.)
캡슐화(Encapsulation)
외부에서 객체의 특정 프로퍼티에 직접 접근하지 못하도록 막는 것.
특정 프로퍼티에 대한 접근은 getter, setter 메소드를 통해서만 가능하다.
class User { constructor(email, birthdate) { this.email = email; this.birthdate = birthdate; } buy(item) { console.log(`${this.email} buys ${item.name}`); } get email() { return this._email; } set email(address) { if (addrress.includes('@')) { this._email = address; } else { throw new Error('invalid email address'); } } }
- get()는 obj.propName을 사용해 프로퍼티를 읽으려고 할 때 실행된다.
- set()는 obj.propName = value로 프로퍼티에 값을 할당하려 할 때 실행된다.
- 프로퍼티 네임과 동일한 이름을 getter, setter의 이름으로 사용했기 때문에, 프로퍼티에 접근하려면 프로퍼티 네임 앞에 언더바(_)를 붙여 접근한다.
- getter, setter만 설정할 경우 obj._propName의 값은 여전히 접근/수정이 가능하기 때문에 완벽한 캡슐화라고 볼 수 없다.
캡슐화 더 알아보기
Java에는 private이라는 키워드가 있어서 문법 차원에서 캡슐화를 지원하지만, JavaScript에는 캡슐화를 자체적으로 지원하는 문법이 아직 없다.
*클로저(Closure)라고 하는 개념을 응용해서 완벽한 캡슐화를 할 수 있다.
- closure 어떤 함수와 그 함수가 참조할 수 있는 값들로 이루어진 환경을 하나로 묶어서, 함수가 정의된 당시에 참조할 수 있었던 변수들을 계속 참조할 수 있는 상태의 함수
function createUser(email, birthdate) { let _email = email; const user = { birthdate, get email() { return _email; }, set email(address) { if (address.includes('@')) { _email = address; } else { throw new Error('invalid email address'); } }, }; return user; }
- 위와 같이 function 안, user 객체 바깥에 _email 변수를 만들고, _email 변수의 값을 읽고 쓸 수 있는 email이라는 getter/setter 메소드를 만들면 완벽한 캡슐화가 가능하다.
- 메소드에도 closure 개념을 응용할 수 있다
function createUser(email, birthdate) { const _email = email; let _point = 0; // 사용자가 물건을 살 때마다 1포인트씩 적립해 주는 함수 function increasePoint() { _point += 1; } const user = { birthdate, get email() { return _email; }, get point() { return _point; }, buy(item) { console.log(`${this.email} buys ${item.name}`); increasePoint(); }, }; return user; }
- function 안, user 객체 바깥에 _point 변수와 incresePoint() 함수를 만들고, _point 변수의 값을 읽을 수 있는 point라는 getter 메소드를 만들면 완벽한 캡슐화가 가능하다.
상속(inheritance)
자식 객체가 부모 객체의 프로퍼티와 메소드를 물려받는 것
- extends 클래스를 다른 클래스의 자식으로 만들기 위해 사용되는 키워드
class User { constructor(email, birthdate) { this.email = email; this.birthdate = birthdate; } buy(item) { console.log(`${this.email} buys ${item.name}`); } } class PremiumUser extends User { constructor(email, birthdate, level) { super(email, birthdate); this.level = level; } streamMusicForFree() { console.log(`Free music streaming for ${this.email}`); } }
- 자식 클래스의 constructor() 안쪽에 super() 키워드를 호출해야 자식 클래스에서 this 키워드에 접근할 수 있다. 호출하기 전에는 ReferenceError가 발생한다.
다형성(Polymorphism)
프로그램 언어 각 요소들이 다양한 데이터 타입에 속하는 것이 허가되는 성질
const user1 = new User('chris123@google.com', '19920321'); const user2 = new User('rache@google.com', '19880516'); const user3 = new User('brian@google.com', '20051125'); const pUser1 = new PremiumUser('tommy@google.com', '19901207', 3); const pUser2 = new PremiumUser('helloMike@google.com', '19900915', 2); const pUser3 = new PremiumUser('alicekim@google.com', '20010722', 5); const users = [user1, pUser1, user2, pUser2, user3, pUser3]; users.forEach((user) => { user.buy(item); });
하나의 변수인 user가 다양한 종류의 객체 User, PremiumUser를 가리킬 수 있는 것도 다형성이라고 한다.
- *자식 클래스에서 부모 클래스의 메소드를 오버라이딩하고 그 후에 이 다형성을 활용하는 경우가 많다.
부모 클래스의 메소드가 필요하다면?
- 자식 클래스에서 부모 클래스의 메소드를 오버라이딩해서 부모 클래스의 메소드를 불러올 수 없을 때, super.method() 키워드를 사용해서 부모 클래스의 메소드를 자식 클래스 내에서 불러올 수 있다.
instanceof 연산자
object instance of constructor:
- constructor의 프로토타입 프로퍼티가 객체의 프로토타입 체인에 나타나는지 여부를 검사하는 연산자
- 객체의 프로토타입 체인을 검사하므로 자식 클래스로 만든 객체를 왼쪽에, 부모 클래스를 오른쪽에 넣고 instaceof 연산자를 적용해도 true를 리턴한다.
static 프로퍼티와 static 메소드
static 클래스로 만든 객체가 아니라 클래스 자체로 접근할 수 있는 프로퍼티나 메소드
class Math { static PI = 3.14; static getCircleArea(radius) { return Math.PI * radius * radius; } } // static 프로퍼티 값 변경 Math.PI = 3.141592; // static 메소드 추가 Math.getRectangleArea = function (width, height) { return width * height; } console.log(Math.PI); console.log(Math.getRectangleArea(4, 5)); // Date 내장 객체의 static 메소드 now() console.log(Date.now());
- static property나 method도 getter, setter 메소드로 캡슐화할 수 있다.
클래스는 파일 하나당 하나씩 넣어주는 게 좋아요
보통 하나의 클래스를 모듈화하여 export하는 방식을 많이 사용한다
'코드잇 부스트' 카테고리의 다른 글
자바스크립트로 리퀘스트 보내기 (0) 2024.06.28 비동기 자바 스크립트 (0) 2024.06.28 모던자바스크립트: 문법과 표현 & 유용한 내부 기능 (0) 2024.05.30 모던 자바스크립트: 동작원리 & 함수 다루기 (0) 2024.05.30 프로그래밍과 데이터 in JavaScript (0) 2024.05.23