JavaScript 에서의 객체지향
프롤로그
- 프로그래밍 세계에서 무언가를 학습하기 위해서는 그 이론 자체를 이해하기보다는 먼저 그 기술이 나오게 된 배경을
이해하는 것이 더 중요합니다. 그래야 새로운 변환점을 맞이했을 때 맥락에 맞게 내 것으로 만드는 것이 쉬워지기
때문입니다.
- 프로그램 뿐 아니라 기술의 발전은 대략 다음과 같은 사이클로 돌아가게 됩니다.
1. 문제 인식
- 프로그램을 하다 보면 누구나 한 번쯤 겪을 법한 문제들이 쌓이기 시작하는 단계입니다.
- 이 때 문제를 해결하기 위해 저마다 여러가지 해법들을 찾아보게 됩니다. 문제는 인식하여 공감대는 형성되었지만
이 문제를 해결하기 위한 최선의 방법은 아직 등장하지 않은 시기입니다.
2. 명명된 새로운 기술의 등장.
- 여러가지 해법들이 쌓여가다 보면 모두가 합의할만한 이론이나 기술이 등장하게 되고 이러한 문제 인식과 해법에
대해 이름이 붙여지는 시기입니다. 그리고 이로 인해 대부분의 사람들이 명확하게 이 문제와 해결 방법에 대해서
인식을 하게 됩니다.
- 여기서 중요한 사실은 이미 대부분의 컨텍스트와 해결 방법은 나온 상태에서 이것들에 대해 정리된 이론이나 개념들은
나중에 이름이 붙여진다는 사실입니다. 이 때 보통 패러다임이 전환되었다고 한다.
3. 기술의 부흥
- 이러한 패러다임의 전환으로 이론과 개념들 그리고 문제 해결 방법이 정립되고 나면 이후 발생하는 모든 문제들은
새로운 시각인 이 방법을 가지고 해결해보려는 시도들이 발생하게 됩니다.
- 그러면서 기술이 폭발적으로 성장하는 시기를 겪게 됩니다. 기존의 문제들이 세련된 형태로 해결이 되며 이 기술을
당연한 것으로 배우게 되는 시기입니다.
4. 안정기 ( 혹은 정체기 )
- 페러다임 전환으로 폭발적인 변화의 시기를 통해 성장을 하고 나면 새로운 한계점을 마주하게 됩니다.
- 기존의 방식으로 만들어진 문제점들이 그 패러다임으로 해결되지 않는 문제가 발생하며 기존 방식으로 해결하려다
보면 굉장히 복잡해진다는 사실을 알게 됩니다. 이러면서 문제 인식을 다시 가지게 되고 첫 번째 시기로 돌아가
기술 발전의 사이클이 돌게 되는 것입니다.
- 대부분의 기술 발전은 위와 같은 사이클을 가지게 되어 있습니다.
- 우리가 프로그래밍을 하다보면 만들어지는 개념들이나 배워야 하는 것들은 대부분 세 번째 시기에 만들어지는
응용법들을 배우고 학습하게 됩니다.
- 이러한 맥락과 해결방법은 자연 발생한 결과물인데, 이러한 결과물에 이름을 붙이고 이론을 다듬는 과정에서
만들어진 생소한 용어와 정의 그리고 개념은 그 맥락없이 이해하려면 상당히 어렵습니다.
결국 기술이란 지난 문제들을 해결하기 위해서 만들어졌기 때문에, 왜 이런 기술이 필요했고 어떤 발전
과정을 거쳤는지 파악한다면 새로운 용어에 대한 정의나 개념의 이해가 더 쉽게 될 것입니다.
객체 지향 이전의 이야기
- 객체지향 패러다임이 존재하기 전으로 가보자.
- JavaScript에서 Object를 사용하지 않고 boolean, string, number ,if, for, while 만으로 개발한다고 상상해 보자.
1. 순차적 프로그래밍과 goto
- 완전 초창기 프로그래밍에서 프로그램은 순서대로 실행되었습니다.
- 지금도 프로그래밍을 하다보면 그 전에 만들어 둔 것과 같은 반복적인 동작이 필요하다는 것을 알게 됩니다.
for이나 while과 같은 반복문이 존재했지만 일부 반복의 범위가 코드를 다시 실행 해야 할 경우가 발생했고 함수라는
개념이 없던 시절에는 특정 위치로 실행 순서를 강제로 변경하는 goto문을 만들어내게 됩니다.
- 이렇게 강제로 실행 순서를 바꾸다 보니 코드가 커지며 코드의 흐름을 제어하기가 힘들어지게 되었습니다.
var hp = 100
var mp = 100
gameloop:
...
if (key == 'A') {
goto magic
}
...
goto gameloop
magic:
mp -= 10
...
goto gameloop
2. 절차적 ( 구조적 ) 프로그래밍
- 이 후 실행 순서를 강제로 바꾸는 것이 아니라 일정하게 반복되는 코드를 따로 만들어주고, 그에 해당하는 코드를
호출하고 나서 다시 원래 자리로 돌아오는 방식의 프로시저 ( 함수 )를 통해 개발하는 절차적 프로그래밍 패러다임이
탄생하게 되며 지금의 함수와 같은 개념이 생겨나게 되었습니다.
=> 즉 절차적 프로그래밍은 데이터와 데이터를 처리하는 동작을 함수 단위로 코드를 분리하고 재사용하는 형태로
프로그래밍하는 방식이 됩니다.
※ 언제나 문제는 코드의 덩치가 커질 때 발생한다.
- 패러다임의 한계는 프로그램의 덩치가 커져야 알 수가 있게 됩니다. 이러한 방식으로 코드가 커지게 되면 다음과
같은 문제가 발생하게 되었습니다.
- 기본적으로 절차적 프로그래밍은 전역 변수의 형태로 만들었습니다. 그러다 보니 프로그램의 덩치가 커질수록
변수에 같은 이름을 쓸 수가 없게 됩니다.
- 그러다 보니 변수명 관리가 굉장히 복잡해지게 됩니다.
이름 앞에 foo_x, foo_y, bar_something과 같이 prefix가 늘어만 가고 매번 이렇게 prefix를 붙이지 않고 하나의
파일 단위 혹은 모듈 단위로 prefix를 부여해서 관리하는 namespace ( 네임 스페이스 ) 라는 방식이 등장합니다.
3. 데이터를 묶어서 관리해보자 => 구조체!
- 하지만 naespace 만으로는 비슷한 형태의 데이터들을 쉽게 다루기 쉽지 않았습니다.
가령 게임을 만든다고 가정해 본다면 하나의 캐릭터에 속해있는 이름, hp, mp, item 등 구조의 형태를 가지는
변수를 만들기 위해서는 여전히 prefix를 붙여 만들어야 했습니다.
var character1_name = "teo.yu"
var character1_hp = 300
var character1_mp = 500
function character1_useSkill() {
...
character1_mp -= 100 // 변수를 직접 수정하게 됨.
}
character1_do_somthing()
- 위와 같은 프로그래밍을 하게 될 경우 캐릭터가 2 ~ 3개만 되어도 코드들의 중복될 내용이 많을 것 입니다.
- 그래서 연관이 있는 데이터들을 하나로 묶어 namespace 처럼 관리하여 해당 변수에 접근할 수 있는 구조체라는
형식을 생각하게 됩니다.
// struct
// (사실 구조체는 엄밀히 말해 하나의 Type인데 js라서 그냥 이렇게 쓰겠습니다. 찰떡같이 이해해주세요.)
var character = {
name: "teo.yu"
hp: 300
mp: 500
}
function useSkill(character) {
...
character.mp -= 100 // 변수를 직접 수정하게 됨.
}
do_somthing(character)
- 의미 있는 단위로 변수들을 하나로 묶음으로써 변수 명의 중복을 줄이고 함수나 배열 등에서도 하나의 변수처럼 활용
할 수 있게 됩니다.
- 이렇게 코드가 덩치가 커지더라도 일관성을 유지하며 코드를 짤 수 있게 됩니다.
객체 지향 프로그래밍의 등장
- 구조체가 생기면서 산재해 있는 데이터들을 의미 있는 데이터로 구조화시켜서 프로그래밍하니 동작보다는
데이터를 중심으로 코딩하게 되면 코드의 덩치가 커져도 일관성을 유지하기 좋다는 것을 깨닫게 됩니다.
- 그러면서 코드를 한 데 모으다 보니 다음과 같은 패턴이 자주 만들어진다는 것을 깨닫게 됩니다.
// struct
var character = {
name: "teo.yu"
hp: 300
mp: 500
}
function character_attck(character) {...}
function character_useSkill(character) {...}
function character_moveTo(character, toX, toY) {...}
- 위와 같이 특정 구조체만 가지고 동작을 하는 함수 군들이 만들어진다는 것을 알게 되었고 함수 역시 전역
네임스페이스를 사용하다 보니 character_와 같은 prefix를 달아야 한다는 것을 알게 되었습니다.
1. 구조체에 항상 쓰이는 함수들도 하나로 합치는 것은 어떨까? => Class
- 그래서 구조체와 항상 쓰이는 함수들을 하나로 묶어서 구조체와 함께 함수까지 포함하는 개념을 만들게 되고
이것을 class라고 불렀습니다.
struct + function (struct, ... ) = class
( 구조체 + 구조체를 항상 인자로 가지는 함수 = 클래스 ! )
// class
class Character {
name = "teo.yu"
hp = 300
mp = 500
attck() {...}
useSkill() {...}
moveTo(toX, toY) {...}
}
// object
var character = new Character();
character.attck();
character.useSkill()
character.jump();
- 이렇게 만들고 보니 기존의 데이터와 처리방법을 분리해서 개발하던 절차식 프로그래밍과 달리 데이터와 처리 방식이
하나의 모듈로 관리되면서 마치 작은 프로그램들이 독립적으로 돌아가는 형태를 띄게 되어 덩치가 큰 프로그래밍을
작성하더라도 작은 부품들을 미리 만들어두고 이를 조립하는 결합하는 방식으로 개발할 수 있다는 것을 알게 됩니다.
- 그래서 이러한 부품을 만드는 설계도를 만들어 두고 공장에서 찍어내듯 부품을 만들고 이것들을 조합하는 것과 같은
개념으로 Class와 Object가 등장을 하게 됩니다.
- 기존의 구조체와 함수를 합쳐서 선언하는 것을 Class라 부르기로 했고 Class를 통해 만들어진 결과물을
값과 동작을 함께 가지고 있는 것이 주위 사물과 유사하다고 하여 Object라고 부르기로 했습니다.
- 이런 식으로 작은 문제를 해결하는 것들을 모아서 하나의 문제를 해결하는 프로그램으로 개발하는 방식을
Bottom-Up 방식이라고 합니다.
- 작은 문제를 해결하는 독립된 객체를 먼저 만들고 조립하자는 개발 방식은 다음과 같이 개념이 확장됩니다.
프로그램은 모두 객체로 만들어져 있고 객체들 간의 메시지를 주고받는 상호작용으로 이루어진다.
- 이렇게 프로그램을 객체로 바라보는 관점으로 프로그래밍하는 것을 Object-Oriented Programming (OOP )
객체지향 프로그래밍 이라고 부르게 되었습니다.
자바스크립트에서 객체 지향을 하는 게 맞나요? | 요즘IT
이번 글에서는 객체지향 프로그래밍에 대해 이야기를 해보려고 합니다. 그리고 자바스크립트의 객체지향은 일반적인 객체지향 프로그래밍과는 어떻게 다른지 그리고 Javascript에서는 객체지향
yozm.wishket.com