OOP, Core Javascript

2013. 6. 27. 18:13JS&FRONT/NodeJs


자바스크립트가 여러 부분에 사용되어지고 있으며, 그 위상이 요즘 들어 정말 대단하다.
Ajax
html5 에 대한 관심이 방대한 javascript library 와 대규모 웹 기반 어플리케이션 개발을 증폭, 이로 인해 확장성의 중요성이 한층 높아짐
.
그리하여 나도 실무 투입전에 한번 되새김질이 필요하다 싶어.. 이곳저곳에서 자료를 찾기위해 기웃거리다가.. 이렇게 잘 정리 해 놓으신 문학청년’s world 님의 강좌의 리스트를 보고.. 숙독 했습니다. 

 코어 자바스크립트 (1) - OOP | 문학청년`s World

 코어 자바스크립트 (2) - PROTOTYPE | 문학청년`s World

 코어 자바스크립트 (3) - 상속 | 문학청년`s World

 코어 자바스크립트 (4) - CallBack 함수 | 문학청년`s World

 코어 자바스크립트 (5) - 프레임워크 구현 | 문학청년`s World

 코어 자바스크립트 (6) - 프레임워크 구현 심화 | 문학청년`s World

 코어 자바스크립트 (7) - 클로저 | 문학청년`s World

 코어 자바스크립트 (8) - 코딩 스타일 | 문학청년`s World

 코어 자바스크립트 (10) - 해쉬 이벤트 | 문학청년`s World

 코어 자바스크립트 (11) - 이벤트 버블링 | 문학청년`s World

이것 이전에 Javascript OOP에 대한 개념을 좀 잘 살펴보고 싶을 경우에..

http://www.taeyo.net/Columns/List.aspx?SEQ=34&IDX=3

JavaScript OOP 스트레칭
JavaScript OOP 코어객체와 prototype 사용한 객체확장
Js OOP - 사용자 정의 객체. 그리고 상속과 재사용
Js OOP - 나만의 프레임워크 만들기

이 부분도 한번 보자구요
공부한 티를 내기 위해 강좌에 있는거 그냥 한번 정리한다구 죄다 타이핑했는데... 음냥;;; 정리해놓은거가 뭔소린지 모르겠네 ㅎㅎㅎ.....

l  OOP (Object Oriented Programming)

A.     Class definition
Javascript
에서는 함수(function)도 클래스로 취급, PROPERTY, METHOD 또한 존재한다.
Function MyClass(){
}  //-- 1
클래스 선언

var myClass = function(){
}  // -- 2
클래스 선언 가독성 측면에서 1번 보다 2번 방식 선호.

B.     접근 제어자
자바 스크립트는 클래스 내부에서 정의할 수 있는 두가지의 접근 제어자를 제공
접근 제어자가 var 일경우에는 해당 클래스 내부에서만 접근이 가능하며, Private 와 같은 역할, 그리고 클래스 외부에서도 사용하기 위해서는 this 를 사용.
OOP
에서 이런 개념을 캡슐화 라고 하는데, 클래스의 내부의 연산 과정을 숨김으로써 보다 독립적인 코드 구성을 꾀할수 있고, 예기치 못한 접근을 차단하여 무분별한 함수 사용을 미연에 방지
.
함수 형태의 방식의 정의와 클래스 방식의 정의 차이는

1.
해당 페이지에 포함되는 자바스크립트가 많을 경우 동일한 함수가 재 정의 될 가능성이 있다.
**
스크립트 언어 특성상 마지막에 정의된 함수를 사용하게 된다
.
2.
하나의 기능을 수행하고자 다수의 비즈니스 로직 처리 함수를 사용한다면 가독성에 문제가 생길 수 밖에 없다. 위의 예제와 같은 함수 정의 방식은 지극히 수평적이고 함수와 함수 간의 관꼐를 증명할 방법이 없다.

C.     정적 클래스
자바 스크립트에서 정적 클래스는 별도의 INSTANCE를 생성하지 않으며 선언과 동시에 정의가 된다. 정적 클래스는 일반적으로 유틸리티 형태의 기능 구현을 할 때 주로 사용된다.
자바스크립트에서 변수(또는 PROPERTY) 와 함수(또는 METHOD)를 접근하는 방법은 크게 외부에서 가능하지 아닌지로 구분, public METHOD는 클래스안의 private 로 정의된 요소들을 접근 할 수 있지만 자바스크립트에서는 불가능 하다. 외부에서도 접근이 가능하고 클래스 안에 private 으로 정의 된 요소들을 접근할 수 있는 METHOD를 자바스크립트에서는 public 이 아닌 privileged(특권을 갖는...) 라고 한다.

                i.         변수 (PROPERTY)
 
1.      Private : 변수는 앞서 설명한 것처럼 클래스 안에서 var 키워드를 사용하여 선언
                 
오직 private/ privileged 함수 에서만 접근할 수 있다.
 
2.      Public : PROPERTY는 클래스 안에서 this.PROPERTYName 형태로 선언 외부에서도 읽고,쓰기가능3.   Prototype : Prototype PROPERTY는 클래스 외부에서 정의되며, Classname.prototype.PROPERTYName = someValue 형태로 사용하지만 동일한 이름의 public PROPERTY가 존재하지 않을 경우에만 정의할수 있다.

4.      Static PROPERTY Classname.PROPERTYname 형태로 정의되며 INSTANCE의 생성과는 별개의 영역에 존재한다. (클래스 내부적으로 static PROPERTY this.constructor.prototypeName 형태로 접근할수 있음.

               ii.         함수 (function, method)

1.      Private 함수는 클래스 내부적으로 function functionName(){.} or functionName = function(){..} 와 같은 형태로 선언되며 생성자와 privileged METHOD를 통해서만 호출될 수 있다.

2.      Privileged METHOD this.methodName = function(){} 와 같은 형태로 선언되며 클래스 외부에서도 실행할 수 있다. 하지만 외부에서는 prototype 을 이용한 재정의를 할 수 없다.

3.      Public METHOD는 클래스 외부에서 Classname.prototype.methodname = function(){} 와 같이 자유롭게 정의할 수 있지만 클래스 내부에 정의된 private 요소들은 접근할 수 없다. 또한 prototype PROPERTY와 마찬가지로 클래스 내부에 동일한 이름의 privileged METHOD가 존재하지 않을 경우에만 정의 할수 있다.

4.      Static METHOD Classname.methodname ro functionName.methodName 형태로 정의되며 INSTANCE 생성과는 별개의 영역에 존재한다. 자주 사용되는 static METHOD는 대표적으로 call/apply METHOD가 있다. (static PROPERTY와 마찬가지로 클래스 내부적으로 this.constructor.methodName 형태로 접근할 수 있음.

D.     참고 사항
변수와 PROPERTY는 비슷한 의미를 가지고 있지만, 결정적인 차이가 있다. 먼저 변수와 함수는 클래스 내부에서만 존재하며 선언적 의미를 가지고 있다.
PROPERTY
METHOD는 정의되는 것이라 할수 있는데, 여기서 말하는 정의란 클래스가 구체화되어 INSTANCE가 생성되는 것을 말한다
.
이때 PROPERTYMETHOD는 생성된 INSTANCE를 통해 접근할수 있다.

l  Prototype

A.     prototype

javascript
에서 함수는 prototype 이라는 특수한 PROPERTY를 가지고 있다.
이를 사용해서 string number 같은 내장 클래스는 물론이고 사용자 정의 클래스를 포함한 모든 객체를 확장할 수 있다. , 클래스 상속이 아닌 프로토 타입을 이용해서 클래스의 METHODPROPERTY를 추가할 수 있다
.
이는 상속 개념과는 약간 다른다. 상속은 자식 클래스가 원하든 원치 않든 부모의 모든 속성을 물려 받는 것이고, PROTOTYPE을 이용한 객체 확장은 기존의 클래스에서 기능을 외부에서 추가하여 사용하는 것이다
. 기존의 String 내장 객체에 prototype를 사요하여 좌우 공백을 없애는 trim METHOD를 구현하였다. PROTOTYPE을 사용하여 구현하면 해당 페이지는 물론이고, 이 라이브러리를 로드하는 모든 페이지에서도 사용할 수 있다. 즉 앞서 말한 것처럼 새로운 클래스를 생성한 것이 아니라 기존의 클래스의 기능을 확장한 것이다. 바로 이것이 클래스 기반과 PROTOTYPE의 차이점이다.
위와 같이 진행 했을 경우 해당 INSTANCEMETHOD에 접근할 수 있기 때문에 prototype 를 사용해서 string 클래스 자체에 추가해주는 것이 더 좋을 것이다
.
그럼 마지막으로 jQuery에서 자주 사용되고 있는 each METHOD prototype 를 사용해여 구현
.
위 소스 코드는 a,b,c 세번의 메시지를 출력한다. Each METHOD CallBack 함수의 파라미터를 통해 test 배열에 포함되어 있는 객체들을 차례대로 호출한다
.
 
하지만 이상하데.. JQuery 를 사용해본 개발자라면 알겠지만 해당 배열에 포함되어 있는 객체들은 CallBack함수의 파라미터로 넘겨주지 않는다. CallBack 함수의 파라미터로는 해당 객체의 배열 index 값을 보내며 각각의 객체들은 CallBack 함수 내에서 this 키워드로 접근한다
.
아래 예제는 test 배열 변수 값을 얻어와서 index 값과 name 값을 출력 한다
.
JQuery를 사용하다 보면 each METHOD처럼 CallBack 함수 내에서 this 로 배열의 요소들을 접근하는 경우가 많다. 하지만 대부분의 사용자들은 왜 저렇게 구현되는지 관심을 가지지 않는다.
필자는 CallBack 함수내에서 this로 접근할 수 있는 방법으로 prototype을 제시한다
.
위의 예제에서 정말 중요한 부분은 3~4라인이다. 첫번째 예제에서는 바로 callback 함수의 파라미터로 this[i]값을 넘겼다. 하지만 여기서는 callback 함수의 prototype this[i]로 정의하였다. 이전 강좌에서 자바스크립트의 함수는 클래스와 같다라고 설명한 적이 있다
.
즉 함수는 클래스이기 때문에 자신의 원형을 prototype PROPERTY를 통해 정의 할 수 있다
.
이로써 callback 함수는 name PROPERTY를 가진 객체의 원형 클래스가 된다
.
이는 CallBack 함수 내에서 this 키워드를 통해 name PROPERTY에 접근할 수 있음을 의미한다.

B.     Prototype Chain
앞서 설명했듯이 함수(또는 클래스) prototype 이라는 특수한 PROPERTY가 존재한다고 했다.
만약에 함수 이름이 Test 라고 가정을 하고 new 키워드를 사용하여 INSTANCE를 생성하였을 때, Test.prototype 은 방금 생성된 INSTANCE의 추상적인 존재인 원형(PROTOTYPE)이 된다
.
기본적으로 INSTANCE를 생성하지 않았을 때의 프로토 타입은 자바스크립트 최상위 Object 클래스를 참조한다
.
생성된 INSTANCE는 자신의 추상적인 존재인 Test 클래스의 멤버들을 참조하게 된다
.
그리고 Test 클래스의 멤버는 Test 클래스의 PROTOTYPE을 참조하게 되고, Test 클래스의 PROTOTYPE은 최상위 클래스인 Object 클래스의 PROTOTYPE을 참조한다
.
이런식으로 INSTANCE 생성 시점부터 최상위 클래스까지 순차적으로 연결되는 것을 바로 PROTOTYPE 체인 이라고 한다
.
참고로 생성된 INSTANCE는 자신의 클래스 안에 this와 동일하다고 생각하면 된다
.
아래는 INSTANCE를 생성하지 않고 단순히 호출하였을때의 값과 INSTANCE를 생성했을때의 값값 다르다는 것을 알수 있다
.
Test()
와 같이 단순히 함수를 호출하였을 때의 this window 클래스를 참조한다
.
하지만 INSTANCE가 생성되었을때의 this Window 클래스가 아닌 Test 클래스를 참조한다
.
그리고 IE를 제외하고 크롬,파폭에서는 생성된 INSTANCE에는 ‘__proto__  라는 PROPERTY가 존재하는데, 이것은 바로 앞서 말했던 Test.prototype 과 동일하다고 생각하면 된다
.
INSTANCE
가 생성될 때 첫번째로 자신의 클래스의 멤버를 참조한다
.
만약에 호출하는 멤버 METHOD가 없을 경우에는…Test.prototype.test 이다.. 마지막으로 Test prototype이 없다면.. Object 이겠죠
~~
이렇게 prototype chain을 사용한다면 클래스들의 관계를 유기적으로 연결할 수 있다
.
어떻게 보면 PROTOTYPE 체인은 OOP 에서의 상속과도 비슷한 개념이라 볼수 있다
.
자바 스크립트에서는 INSTANCE를 생성하였을 때에만 프로토 타입 체인이 발생하는 것이 아니다
.
정적 METHOD 호출시에도 프로토 타입 체인은 발생한다
.
Test
클래스의 정적 메소스를 정의 하였다. 앞서 설명했듯이 new 키워드를 사용하여 생성된 INSTANCE의 추상적인 존재가 바로 Test 클래스라고 하였다. 하지만 INSTANCE와 별도의 스코프에 존재하는 정적 METHOD의 원형은 Function 클래스 이다
.
그렇기 때문에 위의 예제에서 Test 클래스의 멤버로 선언된 METHOD Test.prototype.print METHOD는 정적 METHOD와 관련이 없는 별개의 METHOD라고 생각하면 된다.

C.     Constructor PROPERTY
PROTOTYPE
constructor 라는 특수한 PROPERTY를 가지고 있는데, 이것은 바로 자신이 원형이 되는 클래스를 참조한다.
t1.constructor === t2.constructor
INSTANCE constructor 는 바로 Test 클래스를 참조하기 때문에 true 가 출력이 된다
.
또한 constructor Test 클래스 그 자체이기 때문에 15~16라인과 같이 새로운 INSTANCE를 생성할수도 있다. 그리고 INSTANCE는 클래스 내부에서 this와 동일하기 때문에 constructor PROPERTY를 가지고 있다. 그렇기 때문에 정적 METHOD Test.show를 호출 할 수 있는 것이다.

l  상속

A.     상속은 다른 클래스의 METHODPROPERTY 등 새로운 클래스에 병합시키는 것을 말한다.
자바스크립트에서는 PROTOTYPE을 사용하여 상속을 구현할수 있다. 우와
~
원래 상속 관련 예제는 자바스크립트 1.3 버전 이후 생긴 apply call 함수를 이용해서 구현했었는데, 자세히 알아보니 개념이 상속과는 조금 다르다
.
각각의 INSTANCE가 이름과 유형의 속성을 가지고 공격/공격 받음/ 이동 의 행동을 할수 있는 Unit 클래스로 구현하였다. 하지만 유닛의 종류가 많아짐에 따라 기계 또는 생물 유닛으로 확장할 필요성이 있었다. 그래서 본연의 속성과 행동을 그대로 가져가되 고유한 특성이 있는 별도의 하위 클래스를 구현하였다. 자바스크립트의 PROTOTYPE 체인을 이용하여 상속을 구현할수 있다
.
PROTOTYPE
은 계층적인 구조에서도 동작하는데 이러한 특성이 OOP의 주요 특징중 하나인 상속과 비슷한 개념
.
물론 실제 OOP 기반의 자바나 C++과 같이 완벽한 상속을 지원하지는 않는다
.
하지만 PROTOTYPE을 잘 이용하면 충분히 확장성을 고려할 수 있는 프로그램을 자바스크립트로 구현할수 있다
.
자식은 PROTOTYPE 체인을 이용하여 부모의 특성을 상속 받았다
.
하지만 자식 내부와 PROTOTYPE을 통해 정의한 METHOD를 모두 주석 처리 하였다. 이럴 경우 생성된 자식 클래스의 INSTANCE print METHOD를 호출하면 어떤 값이 나올까? 결과값은 당연히 자식 클래스에서는 print가 존재하지 않기 때문에 부모 클래스에 정의된 METHOD를 호출하게 된다.

B.     자바 스크립트는 객체 지향 언어에서 중요한 개념인 METHOD 오버로딩을 지원하지 않는다.
오버로딩이란 하나의 클래스에 동일한 이름을 갖는 METHOD를 여러 개 생성할 수 있는 특징을 말하는데, 파라미터 개수 또는 타입이 다르기만 하면 된다
.
오버로딩이 필요한 이유는 동일한 이름을 가짐으로써 비슷한 기능을 하는 METHOD, 이는 복잡한 클래스 구조에서 METHOD 이름을 아낄수 있고, 가독성을 증가 시키는데 중요한 요인으로 작용한다
.
파라미터가 하나인 move METHOD는 아예 실행되지 않았음을 알수 있다. 자바스크립트 특성상 동일한 METHOD는 마지막에 정의된 METHOD를 호출하게 된다. 즉 첫번째 move METHOD는 아래 METHOD로 인해 재정의가 되버린 것이다
.
??? 오버로딩을 지원하지 않는것일까? 그것은 바로 가변적으로 파라미터를 받을수 있는 자바스크립트 고유 특성 때문이다
.
자바스크립트는 함수 또는 METHOD 내부적으로 arguments PROPERTY를 사용할 수 있는데, PROPERTY는 배열 형태로 구성되어 있다
.
즉 해당 함수의 파라미터 수만큼 데이터를 가지고 있다
.
이러한 특성 때문에 자바스크립트는 오버로딩을 지원하지 않는다.

l  CallBack

A.     CallBack 이란 디자인 패턴 중 하나인 Observer 패턴에서 나온 개념으로 객체의 상태 변화(이벤트)가 발생하였을 경우에 이러한 사실을 함수를 통해 전달하게 되는데, 이를 CallBack 함수라고 한다. 자바스크립트에서 CallBack함수는 키보드,마우스 클릭과 같은 디바이스 이벤트 뿐만 아니라, Ajax 데이터 처리등 많은 부분에서 사용되고 있다.

B.     기초
CallBack
함수는 시계의 알람 기능과 비슷하다고 생각하면 조금 더 쉬울 것.
CallBack
함수는 특정 기능을 수행하기 위한 로직과 기능 수행후 반환되는 결과 값을 가지고 이를 표현하는 로직을 서로 분리할수 있다
.
이는 View 의 분리라는 점에서 MVC 패턴과 비슷한다
.
대세가 되어린 jQuery 라이브러리에서 제공하는 많은 함수들의 결과 값이 CallBack 형태로 호출된다. 이런 함수들은 이벤트 처리 , 애니메이션, Ajax , 콜렉션 등에서 사용된다
.
CallBack
으로 결과 값을 반환하는 함수들은 공통적인 특징이 하나 있는데, 그것은 바로 View를 처리하는 시점이 모호하다는 것이다
.


C.     심화
특정 함수의 반환 값을 CallBack으로 넘기는 방법은 위의 예제들을 보면 알 수 있듯이 그렇게 어렵지 않다. 매개 변수를 통해 함수를 받고 그 함수를 통해 결과 값을 다시 호출하면 되기 때문이다. 하지만 JQuery에서 제공되는 함수들을 보면 단순히 CallBack을 통해 결과 값을 넘기지 않는다.
jQuery $.each
함수는 해당 배열의 요소들을 모두 순환하면서 CallBack으로 index 값을 넘기는데, 이 요소를 CallBack 함수의 매개 변수로 넘기지 않고 함수 내에서 this 키워드로 접근한다
.
this 키워드를 통해 test 배열에 포함되어 있는 요소(객체)들을 접근하고, name 이란 PROPERTY를 출력 하였다. 하지만 어떻게 CallBack 함수 안에서 this 키워드를 사용하여 name PROPERTY를 출력할 수 있었을까
?
 매개 변수로 받은 배열을 순차적으로 접근하여 CallBack을 통해 각각의 배열 요소들을 넘겨주는 함수를 구현한 것이다
.
하지만 현재 위치의 요소를 CallBack 함수의 parameter로 넘겼을 뿐, CallBack 함수 내에서 this로 접근하지 못한다
.
그럼 CallBack 함수 내에서 this 값이 무엇이 찍히는지 확인해 보면 [object Window] 라는 메시지가 출력된다. 자바스크립트에서 함수는 정의될때, 기본적으로 Window 객체의 METHOD가 되기 때문에 콜백 함수 내에서 this window 객체가 되는 것이다
.
그렇다면 콜백 함수 내에서 배열 요소를 this로 접근하기 위해서는 어떻게 해야 될까
?
이전에 다룬 prototype를 사용하여 콜백 함수의 원형을 배열 요소로 변경해 주면 된다
.
callback.prototype = arr[1];
callback(i);
자바 스크립트 함수는 클래스이며, 자신의 원형을 prototype 으로 정할 수 있다
.
즉 매개 변수를 통해 받은 콜백함수는 name PROPERTY를 가진 객체 자체가 되는 것이다
.
하지만 prototype으로 자신의 원형을 해당 배열 요소로 정했다고는 하지만 단순한 콜백 함수 호출로는 콜백 함수 내에서 this 키워드로 접근 할 수 없다
.
왜냐하면 자바 스크립트 함수는 앞서 말한 것처럼 기본적으로 window 객체 이기 때문이다
.
그렇다면 자신만의 고유한 객체가 되기 위해선 어떻게 해야 될까? 그건 바로 new 키워드를 사용하면 된다
.
Callback.prototype = arr[i];
new callback(i);
// call
또는 apply 함수를 사용하여 구현 할 수도 있음
.
// callback.call(arr[i], i);
위의 예제의 출력 메시지는 test1 : [object Window] . test2 : [object Object] 이다
.
앞서 말한 것 처럼 자바스크립트 함수는 클래스 이기도 하기 때문에 고유한 객체(INSTANCE)를 생성할 수 있다. new 키워드를 사용하여 콜백 함수를 호출하면 window 객체가 아닌 새로운 객체가 되는 것이다. 단순하게 new 키워드 사용 유무를 non-static / static 개념이라고 생각하면 이해가 쉬울 것이다
.
완성된 each 함수는 바로 (example 46) 이다.

l  Framework 구현
MVC
패턴 기반의 웹 프레임 워크를 직접 구현해 본다.
특히 컨트롤러 영역은 PHP, JSP 와 같은 서버 단 언어가 아닌 자바스크립트로 구성되는데, 오늘 구현하고자 하는 내용은 현재 사용하는 웹 프레임워크들 중에서 많이 사용하고 있는 컴포지트 뷰(Composite View) 패턴 이다
.
Composite view pattern
은 하나의 컨트롤러와 뷰가 일대일 매칭되며, 각각의 컨트롤러들은 서로 연관성이 없는 독립적인 영역으로 구분된다

A.     Parameter Pasing
본 프레임워크는 URL 형태로 컨트롤러 명과 나머지 요청 변수들을 받아온다. 자바스크립트에서 받을 수 있는 URL은 단순 문자열이기 때문에 이를 가동하여 하나의 객체로 만들어야 한다.
initParam
함수는 location.href PROPERTY를 통해서 현재 페이지의 전체 URL를 가지고 온다음.. ? 다음으로 오는 요청 변수들을 params[ctrl"], param[page] 형태로 가공하여 하나의 배열 변수로 만든다.

B.     Templete Loading.
요청 변수를 배열 형태로 만든 다음에는 현재 컨트롤러 명과 일치하는 템플릿을 가져와야 한다. 현재 샘플 페이지 구조에는 temp/템플릿명.temp 형태로 템플릿 파일을 저장해야 한다.
템플릿 로드 함수의 구조는 매우 간단하다. 그냥 간단하게 템플릿 내용을 Ajax 방식을 통해 가져온 후 , 콜백함수로 넘겨주기만 하면 된다.

C.     Controller 호출
웹 페이지 로딩시 , ctrl 요청 변수가 있을 경우에 해당 컨트롤러를 호출한다.
관련된 컨트롤러는 모두 클로저 안에 구현이 되어 있어야 하며, 그 이유는 클로저 안에 구현되어 있어야만 다른 영역에서 임의로 호출되지 않기 때문이다
.
위의 개요에서 언급한 것처럼 컴포지트 뷰 패턴은 각각의 컨트롤러들은 서로 연관성이 없는 독립된 페이지로 구성되어야만 하기 때문이다
.
ctrl = board_list 
è function board_list è board_list.temp
ctrl = board_post
è function board_post è
board_post.temp
ctrl = board_read
è function board_read è
board_read.temp
첫번째 컨트롤러가 호출되는 시점의 예제를 본다.
웹페이지의 URL을 미리 구현해 둔 initParams 함수를 이용하여 파싱한 다음에 최상위 객체인 windowPROPERTY 형태로 요청 변수를 저장한다
.
window
PROPERTY로 저장하는 이유는 요청 변수를 모든 영역에서 사용할 수 있게 하기 위함이다.(요청 변수는 cont.params[KEY] 형태로 값을 가져올 수 있음
.)
cont.params PROPERTY
에 요청 변수를 저장한 후 해당 컨트롤러 명에 맞는 템플릿 내용을 미리 구현해 둔 initTemplate 함수를 사용하여 가져오고, 콜백 함수(컨트롤러 함수)의 요청 변수로 넘겨준다. 하지만 문제가 있다. 어떻게 문자열 형태의 컨트롤러 명을 가지고 미리 정의해둔 컨트롤러 함수를 호출할 수 있을까? 그 해답은 바로 eval 함수 이다
.
eval
함수는 수힉 형태로 된 문자열을 실수로 변환하여 처리하게 하는 자바스크립트의 내장함수이다.

D.     Controller 정의
컨트롤러 함수를 구현할 때에는 특정 규칙이 있다. 첫번째 규칙은 두 개의 매개 변수를 가져야 한다. 아래 예제에서 temp 변수는 해당 컨트롤러 이름과 일치하는 템플릿 파일의 내용이며, type 변수는 컨트롤러 종류이다.
그리고 두 번째 규칙은 해당 컨트롤러 함수 안에서 type 변수에 따라 분기 하여 별도로 구현을 해야 한다
.
컨트롤러 종류는 뷰와 액션 두 가지가 있는데, 먼저 뷰 컨트롤러는 해당 페이지에 템플릿 내용을 가공하여 문서 내에 포함시키는 역할을 한다. 액션 컨트롤러는 가공된 데이터를 특정 문서에 포함시키지 않고 그냥 반환한다
.
뷰 컨트롤러는 주로 URL 을 통해 웹 페이지에 접근하였을 때에만 호출되며, 문서가 로드 된 후에 동적으로 컨트롤러를 호출 할 때에는 액션 컨트롤러를 사용한다.(액션 컨트롤러를 호출할 수 있는 별도의 함수가 제공 됨.)

E.      Controller 구현
아래에 구현된 컨트롤러 함수들은 템플릿을 별도로 가공하지 않고 그대로 사용하였다.
PHP
Smarty 또는 Dwoo 와 같은 템플릿 엔진을 써본 적이 있다면 어떤 식으로 데이터를 가공하는지는 알고 있을 것이라 생각되므로 템플릿과 관련된 설명은 별도로 하지 않겠다
.
참고로 자바스크립트로 PURE jTemplate 와 같은 템플릿 엔진이 존재하기 때문에 적극 활용한다면 본 강좌에서 다루고 있는 웹 프레임워크를 보다 더 잘 활용할 수 있을것이라 생각된다
.
웹 페이지가 모두 로드가 된 이후에 뷰 컨트롤러가 아닌 동적으로 액션 컨트롤러를 호출하고 싶을 때에는 앞에서 구현해 둔 action 함수를 사용하면 된다
.
action
함수는 json 형태로 요청 변수를 넘길 수 있고, 콜백 함수의 매개 변수를 통해 호출하고자 하는 컨트롤러 안에서 반환된 값을 받을 수 있다
.


l  Framework 2

A.     개요
웹 개발을 하다보면 JS를 사용하여 아래 소스 코드와 같이 클라이언트 단에서 직접 태그를 추가하거나 포함하는 경우가 있다.
ex) $(
#view).append(“” + subject + “”
);
로직과 뷰 단을 위의 소스 코드와 같이 섞어서 쓰게 되면 가독성이 매우 떨어지게 된다
.
또한 디자인 이슈로 인해 뷰 단의 수정이 불가피한 경우, 이를 수정하는데 많은 비용이 들게 된다
.
이러한 문제점을 해결하기 위해 이번 프레임 워크에서는 EJS 라는 템플릿 엔진을 사용하여 로직과 뷰 단을 분리 한다
.
EJS :
http://embeddedjs.com

B.     기본 개념
본 프레임 워크를 사용하는 방법은 간단.
위의 소스 코드에서 Ajax으로 호출하는 필자가 NodeJS 로 구현한 내부적으로 OpenAPI를 사용하여 결과값을 JSON형태로 반환해주는 컨트롤러 페이지 이다
.
반환되는 값은 아래 URL 참조( apple”로 이미지 검색하는
OpenAPI URL)
http://apis.daum.net/search/image?apikey=d5e0a09a5a89416c1d0c49d877e2fa9f97b9968b&output=json&result=10&pageno=1&q=apple

C.      사용 방법
본 프레임 워크를 사용하기 위해서는 모든 컨트롤러를 아래 소스 코드에 보이는 클로저 안에 구현해야 한다.
(Example 62)
각각의 컨트롤러는 기본적으로 ejs/컨트롤러명.ejs 라는 템플릿 파일을 참조하게 된다
.
물론 별도의 옵션을 주어 템플릿 파일과 바꿀 수도 있다
.
해당 컨트롤러 함수를 클로저 안에 구현한 이유는 외부로부터 호출되지 않게 하기위함 이며 본 프레임워크가 제공하는 컨트롤러 호출 함수를 사용하지 않는다면 해당 컨트롤러는 절대로 호출되지 않는다. 그렇다면 해당 컨트롤러를 호출하기 위해서는 두가지 방법중 하나를 선택해서 하면 되는데 첫번째 방법으로 JSFW.call 함수를 사용하는 것이다
.
JSFW.call
함수의 매개변수 순서는 컨트롤러명, 매개변수 그리고 콜백함수 (결과 값은 인자로 받을수 있으며, 인자 값은 템플릿이 적용된 HTML 코드)이다
.
JSFW.call
함수의 두번쨰 매개변수로 넘긴 값들은 호출하고자 하는 컨트롤러 함수 내에서 아래 소스 코드의 같은 방법으로 사용 할 수 있다
.
 var keyword = params[
keyword
];
 var page = params[
page
];
그렇다면 EJS 템플릿에서 사용되는 값들은 어떻게 넘길까
?
아래와 같이 하나의 객체로 만들어서 dispatch 콜백 함수를 호출하면 된다
.
var data = {
  _isAction : false,
  title : "[JSFW Library] - Demo",
  totalCount : json.channel.totalCount,
  keyword : keyword,
  items: json.channel.item
};
위와 같이 컨트롤러에서 가공한 데이터들은 아래 템플릿 화면과 같이 사용되어 화면에 뿌려주게 된다. (위에서 사용된 $.post 함수는 이미지 검색 결과 값을 JSON 형태로 받음
)
약간 복잡하게 생각할 수 있지만 본 프레임 워크를 사용하면 컨트롤러와 뷰를 완벽하게 분리할 수 있으며, 컨트롤러 선언부를 클로저 안으로 제한 시키므로써 일반 자바스크립트와의 분리도 가능하다
.
마지막으로 간단하게 프레임 워크가 실행되는 프로세스를 정리하면
>
 1. Load
함수 호출, 내부적으로 JSFW.call 함수 사용

 2.
컨트롤러 실행
 3.
템플릿 적용
 4. JSFW.call
함수의 콜백을 통해 최종 HTML 코드를 받음.

l  클로저

A.     개요
Closure
라는 매우 중요한 개념이 있다. 자바스크립트로 프로그램을 구현하다보면 은연 중에 이러한 개념들을 사용하곤 했는데… closure는 함수 내에 선언된 로컬 변수를 외부에서도 참조할수 있는 함수를 말하며, 어떻게 보면 자바스크립트의 모든 함수가 클로저라고 말할 수 있다.
다른 언어에서는 함수 내부의 지역변수 a는 유효범위를 벗어나서는 쓸수 없는 변수지만 자바스크립트는 그렇지 않다
.
도 마찬가지다. 다시 말해 return 이 되는 함수가 클로저인데 동작하는 함수를 그림으로 표현하면 다음과 같단다
.
ClosureTest()를 생성하면서 인수를 1을 지정하면 중첩 함수인 클로저는 그 값을 참조한다. 따라서 최종적인 클로저는 인수로 받은 b에 기존에 포인터로 가지고 있던 1을 더해서 반환하는 함수 이다. test(2)를 실행하면 다음과 같이 동작, 이 예제에서 중요한 것은 참조 이다.
즉 값 자체를 복사하는 것이 아니라 값을 참조하고 있으므로 참조하는 값이 바뀌면 참조하고 있던 값도 바뀌게 된다.

B.     심화
비유를 하자면 클로저는 C언어에서 & 키워드를 사용하여 정의하는 참조 변수라고 생각하면 된다. (표현 방법의 차이가 있을 뿐, 실제 개념은 비슷하다고 보면 됨
)
item list[i] 값은 result 배열에 push 될 때, 값 자체가 복사되서 들어가는 것이 아니라 참조되어 들어가기 때문에 i의 최종값인 3으로 저장된다. 그렇기 때문에 출력값도 변한다.
익명 함수를 사용하여 간단하게 해결할수 있다
.
i
의 값을 익명 함수의 매개변수로 넘겨 ii 인자 변수로 받음으로 써 I 변수의 참조에서 벗어 날 수 있게 되었다.

l  코딩 스타일

A.     IF 문 과 Switch 문 대체
아래 예제의 get 함수는 key를 매개변수로 받아 if 문과 switch 문을 사용하여 특정 Value 값을 반환해 준다. 이와 같은 개발 패턴은 매우 자주 사용, g자미나 if문 혹은 switch문을 사용하면 소스 코드가 너무 길어지고 가독성이 떨어진다.
그래서 아래와 같이 간결하게 구현할수 있단다
.
function get(type){
  return {
    todo :
‘할일’
,
    calendar :
‘달력’
,
    note :
‘공책’

  }[type]
}

B.     속도 개선
코딩할 때 조금만 신경쓰면 속도 개선의 효과를 누릴수 있다.
1 .
네이티브 코드 사용 : $.each 함수보다는 for문을 사용하라
.
2. var str =
a + b ;  // 잘못 사용

  var str = [
a , b].join(‘’);  // 좋은 사용
3.
배열 길이 추가 정의
for(var i =0 ; i < nodes.length ; i++){} //
별로..
for(var i = 0,len = nodes.length ; i <len;i++){} //
오오오…

l  해쉬 이벤트

A.     개요
Ajax
기반의 단일 페이지 형태의 웹을 구현할 때, 웹 페이지가 계속 바뀌게 되더라도 페이지 자체는 하나 뿐이기 때문에 브라우저 히스토리 기능이 제대로 동작하지 않는다.
아래 URL은 순수 Ajax로 구현한 게시판이다. 브라우저 히스토리 기능이 동작하도록 구현되지 않았기 때문에 대충 테스트를 해보면 문제점에 대해서 …

이런 문제점을 해결하는 방법중하나가 hashchange 이벤트를 사용하는 것이다.
여기서 해쉬란 URL 뒤에 #형태로 붙어있는 앵커(anchor)를 말한다
.
페이스북이나 트위터 등에서도 해쉬를 사용하여 브라우저 히스토리 기능을 이요한다
.


B.     주의 사항
먼저 자바스크립트를 통해 동작하는 것이기 때문에 단순한 구문 오류만 있더라도 웹페이지 전체가 동작하지 않는다. 또한 자바스크립트를 통해 페이지를 동적으로 생성하는 것이기 때문에 검색 엔진의 크롤링이 되지 않으며, 만약 해당 웹 페이지가 수집된다고 하더라도 아무런 내용이 없는 빈 페이지 일 것이다.
이와 같은 사실을 직시하고 구현하고자 하는 웹 페이지의 특성에 맞게 사용하는 것이 가장 좋은 방법일 것이다.

C.     프레임 워크 구현
해쉬 이벤트를 구현하는 것은 아래 예제와 같이 매우 간단하다.
window.addEventListener('hashchange', function(){
               var hash = location.hash;
}, false);
http://me.inpost.kr/index.html
와 같은 일반적인 URL에서 http://me.inpost.kr/index.html#hash1 와 같이 해쉬가 붙계 되면 위의 예제에 있는 콜백 함수가 실행된다. 콜백 함수 내에서는 location.hash 를 통해 # 이후의 문자열을 자져올수 있다.
하지만 문제가 좀 있다. 위의 이벤트 정의는 IE7 버전 이하부터는 지원하지 않는다. 그래서 아래 예제와 같이 setInterval 함수를 활용하여 주기적으로 해쉬 체크를 함으로써 해쉬 이벤트와 비슷한 기능을 구현할 수 있다
.원리는 간단하다. 주기적으로 해쉬를 전역 변수 beforeHash에 저장을 하고 , 이전 값과 최근 값이 다를 경우, 해쉬 이벤트가 발생했다고 판단하여 이후 로직을 실행하는 원리이다.

D.     Init 함수 구현
위의 예제에서 주석 처리되어 있는 init 함수.. 해당 함수는 해쉬를 분석하여, 넘겨줄 파라메터를 파싱하여 지정된 함수를 호출해 주는 핵심 함수이다.
해쉬 규칙은 다음과 같이 되어 있다
.
#호출함수명/매개변수1/매개변수2/매개변수n’ 매개변수는 제한없이 추가할수 있으며, 단지 순서만 기억하면 된다. 해당 매개변수는 호출될 함수에서 배열 형태로 전달 받을수 있다.

E.      완성된 프레임워크
해쉬 이벤트를 통해 호출되는 함수들은 외부에서의 호출을 막기 위해서 클로저 안에 구현을 한다.
(
아래 예제에 구현된 board_list, board_read, board_post 함수는 URL 뒤에 붙어 잇는 해쉬 태그로만 호출이 된다
.)


l  이벤트 버블링

A.     개요
오늘 강과는 이벤트가 어떤 종류가 있고 어떻게 사용하는지 다루지 않을 것이다.
필자는 자바스크립트를 사용하여 클라이언트 개발을 할 경우 , 은근히 이벤트와 관련된 문제 때문에 어려움을 겪은 적이 많았다. 이때 겪는 어려움의 요인 중 하나가 바로 이벤트 버블링 이다
.
간단한 웹 페이지에서는 이벤트가 중첩된 경우가 드물기 때문에 버블링으로 인한 문제가 발생하지 않는다. 하지만 드래그앤드롭과 같이 여러 개의 이벤트가 중첩되어 사용되는 경우에는 이러한 문제가 발생하곤 한다.

B.     버블링과 캡쳐링
계층적 구조에 포함되어 있는 특정 엘리먼트에 이벤트가 발생할 경우, 연쇄적인 반응이 일어나는데 이를 이벤트 전파라고 한다.
이벤트 대상 엘리먼트를 시작으로 최하위 엘리먼트까지 이벤트가 전파되는 것을 캡쳐링이라고 하고, 반대로 최상위 엘리먼트에서 대상 엘리먼트까지 이벤트가 전파되는 것을 버블링이라고 한다
.
참고로 IE 계열의 브라우저에서는 캡처링을 지원하지 않고, 자주 쓰이지 않기 때문에 이벤트 전파라는 용어 대신 이벤트 버블링으로 통일하여 설명한다
.

자식 엘리먼트를 클릭하였을 경우, 결과 값은 두줄이 출력, 이벤트 버블링으로 인해 발생된 현상이다.
버블링과 캡쳐링의 결과값을 비교해보면 currentTarget의 값의 순서가 다르다
.
위에서 target currentTarget의 차이는 자식 엘리먼트에 클릭 이벤트가 발생하여 최상위 또는 최하위 엘리먼트까지 이벤트가 전파될 때, 이벤트 리스너(콜백 함수)의 인자를 통해 이벤트 대상 엘리먼트를 가져올 수 있는데, 그게 바로 target currentTarget 이다
.
먼저 target 은 처음 클릭 이벤트가 발생한 대상 엘리먼트 자체라고 보면 되고, currentTarget은 이벤트가 전파되면서 대상 엘리먼트부터 최상위 부모 엘리먼트까지 순차적으로 바뀌게 된다. 그렇기 때문에 위의 예제 처럼 currentTarget의 값이 달라 지는것이다.

C.     이벤트 버블링 차단.
중첩된 엘리먼트에서 발생하는 이벤트 버블링을 막을 수 있는 방법은 두가지가 있다
.

divs[i].addEventListener("mousedown", function(e){
result.innerHTML += "<strong>target</strong> : " + e.target.id + ", <strong>currentTarget</strong>: " + e.currentTarget.id + "<br />";
e.stopPropagation();
}, true);                             //
버블링(false), 캡처링
(true)

이벤트 리스너(콜백함수)의 인자로 stopPropagationMETHOD를 호출하면 버블링이 차단되어 액션이 한번만 발생한다. 만약에 캡쳐링 상태에서 호출을 하였다면 currentTaget의 값은 childern이 아니라 parent가 출력 될 것이다. 또한 stopPropagation METHOD 말고 false로 리스너 함수를 리턴해버려도 버블링은 차단된다
.
그렇다고 위 두가지가 완전히 같은 것은 아니다
.
stopPropagation METHOD
는 이벤트 버블링은 차단하지만, 대상 엘리먼트의 추가 액션은 허용 하지만, false로 리스너 함수를 리턴하는 것은 이벤트 전파도 막고, 대상 엘리먼트의 추가 액션 또한 허용하지 않는다. 그리고 리스너 함수의 인자로 preventDefault METHOD를 호출 할 수 있는데, METHOD는 이벤트 버블링과는 상관이 없고, 해당 리스너 함수가 호출될때 대상 엘리먼트의 추가 액션을 막는다
.
그렇기 때문에 리스너 함수 내에서 stopPropagation METHOD preventDefault METHOD를 같이 사용하는 것은 false로 리스너 함수를 리턴하는 것과 동일한 특성을 가지는 것이다
.



 

 오늘 공부는 여기 까정!