✅ 클래스와 인스턴스라는 용어를 이해할 수 있다.
✅ new , class 키워드의 사용법을 이해할 수 있다.
✅ 현실 세계의 모델을 바탕으로 클래스의 메소드와 속성을 디자인할 수 있다.
✅ 객체 지향 프로그래밍 특징을 이해할 수 있다(캡슐화, 상속, 추상화, 다향성)
✅ JavaScript에서 객체 지향 프로그래밍을 구현할 수 있다.
✅ Prototype이 무엇인지 이해할 수 있다
✅ 객체 지향 프로그래밍의 상속(Inheritance)의 개념을 이해하고 코드로 작성할 수 있다.
✅ 상속관계를 가진 현실 세계의 모델을 코드로 작성할 수 있다.
✅ 클래스 상속의 원리를 이해할 수 있다.
✅ Prototype chain을 이해하고 설명할 수 있다. (proto)
객체지향 프로그래밍(OOP)은 프로그램 설계 방법론 중 하나이고
명령어, 함수의 목록으로 보는 절차 지향적 관점에서 벗어나
여러개의 독립적 단위 객체의 집합으로 프로그램을 표현한다
속성과 메소드가 하나의 "객체"라는 개념에 포함되며,
이는 자바스크립트 내장 타입인 object(이하, object literal)와는 다르게,
클래스(Class)라는 이름으로 부른다
먼저 이해해야 할 객체지향의 4가지 특징이 있다
데이터(속성)와 기능(메소드)을 하나의 객체 안에 넣어서 묶는 것을 의미한다
속성명을 밑줄로 시작하는 규칙이 있다
무언의 약속으로 앞에 밑줄(_)이 붙어있으면 외부에서 접근하면 안되겠구나
라고 생각하면 된다
캡슐화는 은닉화의 특징도 포함하고 있는데
객체에 대한 구체적인 정보를 외부에서 확인할 수 없도록 하는 것이다
디테일한 구현이나 데이터는 숨기고, 객체 외부에서 필요한 동작(메소드)만 노출시켜서
잘 못 사용될 수 있는 객체의 부분을 사용할 수 없게 막는 것이다
만약 게임 캐릭터 스탯을 올리는 기능을 만들었을때
스탯을 올리고 내리는 것이 아니라 스탯 자체에 접근이 가능하면
말도 안되는 값을 입력해 오류가 날 수 도 있다
이 스탯 변수를 외부에서 바꾸지 못하도록 보호하는 것이 캡슐화 이다!
대부분의 객체지향 프로그래밍 언어는 public, private 와 같은 접근제한자를 선언해
공개범위를 한정할 수 있는데 자바스크립트는 접근제한자를 제공하지 않는다
다른 방법으로 정보 은닉을 할 수 있다
function Person(name, age){
this.name = name // public 접근가능
let _age = age // private 접근불가능
this.sayHi = function () {
console.log(`my name is ${this.name}, i am ${age}`)
}
}
let me = new Person('lee', 20)
me.sayHi(); // my name is lee, i am 20
console.log(me.name) // lee
console.log(me._age) // undefinde
name 프로퍼티는 this.name으로 선언이 되어있어서
객체의 프로퍼티로 적용되며 외부에서 참조, 변경이 가능하지만
age변수는 person 생성자 함수의 지역변수 이기때문에 외부에서 참조하거나 변경 할 수 없다
부모 클래스의 특징을 자식 클래스가 물려받는 것이다
이미 존재하는 코드를 사용하거나 그 코드를 활용하기 좋은 방법이고
프로토타입을 이용한 객체로의 상속을 의미한다
내부 구현은 아주 복잡한데, 실제로 노출되는 부분은 단순하게 만드는 방법
우리가 만든 복잡한 객체를 사용자들이 쉽게 사용 할 수 있도록 해준다
예를 들어 전화라는 객체가 있을때 그 안에는 스피커와 마이크가 존재하고, 서킷 보드 등이 존재하는 등 내부 구현이 되어 있다
그러나 실제로 사용할 때는, 이런 존재에 대해서 생각하지 않고 단순히 수화기를 들고 버튼을 눌러서 해결하는 것으로 인터페이스(interface)를 단순화할 수 있다
너무 많은 기능들이 노출되지 않아 예기치 못한 사용상의 변화가 일어나지 않도록 만들 수 있다
캡슐화가 코드나 데이터의 은닉에 포커스가 맞춰져있다면,
추상화는 클래스를 사용하는 사람이 필요하지 않은 메소드 등을 노출시키지 않고, 단순한 이름으로 정의하는 것에 포커스가 맞춰져 있다
클래스 정의 시, 메소드와 속성만 정의한 것을 인터페이스라고 부르고 이것이 추상화의 본질이다
객체 역시 똑같은 메소드라 하더라도, 다른 방식으로 구현될 수 있다
비슷한 오브젝트를 많이 만들어서 사용할 때 사용한다
일반 함수와 다르게 대문자와 일반명사, new 키워드를 사용한다
사람의 데이터를 쭉 나열할 때
let person = {
name : 'kim',
age : 25,
say(){
console.log(`${this.name}의 나이는 ${this.age}살 입니다`)
}
}
constructor 문법 사용
문자 함수 다 넣을 수 있다
// this 는 새로 생성되는 object를 의미한다
// 새로 생성되는 object의 name 속성에는 이름 파라미터 값을 넣어준다
function Group(이름, 나이){
this.name = 이름
this.age = 나이
this.say = function(){
console.log(`${this.name}의 나이는 ${this.age}살 입니다`)
}
}
new Group(); // {} 하나의 object 가 남는다
// 상속 : person1, person2(자식)가 Group(부모)이 가진 속성들을 물려받음
// 사용할때는 변수에 할당해서 사용한다
let person1 = new Group('kim', 25); // Group {name : 'kim', age : 25}
let person2 = new Group('lee', 20); // Group {name : 'lee', age : 20}
person1.say(); // kim의 나이는 25살 입니다
상속을 구현할 수 있는 또 하나의 문법
function constructor 문법을 사용하면 prototype 이라는 공간이 자동으로 생긴다
prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다
Group.prototype
// {constructor :f}
function Group(이름, 나이){
this.name = 이름
this.age = 나이
this.say = function(){
console.log(`${this.name}의 나이는 ${this.age}살 입니다`)
}
}
Group.prototype.gender = '여';
let person1 = new Group('kim', 25); // Group {name : 'kim', age : 25}
let person2 = new Group('lee', 20); // Group {name : 'lee', age : 20}
person1.gender // '여'
// 부모의 값에 지정되어 있어서 person1 값에 나오지 않아도 사용할 수 있다
prototype의 동작원리
자바스크립트에서 person1.gender 값을 출력할때
1. person1 이 직접 gender 값을 갖고있는지 보고 없으면
2. person1 의 부모 유전자가 gender 값을 가지고 있는지 확인해서 사용한다
prototype의 특징
person1.__proto__ // {gender : '여', constructor :f}
__proto__
를 이용해서 부모유전자 강제 등록하기let 부모 = { name : 'kim' };
let 자식 = {};
자식.__proto__ = 부모
자식.name; // 'kim'
Object.create(물려받을 부모 object);
let 부모 = { name : 'kim', age : '50'}
let 자식 = Object.create(부모);
// prototype 을 부모로 지정
자식 // {}
자식.name // 'kim'
자식.age // 50
//자식의 값을 변경하고 싶을때
자식.age = 20;
자식 // {age : 20}
자식.age // 20
// 1차로 직접 값을 가지고 있는지 자식에게 물어보고
// 2차로 부모에게 물어보기 때문에 자식값이 나온다
class 부모 {
constructor(){
this.name = 'kim'
// 1. 함수 추가방법
// 자식이 직접 함수를 가진다
this.sayHi = function(){console.log('hello')}
}
// 2. 함수 추가방법
// 부모.prototype에 추가된다
sayHi(){
console.log('hello')
}
}
let 자식 = new 부모()
console.log(자식) // 부모 {name : 'kim'}
유사한 클래스를 하나 더 만들고 싶을때 사용한다
super() : 물려받는 class의 constructor
class 아빠 {
constructor(name){
this.성 = '박';
this.이름 = 'name';
}
sayHi(){
console.log('hi')
}
}
// 아빠의 속성을 그대로 물려받은 클래스를 만들고 싶을 때
class 아들 extends 아빠 {
constructor(name){
super(name);
this.나이 = 20;
}
}
// ectends 로 만든 class는 this를 바로 쓰지 못하고
// super() 다음에 써야 한다
let 아들1 = new 아빠('명수');
// 아빠 {성 : '박', 이름: '명수', 나이: 20}
아들1.sayHi()
// hi
참고자료
생활코딩 객체지향프로그래밍