코드스테이츠 프리과정 중 객체에 대해서 배우다 이런 질문을 한 적 있다.
객체 지향 프로그래밍이라는 말을 많이 하시던데,
그 오브젝트가 이 오브젝트인가요? 모든 프로그래밍을 객체 중심으로 한다는 건가요?
당시 강사분은 반은 맞고 반은 틀리다는 이야기를 하시며 이머시브 과정을 기약하셨다.
그리고 이머시브 두 번째 스프린트를 마치고, OOP 스프린트를 시작하게 되었다.
MDN은 OOP에 대해서 다음과 같이 설명한다.
객체지향 프로그래밍은 실제 세계에 기반한 모델을 만들기 위해 추상화를 사용하는 프로그래밍 패러다임이다. 객체지향 프로그래밍은 함수들의 집합 혹은 단순한 컴퓨터의 명령어들의 목록 이라는 기존의 프로그래밍에 대한 전통적인 관점에 반하여, 관계성있는 객체들의 집합이라는 관점으로 접근하는 소프트웨어 디자인으로 볼 수 있다. 객체지향 프로그래밍에서, 각 객체는 메시지를 받을 수도 있고, 데이터를 처리할 수도 있으며, 또다른 객체에게 메시지를 전달할 수도 있다. 객체는 별도의 역할이나 책임을 갖는 작은 독립적인 기계로 볼 수 있는 것이다. (생략)
OOP에 대한 내 첫 질문 객체를 중심으로 프로그래밍을 하는 것인가는 반정도 맞았다. 틀린 반은 Object에 대한 이해다. 오브젝트는 단순히
타입의 형태가 아니라, things를 의미한다. 사실 프로그래밍 언어도 번역되는 과정에서 일본이라는 한 다리를 거쳤는데, 일본의 용어를 그대로로 사용하다보니 Object를 객체라고 사용하게 되었다고 한다. 거 참 이 이야기를 여기서도 듣네, 일본을 거친 학문들은 어쩔수없나보다...
무튼, 모든 프로그램을 구성하는 요소가, Object기반이 될 수 있도록 의도하는것이 바로 OOP이며, 하나의 라이브러리나, 특정 언어를 지칭하는것이 아니라, 프로그래밍이라는 세계에서 하나의 철학을 의미하는 단어다.
자바스크립트는 본디 OOP를 추구하는 언어는 아니었으나, ES6 이후 클래스를 도입하면서 OOP를 추구하고 있다.
OOP의 핵심개념은 Class다.

위 그림과 같이, 클래스는 oop에서 특정 object를 생성하기 위해 변수와 메소드를 정의하는 청사진이다. 즉 클래스는 OOP에서 객체를 생성하기 위한 청사진이라고 볼 수 있다.
Class를 통해 거푸집을 만들고, 세부사항을 입력해 각각의 정보를 담고 있는 Object Instance를 생성한다. 강의를 들으면서도 이게 뭐지...했는데 사실 생각해보며 이미 Data Structure 스프린트를 진행하며 클래스를 수도 없이 사용하고 있었다.
class TreeNode {
constructor(value) {
this.value = value;
this.children = [];
}
let new Node = new TreeNode(value);
거푸집을 포함한 프로토타입의 클래스를 생성하고, new 키워드를 통해 새로운 Object를 생성하는 과정을 통해 이 과정을 익숙하게 사용하고 있었다.
따라서 객체 지향 프로그래밍은 메모리에 할당된 인스턴스인 객체를 만들어 각자의 객체가 메세지를 주고받고 데이터를 처리하게 프로그래밍 하는 패러다임을 객체 지향 프로그래밍이라 할 수 있다.
Class : class는 object를 생성하기 위한 거푸집, 청사진
Object : OOP 에서 class로 구현된 모든 대상을 의미
Instance : class를 기초로 구현된 실체. 이 instance는 메모리에 할당되고, 클래스에서 구현된 속성과 메소드를 가진다.
OOP가 추구하는 basic Concepts과 Benefits은 다음과 같다.
Encaptulation은 우리말로 캡슐화다. 연관된 데이터와 함수를 논리적으로 묶는 것이며,
추가적으로 데이터를 보호하기 위해 다른 객체의 접근을 제한하는 기능을 하기도 한다.(정보 은닉)
]
Inheritance(상속)은 절차 지향과 객체 지향의 가장 큰 차이다. 프로그래밍에서 상속은 부모의 특징을 물려받는것을 의미한다.
클래스의 기능과 특성을 그대로 물려받기 때문에, 기존 코드를 재활용할 수 있다.

사용자 입장에서 구조를 사용하기 간단하게 이루어지도록 만들어준다고 이해할 수 있을 것 같다. 우리가 사용하는 다양한 기계의 내부는 복잡하게 이루어져있겠지만, 사용자 입장에서는 기계가 요구하는 몇 가지 요소를 입력하면 중간 중간 과정에 대해 신경쓰지 않고 결과값을 얻어낼 수 있다. 추상화는 따라서, 간편화시킨다는 말로 이해할 수도 있다.
Polymorphism은 다향성을 의미한다. 상속과 연관되는 부분이다. 한 부모를 가진 다양한 자녀들은 각자의 특징에 따라 서로 다른 특성을 가져야할 경우가 있다. 아래의 경우처럼.

상위 클래스에서 물려받은 메소드가 있어도, 자신에게 필요한 특성이 있다면, 자신의 특징에 맞게 다시 구현(Overwriting)할수있다.
만약 다향성이 없다면

이 꼴이 나겠지..
함수를 선언하고 함수 내에서 오브젝트 값을 담아 출력하는 방법.
: 인스턴트를 생성할 때 마다 모든메소드들을 output에 할당해야하기때문에 메모리를 많이 차지한다.
let Cat = function(name, bDay) {
let output = {}; // 리턴할 결과물인 객체 선언
output.name = name; // property
output.bDay = bDay;
output.status = function(){
console.log(`${this.name}는 사랑스러워요.`)};
return output;
}
let dddung = Cat('뚱이',0423);
객체 메소드를 하나만 생성하고, 생성되는 객체는 객체 메소드를 참조해 메모리 효율을 향상시킬 수 있다.
let extend = (to, from) => {
for (let key in from) {
to[key] = from[key];
}
}
let method = {};
method.status = function() {
console.log(`${this.name}는 사랑스러워요.`)
};
let Cat = function(name, bDay) {
let output = {}; // 리턴할 결과물인 객체 선언
output.name = name; // property
output.bDay = bDay;
extend(output, method);
return output;
}
let dddung = Cat('뚱이',0423);
Object.create()로 특정 객체를 프로토타입으로 삼는 객체를 생성할 수 있다.
let method = {};
method.status = function() {
console.log(`${this.name}는 사랑스러워요.`)
}
let Cat = function(name, bDay) {
let output = Object.create(method); // 리턴할 결과물인 객체 선언
output.name = name; // property
output.bDay = bDay;
return output;
}
let dddung = Cat('뚱이',0423);
:가장 많이사용하는 방식!
let Cat = function(name, bDay) {
this.name = name; // property
this.bDay = bDay;
}
Cat.prototype.status = function () {
console.log(`${this.name}는 사랑스러워요.`)
}
let dddung = new Cat('뚱이',0423);
자바스크립트는 프로토타입 기반의 언어다. 프로토타입은 '원형'이라는 뜻으로, 자바스크립트에서 모든 object는 위에서 설명한 것 처럼,
자신의 근원인 '원형'을 가지고 있다. 프로토타입을 기반으로 생성된 Instance는 자신의 Constructor Class가 가지고 있는 속성을 물려받아 사용할 수 있는데, 이를 바로 '프로토타입'의 속성을 사용하는것이라고 볼 수 있다.
let a = [];
console.dir(a)

임의로 생성한 빈 어레이는 당연히 Array method를 사용할 수 있다. 이유는 임의의 어레이 a가 자바스크립트에 내장된 array 컨스트럭터를 기반으로 생성되었기 때문이다. 그리고 다시 Array는 프로토타입으로 자바스크립트의 Object로 가지고 있다.
다음과 같이...
여기서
__proto__ 는 해당 인스턴스가 원형으로 삼고있는 Prototype이 무엇인지, 그리고 내재한 Method에 대해서 서술한다.
그렇다면, 상속을 어떻게 구현해야할까?
Array method에 slice()를 통해 배열을 복사할 수 있는 것 처럼, Object.create(arg)는 arg 를 프로토타입으로 갖는 요소를 만들어준다.(위 3번처럼) 다만, 이렇게 prototype을 할당해버리면, 프로토타입간 같은 메모리 주소를 가리키게 되기 때문에, 상위 constructor를 다시 설정하고, 해당 메소드도 다시 정리해야 한다. 또한 context가 저장되지 않기 때문에, call이나 apply를 통해서 this를 다시 정의해야 한다.
그래서 나타난 ES6를 사용한 클래스 사용 방법! class라는 키워드를 통해 새로 클래스를 만들 수 있다. 클래스를 선언하고, 내부 constructor를 작성한다. 그리고 다시 만들고자 하는 하위 요소는 extends를 통해 메소드를 상속받는것이 가능하다. 또한 이때, 'super'라는 요소로 상위 요소를 가르킬 수 있다.
: ES6에서 새로 생긴 방법, 데이터 스트럭처 과제에서 사용
class Cat {
constructor(name, bDay) {
this.name = name;
this.bDay = bDay;
}
status() {
console.log(`${this.name}는 사랑스러워요.`)
}
}
class fatCat extends Cat {
constructor(name,bDay) {//상위 컨스트럭터와 구조가 같다면 생략 가능하다.
super(name,bDay);
}
status(){
console.log(`${this.name}는 살을 빼야 합니다.`)
}
}
let dddung = new fatCat('뚱이',0423);