섹션 18. 객체지향 - 객체지향 프로그래밍 소개
1강. 객체지향 프로그래밍 오리엔테이션
1) 객체지향 프로그래밍(OOP, Object-Oriented Programming)
- 좀 더 나은 프로그램을 만들기 위한 프로그래밍 패러다임
- 로직을 상태(state)와 행위(behave)로 이루어진 객체로 만드는 것
2) 핵심 : 객체(Object)
- 객체는 레고블록처럼 객체+객체로 조립해서 프로그램을 만들 수 있다.
- 이런 기법을 OOP라고 한다.
- 프로그램이 커지면서 발생하는 막장을 해결하기 위해 Grouping, Categorizing이 쓰이는데, 그룹핑된 하나하나의 단위들을 객체라고 생각하면 된다.
- 객체끼리 구획화시키고 분류해서 생각한다.
- 재활용성에 객체가 기여한다.
- 여기서 쓰던걸 저기에 쓰니 여러 문제가 발생하는데, 이를 해결하기 위해 제공하는 기능들이 많다.
객체라는 것을 너무 어렵게 생각할 필요 없이 기능단위로 껍데기를 씌워서 한 덩어리로 만들어 놓은 것이라고 생각하면 된다.
2강. 추상화
1) 문법
객체지향을 편하게 할 수 있도록 자바스크립트에서 제공하는 기능을 알아야 한다.
if, for문과 같은 문법적 구성을 가지고 있다.
2) 설계
현실을 잘 담아내는 소프트웨어를 만드는 것이 어렵다.
현실에서 우리가 관심 있는 특성이나 관점을 소프트웨어화 시켜서 문제를 해결하는 것이 프로그래밍이다.
현실은 복잡하고 소프트웨어는 단순하다.
추상화, abstract
- 반영해야 할 현실을 소프트웨어적으로 단순화해서 만든 행위
ex. 지하철 노선도에서는 목적지까지 가려면 몇 개의 역과 어디서 환승해야 되는지의 정보만 알면 된다. 역간 거리, 높낮이 등의 정보는 필요 없다. 즉, 최소한의 정보를 남기고 단순화한 것이 지하철 노선도라고 볼 수 있다.
설계 : 현실을 추상화하는 과정
3강. 부품화
1) 부품화
좋은 객체를 만든다 = 다른 곳에서 활용이 가능하도록 부품화한다.
객체지향은 부품화의 정점이라고 할 수 있다.
옛날 컴퓨터는 모든 부품이 한 덩어리 었지만, 지금 PC는 여러 부품의 조합으로 이뤄져 있다.
하지만, 맥 PC의 경우에는 모니터와 본체가 한 덩어리가 되었다.
설계가 어려운 점이 이것이다. 적절한 부품화를 통해 재활용성을 높이되, 그 수준이 적당히 조화를 이뤄야 한다.
2) 은닉화(Information Hiding), 캡슐화(Encapsulation)
좋은 부품 : 어떻게 만들어졌는지 모르는 사람도 그 부품을 쓰는 방법만 알면 된다.
내부의 동작 방법을 단단한 케이스(객체) 안으로 숨기고, 사용자에게는 그 부품의 사용방법(메서드)만 노출하면 된다.
3) 인터페이스(interface)
모니터가 고장 났을 때, 모니터만 바꿀 수 있는 이유는 모니터별 규격화가 되어있기 때문이다.
다른 표준의 모니터를 연결하려고 하면 물리적으로 다르게 만들어서 꽂아지지 않게 만든다.
결합조차 되지 않게 강제하는데, 이런 연결점을 인터페이스(interface)라고 한다.
소프트웨어라고 하는 것도 하드웨어와 다르지 않다.
차이점 : 복제, 상속
차이점이 있기 때문에 모두 같다는 생각은 하지 않는 것이 좋다.
섹션 19. 객체지향 - 생성자와 new
1강. 자바스크립트의 객체지향
1) 객체
서로 연관된 변수와 함수를 그룹핑한 그릇이다. 객체 내의 변수를 프로퍼티(property), 함수를 메서드(method)라고 부른다.
자바스크립트 계열 언어들은 prototype-based programming이라고 불리기도 한다.
2) 객체지향의 기본적 형태
연관되어 있는 변수와 메서드를 객체라고 하는 그릇에 넣고, 연관되지 않는 것들은 별도의 객체에 분리를 시켜놓는다. 연관되어 있는 것을 categorizing 한다는 것. 각각의 객체는 독립성을 갖고 있다. 이 말은, 여러 완제품의 부품으로 사용될 수 있다는 것이다. 좋은 부품을 만드는 것이 객체지향을 향하는 길이다.
2강. 객체 생성
객체를 만드는 가장 보편적인 방법
{ } : 비어 있는 객체를 만듦. Object라는 이름의 Object를 만드는 것
변수.name
객체에 담겨있는 변수를 속성(property)이라고 한다.
var person = {}
person.name = 'egoing';
person.introduce = function(){
return 'My name is '+this.name;
}
document.write(person.introduce());
위의 코드는 var person에서 정의한 객체와 아래의 변수와 속성들이 따로 떨어져 있다.
그래서 중간에 무엇이 껴들어가면 코드가 망가질 수 있기 때문에 { } 사이에 변수와 속성들을 담는다.
var person = {
'name' : 'egoing',
'introduce' : function(){
return 'My name is '+this.name;
}
}
document.write(person.introduce());
중괄호 사이에 프로퍼티와 메서드를 담아준다.
그러면 가독성도 좋고, 중간에 무엇이 끼어들어서 변조되는 것을 막을 수 있다.
하지만 이를 복붙 하면 중복이 발생한다.
그러면 유지보수하기가 매우 어렵다.
이를 해결하기 위해 생성자, new가 필요하다.
3강. 생성자와 new
1) 생성자(constructor)
객체를 만드는 역할을 하는 함수.
JavaScript에서 함수는 재사용 가능한 로직의 묶음이 아니라 객체를 만드는 창조자라고 할 수 있다.
함수에 new를 붙이면 그 return 값은 객체가 된다.
- var p = new Person( ) ;
→ Person { } - var p = { } 와 같다.
function Person(){}
var p = new Person();
p.name = 'innovation_im';
p.introduce = function(){
return 'My name is '+this.name;
}
document.write(p.introduce());
이렇게 생성한 객체가 늘어나서 복붙 하면 아래와 같이 표현이 될 것이다.
function Person(){}
var p1 = new Person();
p1.name = 'innovation_im';
p1.introduce = function(){
return 'My name is '+this.name;
}
document.write(p1.introduce()+"<br />");
var p2 = new Person();
p2.name = 'paradigm';
p2.introduce = function(){
return 'My name is '+this.name;
}
document.write(p2.introduce());
문제는 introduce 부분이 중복되고 코드가 길어진다.
이를 해결하기 위해 생성자를 이용해 다음과 같이 해결할 수 있다.
function Person(name){
this.name = name;
this.introduce = function(){
return 'My name is '+this.name;
}
}
var p1 = new Person('innovation_im');
document.write(p1.introduce()+"<br />");
var p2 = new Person('paradigm');
document.write(p2.introduce());
각각의 생성자 p1, p2가 같은 함수를 타고 들어가서 각각 다른 객체를 생성하고 return 값을 다르게 받는다.
2) 초기화(init, initialize)
생성자 : 객체에 대한 초기화를 한다.
Person이라는 생성자가 만들어 놓은 빈 객체가 어떠한 프로퍼티와 메서드를 가져가야 하는지를 생성자 함수 안에 기술함을 통해서 객체가 가지고 있는 정보나 일을 세팅해 주는 역할을 한다.
그로 인해 코드의 재사용성이 대폭 높아진다.
섹션 20. 객체지향 - 전역객체
1강. 전역객체(Global object)
암시적이다 = 생략했을 때 기본적으로 무언가 사용된다.
자바스크립트에서 모든 객체는 기본적으로 전역객체의 프로퍼티임을 알 수 있다.
var o = {'func':function(){
alert('Hello?');
}}
o.func();
window.o.func();
여기서 o.func와 window.o.func는 같은 결과를 내는데, 위에서 설명한 이유 때문이다. 모든 객체는 기본적으로 전역 객체의 프로퍼티이다.
전역객체의 API
그러나 호스트 환경에 따라 전역 객체는 달라질 수 있다. 서버 측 JS인 node.js의 경우 window가 아니라 global이다.
섹션 21. 객체지향 - this
1강. 함수와 this
this는 함수 내에서 함수 호출 맥락(context)을 의미한다. 맥락은 상황에 따라서 달라지기 마련인데, 함수를 어떻게 호출하느냐에 따라서 this가 가리키는 대상이 달라진다는 것이다. 함수와 객체가 느슨한 자바스크립트에서 this는 이 둘을 연결시켜 주는 실질적인 연결점이다.
2강. 메서드와 this
메서드를 호출하면 그 메서드가 소속되어 있는 객체를 this로 접근할 수 있다. 자기 자신을 this로 접근할 수 있다.
객체의 소속인 메서드의 this는 그 객체를 가리킨다고 할 수 있다.
var o = {
func : function(){
if(o === this) {
document.write("o === this");
}
}
}
o.func();
소속되어있지 않은 함수는 window, 전역객체를 가리킨다.
window.func( ) = func( )
func가 window의 객체이기 때문에 이 메소드 안에서의 this는 매소드의 객체를 가리킨다.
window가 생략되어 암시적으로 나타나기 때문에 함수를 호출하는 것과 메서드를 호출하는 것이 다르다는 느낌이 들뿐이다. 하지만 같은 얘기다.
매소드 호출
o. func( ) = o.o
func( ) = o
3강. 생성자와 this
생성자 안에서 this는 어떤 의미를 갖는가.
함수 안에서 this는 함수가 소속되어 있는 객체를 가리킨다.
그 생성자가 만든 객체를 가리킨다.
var funcThis = null;
function Func(){
funcThis = this;
}
var o1 = Func();
if(funcThis === window){
document.write('window <br />');
생성자의 맥락으로 생성자로 사용될 때는 this의 값이 객체가 되지만, 함수로 호출하게 되면 this의 값은 window를 가리킨다.
this는 객체에 대한 초기화가 끝나서 어떤 식별자에 담기기 전에 우리가 그 객체를 참고할 수 있는 레퍼런스(식별자)이기 때문에 this라는 키워드는 필수적으로 사용되는 키워드이다.
var o2 = new Func();
if(funcThis === o2){
document.write('o2 <br />');
}
여기서 중간에 if(O2) == this){ }를 해도 아직 객체가 생성되기 전이기 때문에 O2는 undefined이다.
4강. 객체로서 함수
함수 리터럴(literal)
함수를 쉽게 작성할 수 있도록 코드를 작성해서 자바스크립트 해석기에 제출하면 자바스크립트 해석기는 함수의 객체를 만들어줌.
function sum(x, y){return x+y;} //함수 리터럴
var o = { } //객체 리터럴
var a = [1, 2, 3]; //배열 리터럴
편리하게 값을 만들 수 있는 문법적인 체계를 리터럴이라고 하는 것
5강. apply와 this
자바스크립트가 유연한 이유 : apply, call
자바스크립트의 함수는 일반적인 객체지향 언어의 메서드보다 위상이 높다.
그럼에도 불구하고, 어떻게 호출하느냐에 따라서 함수는 어떤 존재에 종속될 수도 있다.
var o = {}
var p = {}
function func(){
switch(this){
case o:
document.write('o<br />');
break;
case p:
document.write('p<br />');
break;
case window:
document.write('window<br />');
break;
}
}
func(); //this가 window 호출, 마지막에서 break
func.apply(o); //case o 에서 break
func.apply(p); //case p 에서 break
//어떻게 호출하느냐에 따라서 함수가 종속되는 포인트가 다르다.
this는 변화무쌍해서 대단히 혼란스럽다.
함수가 누구의 소속이냐에 따라서 this는 그 객체를 가리킨다.