Object Oriented Programming (객체 지향 프로그래밍) 는 프로그램 설계 방법론의 일종이다.
프로그래밍 할 때 프로그램을 단순히 데이터와 처리 방법으로 나누는 것이 아닌
객체
라는 단위로 나누고 이를 서로 상호작용할 수 있게 만들어 역할을 수행 할 수 있게 만든다.
그래서 이를 사용하기 위해 다른 언어에서는 Class
라는 문법을 제공하고 있는데
물론 Class
가 없다고 객체가 아닌 것은 아니다.
Javascript 에서는 Prototype
을 사용하여 객체를 표현하고
C Language 와 Golang 에서는 struct(구조체)
를 사용해서 객체를 표현한다.
그리고 이러한 객체 지향 프로그래밍에서 4가지의 특징이 있다.
캡슐화 (Encapsulation)
변수와 함수를 하나로 묶고 필요에 따라 접근 권한을 나누어 외부에서 함부러 접근하지 못하게 제한을 두어 객체의 손상을 방지한다.
이에 따라 내부 구현 내용을 감추어 외부에서 확인 할 수 없도록 정보 은닉
도 포함되게 된다.
추상화 (Abstraction)
객체들이 사용하는 공통적인 변수와 함수들을 따로 묶는 것
을 말한다.
예를 들어 말, 강아지, 고양이가 존재한다고 치면
이 3가지의 동물들이 공통적으로 수행하는 행동 중 숨쉬기, 걷기, 달리기 등등이 있을 것이고
다리 개수, 성별 등 공통 적으로 가지고 있는 특징들도 있다.
이렇게 공통적인 행동과 특징들을 가지고 하나의 객체를 정의 하는 과정
을 추상화로 볼 수 있다.
상속 (Inheritance)
자식 객체가 부모 객체의 변수와 함수를 그대로 물려 받을 수 있는 것
을 뜻한다.
예를 들어 동물이라는 객체에 달리기, 숨쉬기 함수가 있다면
강아지, 고양이 객체를 만들 때 동물 객체를 상속 받아
강아지, 고양이 객체에서는 달리기, 숨쉬기 함수를 따로 구현하지 않고
동물 객체의 달리기, 숨쉬기 함수를 쓸 수 있다.
다형성 (Polymorphism)
같은 객체임에도 상황에 따라 다르게 동작 할 수 있는 것을 뜻한다.
오버로딩 (Overloading) 이나 오버라이딩 (Overriding) 같은 것을 사용하여 객체를 상황에 따라 다르게 사용 할 수가 있는 것이다.
int sum(int n1, int n2) {
return n1 + n2;
}
int sum(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
class Person {
eat() {
console.log("밥 먹을거야");
}
}
class Kim extends Person {
eat() {
console.log("난 밥 싫어 라면 먹을거야");
}
}
let kim = new Kim();
kim.eat(); // 난 밥 싫어 라면 먹을거야
사실상 함수 내부에서 오브젝트에 값을 다 담아서 반환해주는 것과 같다
let Person = function(name, age) {
let obj = {};
obj.name = name
obj.age = age
obj.print = function() { console.log(this.name + " " + this.age); }
return obj;
}
var lee = Person("Lee", 24);
lee.print(); // Lee 24
객체 메소드를 하나만 생성해주고 생성되는 객체에서는 생성된 객체 메소드를 참조하여
메모리 사용 효율을 높인다.
let extend = (to, from) => {
for(let key in from) {
to[key] = from[key];
}
}
let method = {};
method.eat = function() {
console.log(`난 ${this.myfood}를 먹을거야`);
}
let Person = function(food) {
let obj = { myfood: food };
extend(obj, method);
return obj;
}
let my = Person("Apple");
my.eat(); // 난 Apple를 먹을거야
Object.create
를 사용하면 특정 객체를 프로토타입으로 하는 객체를 생성 할 수 있다.
let method = {};
method.eat = function() {
console.log(`난 ${this.myfood}를 먹을거야`);
}
let Person = function(food) {
let obj = Object.create(method);
obj.myfood = food;
return obj;
}
let my = Person("Apple");
my.eat(); // 난 Apple를 먹을거야
아마 이 방법이 일반적으로 많이 사용하는 Class를 생성하는 방법일 것이다.
다만 위와 방법과 다른 점은 new 키워드를 사용해서 객체를 생성해야 한다.
let Person = function(food) {
this.myfood = food;
}
Person.prototype.eat = function() {
console.log(`오늘은 ${this.myfood}으로 먹어볼까?`);
}
let my = new Person("볶음밥");
my.eat() // 오늘은 볶음밥으로 먹어볼까?
Javascript에서의 프로토타입은 무엇일까?
뜻을 찾아 보게 되면 일반적인 의미로 원형
이라는 뜻을 가지고 있다.
이것을 객체에 의미를 부여해보면 객체의 원형
즉 자신을 만들어낸 객체의 원형
을 뜻한다.
또한 자신을 만들어낸 객체의 원형
이 있다면 객체의 원형에서 만들어질 객체
도 있지 않은가?
그래서 객체의 원형에서 만들어질 객체
는 자신을 통해서 만들어질 객체의 원형
의 뜻도 지닌다.
그리고 Javascript에서는 이러한 프로토타입을 표현하는 용어가 있다.
이러한 용어를 이해하기 위한 예를 보자
function Person() {}
console.dir(Person);
그리고 여기서 prototype
속성과 __proto__
속성을 확인 할 수가 있다.
해당 속성에 내용은 직접 확인해 보도록 하고 이들의 관계에 대해서 알아보자.
이들의 관계에 대해서 표로 표시하자면 아래 이미지와 같다.
[출처 : https://mygumi.tistory.com/312]
표에 나온 용어들이 무엇을 나타내는지 정리 해보자.
__proto__
: 자신을 만들어낸 객체의 원형constructor
: 생성자를 뜻하며 자신을 만들어낸 객체prototype
: 자신을 원형으로 만들어진 새로운 객체__proto__
속성은 Prototype Link
로 연결되어 자신을 만들어낸 객체를 연결 시키고
constructor
속성은 Prototype Object
로 연결되어 자신을 만들어낸 객체에 연결 시키고
prptotype
속성은 Prototype Object
로 연결되어 자신이 만들어 낸 새로운 객체에 연결 시킨다.
그리고 Prototype Object
는 생성 당시에 객체가 가진 정보를 토대로 새로운 객체를 생성한다.
예를 들면
let My = function(name) {
this.name = name;
this.show = function() { console.log("First " + this.name); }
}
My.show = function() { console.log("Second " + this.name); }
let my = new My("Lee");
my.show() // "First Lee"
해당 코드처럼 중간에 Second로 변경 해주었지만 그대로 First로 나오는 것을 확인 할 수 있다.
이는 My 객체의 Prototype Object가 My 객체 생성 당시의 정보인 show를 복제 하기때문에
My 객체를 이용해서 새로 만든 객체의 경우 First를 출력하는 show 메소드가 그대로 복제 된것이다.
Javascript는 Class
라는 개념이 존재 하지 않는다.
물론 최근에는 Class
라는 키워드가 추가되어 클래스처럼 표현 할 수 있지만
이는 문법만 매핑 해준 것이고 동작 방법은 프로토타입을 활용하여 객체를 생성하는 것과 같다.
따라서 결과적으로 프로토타입의 사용 이유는
Javascript는 Class
라는 개념이 존재 하지 않기 때문에 프로토타입
이라는 객체를 활용하여
이를 Class
처럼 표현하기 위해 사용한다고 볼 수 있다.
Javascript에서는 함수를 이용해서 클래스를 구현했었지만
ES6에서 Class 키워드를 지원해서 해당 문법을 이용해서 클래스같은 클래스를 만들 수 있다.
let Person = function(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.show = function() {
console.log(`Hello My name is ${this.name}, My age is ${this.age}`);
}
let person = new Person("Lee", 24);
person.show(); // Hello My name is Lee, My age is 24
//////////////////////////////////////////////////////////////////////
// TO CLASS
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
show() {
console.log(`Hello My name is ${this.name}, My age is ${this.age}`);
}
}
let person = new Person("Lee", 24);
person.show(); // Hello My name is Lee, My age is 24
이렇게 Person Class를 만들 수 있으며
constructor
는 생성자 함수로서 객체의 변수를 초기화 하는 함수이다.
그외에 코드에서 볼 수 있는 것은 함수를 작성 할 때 따로 function
키워드를 작성하지 않아도 된다.
그다음엔 상속을 해보자.
class Animal {
constructor(name) {
this.name = name;
}
whois() {
console.log(`My name is ${this.name}.`);
}
}
class Cat extends Animal {
constructor(name) {
super(name);
}
}
let myCat = new Cat("Bab");
myCat.whois(); // My name is Bab.
Class
키워드를 사용하여 상속을 할 때에는 extends
키워드를 쓴 다음 상속할 클래스 이름을 적는다.
그리고 자식 클래스의 생성자에서 super
키워드를 써서 부모 클래스 호출한다.
이러한 과정을 거쳐 부모 클래스의 내용을 자식 클래스가 상속받아 사용 할 수 있다.
이 글이 올라오기만을 기다렸습니다... 지식도둑질 해야지