'Javascript'에 해당되는 글 112건
- 2012.09.30 javascript XML CDATA Section 사용 방법
- 2012.09.28 IE 버전을 알아내는 여러가지 구현 방법
- 2012.09.14 "소셜 버튼" 생성 모듈 구현
- 2012.09.06 자바스크립트 인터페이스 구현
- 2012.09.06 자바스크립트 추상 클래스 구현
- 2012.08.27 자바스크립트 문서화를 위한 "jsdoc toolkit" 사용법 및 예제
- 2012.08.18 Javascript MVC 패턴 구현 1
- 2012.07.24 LazyImageLoader.js(점진적 이미지 로딩)
- 2012.07.04 자바스크립트 (Singleton, Factory, Chain, Interator) Pattern 구현
- 2012.07.04 자바스크립트 Mediator(중재자) Pattern 과 Facade Pattern 구현
javascript XML CDATA Section 사용 방법
javascript XML CDATA Section 사용 방법
1. XML은 CDATA Section(<![CDATA[ ~ ]]>)이라는 것을 지원하는데, 이 영역 안에 들어갈 경우 <, >, & 와 같은 특수 문자(마크업으로 인식될 문자)들을 일반 문자(<, >, &)와 같이 쓸 수 있다.
즉, <, >, &와 같이 Entity로 써야하는 문자들을 아무런 변환 없이 일반 문자(<, >, &)와 동일하게 사용할할 수 있게 만든다.(하지만 실제 JS 영역 안의 Entity 문자는 브라우저가 Entiry 문자 그대로 해석해 버리기 때문에 일반 문자로 변환되지 않는 단점이 존재한다.)
- 소스보기는 위 HTML TAB 이동!!!(결과 페이지: http://mohwa.org/html/cdata.xhtml)
2. Javascript 코드에 CDATA Section 삽입 시 시작과 끝 부분에 //(주석)을 포함하는 것은 해당 Section을 해석하지(오래된 브라우저) 못하는 브라우저에 대한 에러를 막기 위해서다.(위 소스 코드를 참조)
3. 브라우저가 해당 페이지의 응답 Content-Type을 XHTML로 해석 시 제대로 작동하며, HTML등 다르게 해석 시 에러가 발생한다.(대부분의 브라우저(IE8+, Chrome, Safari, FF)에서 해당 파일의 확장명을 *.xhtml로 생성한 경우 서버는 페이지의 응답 Content-Type을 "application/xhtml+xml"로 반환한다. 그렇지 않은 경우 보통 "text/html"로 반환하고 페이지 에러가 발생하게 된다.)
- Content-Type: text/html
- (문법오류):
- Content-Type: application/xhtml+xml
- 결과(성공)페이지:
4. 파일의 확장명을 *.xhtml로 생성하거나, 응답 Content-Type을 "application/xhtml+xml"로 지정한 경우 브라우저는 자동으로 XML 유효성 검사를 실행하게 된다.(**IE를 제외한 대부분의 브라우저**)
즉, 개발 시 "W3C Validator"로 재 확인해 볼 필요없이 검증이 실시간으로 가능해지며, 그에 따른 개발 비용을 줄일 수 있있다.
- Chrome:
- Firefox:
5. "text/html" 응답 Content-Type에서 위 문제(</script> 문자열 사용?)를 해결할 수 있는 방법으로, 해당 태그 문자열을 아래와 같이 변경해 주면 된다.
- 소스보기는 위 HTML TAB 이동!!!
참고사이트:
XHTML과 CDATA의 문제점
http://kwon37xi.egloos.com/3798259
XHTML 에서 자바스크립트 사용하기
http://forums.mozilla.or.kr/viewtopic.php?f=9&t=3433
IE 버전을 알아내는 여러가지 구현 방법
IE 버전을 알아내는 여러가지 구현 방법
IE 버전을 알아 내는 "첫 번째 방법"은 보통 사용자 "Agent" 정보를 반환하는 "window.navigator.userAgent" 속성 과 간단한 정규식을 활용해 위와 같이 해당 IE 버전을 필터링 하여 반환 받을 수 있다.
또한, 두 번째 방법으로는 "HTML 조건부 주석"을 활용한 방법으로 while 문 안에서 각 버전(IE4+)별 조건부 주석을 모두 실행하여, 해당 버전이 일치할 시 조건부 주석 안의 "i" 태그가 미리 생성된 div 태그에 포함(innerHTML 속성 사용) 된다.
즉, 미리 생성된 f 컬렉션은 하나의 "i" 태그를 포함하게 되므로 "!f[0]" 가 조건부인 "while 순회문"은 빠져나오게 되는 것이다.
P.S: 두 번째 코드는 아래 사이트를 참고하여, 알아보기 편하게(제 기준이지만;;) 코드를 변경하였습니다. 하지만 원본 코드의 간결함은 잃어 버린듯 합니다..^^;;
참고 사이트:
- userAgent sniffing을 사용하지 않고 IE의 버전 알아내기
http://codefactory.kr/2012/01/15/non-ua-based-ie-version-check/
"소셜 버튼" 생성 모듈 구현
1. 소셜 버튼 생성 모듈 구현
각종 SNS 서비스(트윗, 페이스북, 구글플러스)에서 제공하는 "소셜 버튼"을 생성하는 자바스크립트 모듈을 아래와 같이 구현해 보았습니다.
모듈에 대한 더 자세한 내용은 아래 링크(테스트, 메뉴얼)를 통해 확인 하실 수 있습니다.
테스트(예제) 페이지:
http://mohwa.org/html/twitter.html
모듈(sns.js) 메뉴얼:
http://mohwa.org/doc/sns/index.html
jsfiddle 소스:
http://jsfiddle.net/mohwa/mV7sU/
- 참고 사이트:
트위터 플러그인:
https://dev.twitter.com/docs/twitter-for-websites
구글플러스 플러그인:
https://developers.google.com/+/plugins/
페이스북 플러그인:
http://developers.facebook.com/docs/plugins/
미투데이 플러그인:
http://me2day.net/me2/plugin/guide/metoo_plugins
2. "트윗" 소셜 버튼 옵션 중 "data-dnt" 에서 DNT(Do Not Track)란?
사용자 브라우저의 DNT(do not track) 옵션 설정(유효)시 해당 사이트의 컨텐츠 커스터마이즈(사용자 정보 수집으로 인한 신규 컨텐츠 개발 및 수정)를 위한 사용자 정보 수집을 중지 시킨다.
예: 트위터 제공 컨텐츠 중 하나인 "추천 이용자" 또한 각 사용자 정보(Follow 데이타 등..)를 수집한 결과로 생산된 파생 컨텐츠이다.
DNT(do not track) 설정 방법:
1. 사용자 브라우저의 DNT 옵션 활성화 설정(사파리 기준).
2. 사용자 브라우저의 DNT 활성화 설정 유/무 에 따른 "HTTP Request Header" 비교 이미지.
2.1: 비활성 시 화면
2.2: 활성 시 화면
위 결과와 같이 "DNT" 옵션 설정 유/무 에 따라 "HTTP Request Header"에 "DNT" 헤더가 추가 요청되며, 요청받은 웹 사이트에서는 요청된 "DNT" 헤더를 확인 후 이 사용자에 대해서는 어떠한 "정보 수집" 등의 "트래킹" 행위를 중지 하게 된다.
당연한 얘기지만, 사용자 브라우저 설정(옵션)에 따라 헤더(DNT)값이 서버로 요청될 뿐, 로그 수집과 관련된 모든 권한은 해당 웹 사이트가 가지고 있는 것이다.
즉, 컨텐츠 제공자에게 사용자 정보 수집 중지에 관한 강제성이 존재하지 않으며, 이에 따라 결국 사용자는 DNT가 지원되는 사이트(트위터 등)에서만 정보 수집에 관한 "중지" 권한을 보장받을 수 있는 것이다.
DNT(do not track) 관련 참고 링크:
트위터 프라이버시 보호 기능이란?
브라우저 추적 거부 설정이란?
http://japanese.engadget.com/2012/05/18/twitter-do-not-track/
DNT 기능이란?
http://buzz.tistory.com/entry/DNTDo-Not-Track
자바스크립트 인터페이스 구현
1. 제약사항(C# 기준)
1. 스스로의(추상클래스 자신) 객체를 가질 수 없다.
2. 선언된 인터페이스의 메서드는 상속받은 일반클래스(구현클래스)에서 반드시 전부 구현되어야 한다.
3. 추상클래스와 달리 일반 속성(Attribute) 및 메서드(Method)를 정의할 수 없다.
4. 다중상속이 가능하다.
2. 다중상속 예제 코드:
01: using System; 02: 03: namespace ConsoleApplication2 04: { 05: interface IMy 06: { 07: void abc(); 08: } 09: 10: interface IYou 11: { 12: void abc(); 13: } 14: 15: class CMy : IMy, IYou 16: { 17: void IMy.abc() 18: { 19: Console.WriteLine("My"); 20: } 21: 22: void IYou.abc() 23: { 24: Console.WriteLine("You"); 25: } 26: } 27: 28: class Program 29: { 30: static void Main(string[] args) 31: { 32: CMy m = new CMy(); 33: ((IMy)m).abc(); 34: ((IYou)m).abc(); 35: } 36: } 37: }[출처] [C#] 인터페이스 다중 상속과 구현|작성자 씨피유
출처: http://blog.naver.com/PostView.nhn?blogId=thx4alice&logNo=110023547339
3. 자바스크립트 인터페이스 구현
// IUser 인터페이스 var IUser = (function(){ var iUser = function(){ // 자기 자신의 객체 생성을 막기 위한 추가 소스 if (this.constructor === iUser){ throw new Error('정의된 인터페이스는 자기 자신의 객체를 가질 수 없습니다.'); } else{ return this; } }; var prototype_members = { // 메서드 getId: function(){ }, setId: function(){ } }; for (var n in prototype_members) iUser.prototype[n] = prototype_members[n]; return iUser; })(); // IBoard 인터페이스 var IBoard = (function(){ var iBoard = function(){ // 자기 자신의 객체 생성을 막기 위한 추가 소스 if (this.constructor === iBoard){ throw new Error('정의된 인터페이스는 자기 자신의 객체를 가질 수 없습니다.'); } else{ return this; } } var prototype_members = { // 메서드 getBoard: function(){ }, setBoard: function(){ } }; for (var n in prototype_members) iBoard.prototype[n] = prototype_members[n]; return iBoard; })(); // User Entitie var UserEntitie = new (function(){ var userEntitie = function(){ this.id = ''; return this; } return userEntitie; }())(); // 정의된 인터페이스(IUser) 메소드들을 상속받은 일반 클래스(User1)에서 구현한다. var User1 = interfaceInherit(IUser, { // Repository getId: function(){ return UserEntitie.id + '의 아이디 입니다.'; }, setId: function(id){ UserEntitie.id = id; return this; } }); // 정의된 인터페이스(IUser, IBoard) 메소드들을 다중 상속([IUser, IBoard]받은 일반 클래스(User2)에서 구현한다. var User2 = interfaceInherit([IUser, IBoard], { // Repository getId: function(){ return UserEntitie.id + '의 아이디랑꼐!!!!'; }, setId: function(id){ UserEntitie.id = id; return this; }, getBoard: function(){ return this; }, setBoard: function(){ return this; } }); // 인터페이스 상속(다중) 및 구현 function interfaceInherit(_interfaces, opt){ var o = {}; // 인터페이스 메서드 카운트 var interfaceMethodCount = 0; // 일반클래스(구현클래스)의 인터페이스 메서드 구현 카운트 var classMethodCount = 0; _interfaces = _interfaces.length ? _interfaces : [_interfaces]; for (var i = 0, length = _interfaces.length; i < length; i++){ var _interface = _interfaces[i]; var F = function(){}; for (var n in _interface.prototype){ F.prototype[n] = _interface.prototype[n]; } var $F = _interface.call(new F()); for (var n in $F){ // 인터페이스에 정의된 함수만 구현 가능하다. if (Object.hasOwnProperty.call(opt, n)){ o[n] = opt[n]; classMethodCount++; } interfaceMethodCount++; } if (interfaceMethodCount !== classMethodCount){ // 일반 클래스(구현 클래스)에 정의된 인터페이스 메서드의 구현 메서드가 없을떄.. throw new Error('상속된 인터페이스 메서드가 구현(모두)되지 않았습니다.'); return {}; } } return o; } alert(User1.setId('xanione').getId()); alert(User2.setId('yanione').setBoard().getBoard().getId());
예제 실행 URL:
http://jsfiddle.net/jeonseounggyun/jML3y/
참고 URL:
1. 인터페이스를 사용하는 이유는 몰까?
2. 추상클래스와 인터페이스의 사용
http://blog.daum.net/question0921/1056
3. 인터페이스와 다중상속
4. 인터페이스 사용이유?
http://www.okjsp.pe.kr/seq/161248
자바스크립트 추상 클래스 구현
- 추상클래스 분류:
Animal(동물), Felidae(고양이과), Canidae(개과)
- 일반클래스(구현클래스) 분류:
하마, 사자, 고양이, 호랑이, 늑대, 개
1. 각 단어에 대한 의미
추상: 덜 구체화된 무엇.
객체: 상태(Attribute)와 행동(Method)을 가진 것.
클래스: 객체 생성을 위한 일종의 도면(설계도, 청사진).
초기화: 정의된 클래스를 이용하여 객체를 생성(인스턴스 생성)하는 것.
2. 제약사항(C# 기준)
1. 스스로의(추상클래스 자신) 객체를 가질 수 없다.
2. 선언된 추상클래스의 추상 메서드는 상속받은 일반클래스(구현클래스)에서 반드시 전부 구현되어야 한다.
3. 클래스(추상)가 메서드(추상)를 반드시 포함하지 않더라도 abstract 키워드가 있다면 추상클래스가 된다.
4. 일반 속성(Attribute) 및 메서드(Method)를 정의할 수 있다.
3. 추상클래스(Animal(동물))는 왜 객체를 가질 수 없는가?
위 "1. 단어에 대한 의미"에서 "객체"란 상태(Attribute)와 행동(Method)을 가진것이라 이미 언급하였다.
또한, "추상"이란 덜 구체화된 무엇을 뜻하며, 이는 "객체"가 반드시 가져야할 상태(Attribute)와 행동(Method(구현되지 않은 추상 메서드))을 갖지 못했다는 의미로 볼 수 있다.
즉, 이를 요약하면, "넌 너무 추상적인 클래스(설계도, 청사진)를 가졌으니 객체를 만들 수 없다!!!(인용)" 라는 의미로 보면 될듯하다.
4. 자바스크립트 추상 클래스 구현
/** * * 추상클래스(ABoard)가 가진 기본적인(C# 기준) "제약"과 같이 자기 자신의 객체를 가질 수 없다. */ var ABoard = (function(){ var aBoard = function(){ this.id = ''; this.name = ''; // 자기 자신의 객체 생성을 막기 위한 추가 소스 if (this.constructor === aBoard){ throw new Error('정의된 추상클래스는 자기 자신의 객체를 가질 수 없습니다.'); } else{ return this; } }; var prototype_members = { getId: function(){ return this.id; }, setId: function(id){ this.id = id; return this; }, getName: function(){ return this.name; }, setName: function(name){ this.name = name; return this; }, view: function(){ }, write: function(){ } }; for (var n in prototype_members) aBoard.prototype[n] = prototype_members[n]; // 기존 OOP 언어의 abstract "키워드"와 같이 아래 처럼 추상메서드를 선언이 가능하다. aBoard.prototype.view.isabstract = true; aBoard.prototype.write.isabstract = true; return aBoard; })(); // 상속받은 추상 메소드를 구현한다.(자유게시판) var Free = abstractInherit(ABoard, { // Repository view: function(){ alert(this.id + '님의 이름은 ' + this.name + '입니다.'); }, write: function(){ alert('write ok!!!'); return this; } }); // 상속받은 추상 메소드를 구현한다.(QA게시판) var QA = abstractInherit(ABoard, { // Repository view: function(){ alert(this.name + '님 안녕하세요!!!!'); }, write: function(){ alert('write ok!!!'); return this; } }); // 일반클래스(구현클래스)에 정의된 추상클래스 상속함수 function abstractInherit(_abstract, opt){ var o = {}; // 추상 클래스의 추상 메서드 카운트 var abstractMethodCount = 0; // 일반 클래스의 추상 메서드 구현 카운트 var classMethodCount = 0; var F = function(){}; for (var n in _abstract.prototype){ F.prototype[n] = _abstract.prototype[n]; } var $F = _abstract.call(new F()); for (var n in $F){ o[n] = $F[n]; if (opt[n]) o[n] = opt[n]; if ($F[n].isabstract) abstractMethodCount++; if ($F[n].isabstract && opt[n]) classMethodCount++; } if (abstractMethodCount !== classMethodCount){ // 일반 클래스(구현 클래스)에 정의된 추상 메서드의 구현 메서드가 없을떄.. throw new Error('상속된 추상 메서드가 구현(모두)되지 않았습니다.'); return {}; } else { return o; } } Free.setId('yanione1').setName('전성균1').write().view(); QA.setId('yanione2').setName('전성균2').write().view();
예제 실행 URL:
http://jsfiddle.net/jeonseounggyun/Cavbe/
출처 및 참고 URL:
1. 추상 클래스의 존재 이유
2. 왜 추상 클래스를 사용하게 될까?
자바스크립트 문서화를 위한 "jsdoc toolkit" 사용법 및 예제
자바스크립트 문서화를 위한 "jsdoc toolkit" 사용법 및 예제
1. jsdoc tookit-2.4.0.zip(현재 버전 기준)을 다운받아 적당한 위치에 압축을 해제한다.
2. jsdoc toolkit 실행
- Mac OS 기준:
터미널 접근 후 해당 폴더(jsdoc tookit 루트 폴더)에 위치하여 아래 명령어를 실행한다.
java -jar jsrun.jar app/run.js javascript_doc_test.js(jsdoc을 활용해 변환시킬 *.js 파일) -t=templates/jsdoc -d="out"(이와 같이 디렉토리를 지정(-d="out")하면 현재 위치(jsdoc 루트 폴더)에 ".out" 폴더가 생성되며, 그 아래 index.html(root file), symbols(하위 file을 포함하는 디렉토리)가 추가적으로 생성된다.
- Window OS 기준:
아래 링크를 참고해 "java"를 다운받아 설치한 후 OS 환경변수를 설정한다.
- 자바(java) 설치 및 환경변수 설정...
http://caskers.tistory.com/372
윈도우 명령프롬프트(커멘드창) 접근 후 해당 폴더(jsdoc tookit 루트 폴더)에 위치하여 아래 명령어를 실행한다.
java.exe -jar jsrun.jar app/run.js javascript_doc_test.js -t=templates/jsdoc -d="out"
3. jsdoc toolkit 작성법
@namespace: 네임스페이스 설명(javascript를 이용한 MVC Pattern 구현)
@author: 작성자(<a href="http://mohwaproject.tistory.com">mohwa</a>)
@version: 버전(0.1)
@since: 작성일(2012.08.)
@see: 참조 문서 및 메서드
@description: 상세 설명
@class: 클래스 설명(MVC Data Model 중 하나로 등록된 각 데이터 모델(Object)을 갱신 및 mvc.Entities.cookie 클래스를 통해 유지 시킨다.)
@constructor 함수가 생성자일 경우만 표기(Entities Class 생성자 함수)
@param 해당 매개변수({String} memberName 등록된 Entities 객체 구분 key(mvc.Entities[key] 암묵적 전역 변수에 객체(this)가 선언 및 정의한다.))
@type 리턴 데이터 타입(Object)
@returns 리턴값(해당 context)
@example 예제코드(mvc.Entities('board');)
@private: 해당 함수가 private(지역)일 경우만 표기
@public: 해당 함수가 public(공공)일 경우만 표기
@static: 해당 함수가 static(정적)일 경우만 표기
4. 참조 사이트:
jsdoc toolkit:
http://code.google.com/p/jsdoc-toolkit/
mvc.js jsdoc:
http://mohwa.org/doc/mvc/index.html
jundo jsdoc:
http://dev.iamdenny.com/Drag-Drop/doc/index.html
Javascript MVC 패턴 구현
Javascript MVC 패턴 구현
1. MVC 패턴 정의:
하나의 응용 프로그램을 Model(데이터)계층, View(표현(페이지랜더링))계층, Control(User Interation)계층으로 분리하는 디자인 패턴 중 하나이다.
2. javascript MVC 패턴 정의:
Model: 데이터 객체를 저장하는 창고로 쓰이며, View나 Controler에 대해서 전혀 신경 쓸 필요가 없고, 모델은 데이터, 데이터와 직접적으로 관련이 있는 로직만을 포함하는 것이 좋다.
즉, "이벤트 처리 코드", "뷰 템플릿" 과 같이 모델과 관련 없는 로직등은 포함하지 말아야 한다.
View: 사용자와의 상호작용을 맡는 계층이며, 보통 HTML, CSS, 자바스크립트 템플릿으로 View를 구성한다.
Model과 마찬가지로 View 또한, 에플리케이션의 다른 부분(계층)과 분리되어야 한다.(Controler나 Model 객체와 독립적이어야 한다는 뜻이다.)
Controler: Model과 View 사이의 접착제 역활을 하며, 보통 이벤트를 통해 갱신된 데이터를 Model에 적용하고 그 결과를 View에 반영 시킨다. 또한, 보통 Controler객체 초기화(init)시 각 이벤트 리스너를 추가시키는 로직을 구성한다.
3. 구현한 MVC 패턴 정의:
Model: 등록된 Data Model인 "Concrete(Function 구성)" 객체를 통해 데이터를 Controler에 반환하고, "Entitie(Object(json)구성)" 객체를 통해 등록된 각 데이터 모델을 갱신하고, 유지(Cookie 사용)시킨다.
View: Controler를 통해 등록된 View(Function)를 호출 한다.
Controler: Model과 View 사이의 접착제 역활을 하며, 각 이벤트들을 통해 호출 시킨다.
또한, Model(Concrete, Entitie)를 통해 반환된 결과를 View에 반환 후 호출(렌더링)시킨다.
MVC.js URL:
http://img.fpscamp.com/js/mvc/mvc.js
테스트 URL:
ps. 아직 각 브라우저의 몇가지 잔존 버그가 존재합니다.(테스트 시 크롬 브라우저를 이용을 권장드립니다.^^;;)
4. 실행 예제
// Entities mvc.Entities('board').append('info', {id: 'yanione', name: 'yanione_name'}); // Concretes mvc.Concretes('board').append('view', function(entitie){ this.callback(entitie); }); // Views mvc.Views('info').append('render', function(ret){ for (var n in ret){ document.body.innerHTML += n + '=' + ret + '
'; } }); window.onload = function(e){ // Controls, Models mvc.Controls('boardInfo', mvc.Models(mvc.Concretes.board, mvc.Entities.board), mvc.Views.info).exec('view', 'render', 'info'); }
http://mohwa.org/doc/mvc/index.html
LazyImageLoader.js(점진적 이미지 로딩)
LazyImageLoader.js
얼마전 @niceaji님을 통해 알게 된 Jquery 확장 기능인 LazyLoad.js를 테스트 해보니 몇가지 버그가 존재하는것을 발견하였습니다.
@niceaji 님의 포스트: http://uix.kr/archives/1088
코드 전체를 분석해 보지는 않았지만, 핵심 기능인 가시거리(좌표)내의 이미지 로딩이 제대로 되지 않는 버그가 존재 했으며,(가시거리 수치가 잘못 계산된 탓인지? 로딩 시 수치 밖의 이미지까지 로딩되는 버그.) 또한 IE 브라우저에서는 스크립트 오류가 발생하기도 했습니다.(오류는 발생하지만 기능은 정상적으로 수행됩니다;;;)
아래는 해당 기능(점진적 로딩)과 몇 가지 기능을 추가하여, 재 작성된 소스 코드 링크 및 사용 방법 입니다.
1. jsbin 소스 링크:
http://jsbin.com/owayim/11/edit
2. 모듈 사용방법
LazyImageLoader({ onload: function (e, elem) { //alert(elem); }, onerror: function (e, elem) { }, loadingImage: '', loadIntervalTime: 30 });
onload: 각 이미지 로딩 시 이벤트 핸들러
onerror: 각 이미지 로딩 에러 시 이벤트 핸들러
loadingImage: 각 이미지 로딩 전 Default 이미지 경로
loadIntervalTime: 각 이미지 로딩 시간 간격
3. <img> 태그 정의
<img data-name="lazy" data-src="http://img.vaanonline.co.kr/upload/screenshot/120705/120705adiifqytcrimqb.jpg" /> <img data-name="lazy" data-src="http://img.vaanonline.co.kr/upload/screenshot/120705/120705adiifqytcrimb.jpg" /> <img data-name="lazy" data-src="http://img.vaanonline.co.kr/upload/screenshot/120705/120705adiifqytcrimqb.jpg" /> <img data-name="lazy" data-src="http://img.vaanonline.co.kr/upload/screenshot/120705/120705adiifqytcrimqb.jpg" />
data-name: "lazy"
data-src: 대치 이미지 경로
자바스크립트 (Singleton, Factory, Chain, Interator) Pattern 구현
Singleton Pattern
함수클래스의 객체를 단 "하나"만 생성하게 만드는 디자인 패턴.
즉, 동일한 함수클래스 호출 시 반환되는 두번째 객체 부터는 이전에 생성된 객체를 반환하게 된다.
-
var Singleton = (function () {
-
-
var that = null;
-
-
var Singleton = function () {
-
-
if (that) return that;
-
-
that = this;
-
-
return that;
-
}
-
-
return Singleton;
-
-
})();
-
-
function User() {
-
return this;
-
}
-
-
var obj1 = Singleton();
-
var obj2 = Singleton();
-
-
//alert(obj1 === obj2); // true
-
//alert(new User() === new User()); // false
Factory Pattern
사용자가 구체적인 클래스 정보를 모르고도 빌드(객체 생성 캡슐화)를 통해 객체를 생성할 수 있도록 만드는 디자인 패턴.
아래 코드에서는 클래스 타입 뿐 아니라 해당 클래스의 매개변수까지 넘겨 객체를 반환할 수 있게 설계 되었다.
-
var Factory = (function () {
-
-
var Factory = function () {
-
-
var ns = arguments[0].split('.')
-
, parent = eval(ns[0])
-
, childs = ns.slice(1);
-
-
for (var i = 0, length = childs.length; i < length; i++) {
-
-
if (!parent[childs[i]]) break;
-
-
parent = parent[childs[i]];
-
}
-
-
// parent.apply(obj, []) 함수의 반환값은 parent 함수(User)를 실행시킨 결과 return this(window object) 이다.
-
function T(args) { return parent.apply(this, Array.prototype.slice.call(args, 1)); };
-
-
T.prototype = parent.prototype;
-
-
return new T(arguments);
-
}
-
-
return Factory;
-
-
})();
-
-
-
function User(name, score) {
-
this.name = name;
-
this.score = score;
-
-
return this;
-
}
-
-
User.prototype.getName = function () {
-
return this.name;
-
}
-
-
User.prototype.getScore = function () {
-
return this.score;
-
}
-
-
User.name1 = function (name, score) {
-
this.name = name;
-
this.score = score;
-
return this;
-
}
-
-
User.name1.prototype.getName = function () {
-
return this.name;
-
}
-
-
User.name1.prototype.getScore = function () {
-
return this.score;
-
}
-
-
-
var obj1 = Factory('User', 'user1', 1);
-
var obj2 = Factory('User.name1', 'user2', 2);
-
-
alert(obj1.getName());
-
alert(obj1.getScore());
-
-
alert(obj2.getName());
-
alert(obj2.getScore());
Chain Pattern
해당 객체를 메서드의 반환 값으로 지정하여 연속된 메서드를 호출할 수 있도록 만드는 디자인 패턴이다.
-
var Chain = new (function () {
-
-
var Chain = function () {
-
-
this.name = '';
-
this.age = 0;
-
-
return this;
-
};
-
-
Chain.fn = Chain.prototype = {
-
-
getName: function () {
-
return this.name;
-
},
-
setName: function (name) {
-
this.name = name;
-
return this;
-
-
},
-
getAge: function () {
-
return this.age;
-
},
-
setAge: function (age) {
-
this.age = age;
-
return this;
-
}
-
};
-
-
return Chain;
-
-
}())();
-
-
//alert(Chain.setName('test').getName()); // test
-
//alert(Chain.setAge(10).getAge()); // 10
-
//alert(Chain.setName('test').setAge(10).getAge()); // 10
Interator(반복자) Pattern
기능의 세부적인 구현을 외부로 노출시키지 않고, 컨테이너(Interator(arguments)의 요소에 차례대로 접근할 수 있는 방법(.each())을 제공하는 디자인 패턴
-
var Interator = (function () {
-
-
var Interator = function () {
-
return new Interator.fn.init(arguments);
-
};
-
-
Interator.fn = Interator.prototype = {
-
init: function (arguments) {
-
this.arguments = arguments;
-
return this;
-
},
-
each: function (callback) {
-
-
callback = typeof callback === 'function' ? callback : function () { ; };
-
-
for (var i = 0, length = this.arguments.length; i < length; i++) {
-
-
var argument = this.arguments[i];
-
callback.call(argument, i);
-
}
-
}
-
};
-
-
Interator.fn.init.prototype = Interator.prototype;
-
-
return Interator;
-
-
})();
-
-
-
Interator(1, 2, 3).each(function (i) {
-
alert(this + ',' + i);
-
});
자바스크립트 Mediator(중재자) Pattern 과 Facade Pattern 구현
Mediator(중재자) Pattern
객체 설계 시 최대한 객체간의 결합도를 낮춰, 필요 시 유지보수가 용이한 형태로 설계되야 한다.
즉, 객체간의 결합도가 높아지면 높아질수록, 유지보수(수정 비용) 비용 또한 올라간다. 중재자 패턴은 이런 문제를 완하하기 위한 디자인 패턴이며, 아래 코드의 독립된 객체(user1 ~ user4)들은 자신의 상태(score)가 변경되면, 이를 중재자에게 알리고(Mediator.play()), 점수판 객체(Score)의 update 메서드를 호출해 모든 플레이어들이게 변경사항을 통지한다.
- 점수판 객체(Score)는 어떤 유저에 관한 정보도 일체 알지 못하며, 어떤 정보도 저장하지 않는다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title></title> <script type="text/javascript"> //<![CDATA[ // Mediator(중재자) Pattern var Mediator = new (function () { var Mediator = function () { this.mediators = []; return this; } Mediator.fn = Mediator.prototype = { make: function (user) { if (!user) return false; this.mediators.push({ user: user }); return this; }, remove: function (user) { for (var t in this.mediators) { if (user) { if (this.mediators[t].user === user) { delete this.mediators[t]; } } else { delete this.mediators[t]; } } return this; }, play: function () { var names = [] , scores = []; for (var n in this.mediators) { names.push(this.mediators[n].user.name); scores.push(this.mediators[n].user.score); } var score = new Score(); score.update.apply(score, [names, scores]); } } return Mediator; } ())(); function Users(name) { this.name = name; this.score = 0; // 플레이어 목록 추가 Mediator.make(this); return this; } Users.prototype.play = function () { this.score++; // boardcast call Mediator.play(); return false; } function Score() { return this; } Score.prototype.update = function (names, scores) { var elem = document.getElementById('userScoreBoardList') , h = []; for (var t in names) { h.push('<li>' + names[t] + '님의 점수는 ' + scores[t] + '</li>'); } elem.innerHTML = h.join(''); return this; } window.onload = function () { user1 = new Users('user1'); user2 = new Users('user2'); user3 = new Users('user3'); user4 = new Users('user4'); //Mediator.remove(user4); } //]]> </script> </head> <body> <a href="#" onclick="return user1.play()">user1</a> <a href="#" onclick="return user2.play()">user2</a> <a href="#" onclick="return user3.play()">user3</a> <a href="#" onclick="return user4.play()">user4</a> <ul id="userScoreBoardList"></ul> </body> </html>
Facade Pattern
사용되는 빈도가 높은 메서드들을 하나로 감싸 새로운 메서드를 만들어 좀 더 편리한 API를 제공하는 디자인 패턴이다.
가장 대표적인 예로 아래와 코드에서 처럼 크로스 브라우징을 위한 DOM Event 할당 함수(addEventListener, attachEvent)를 꼽을 수 있다.
var Facade = new (function () { var Facade = function () { return this; } Facade.fn = Facade.prototype = { bind: function (elem, type, handler, capture) { type = typeof type === 'string' ? type : ''; handler = typeof handler === 'function' ? handler : function () { ; }; capture = capture || false; if (elem.addEventListener) { elem.addEventListener(type, handler, capture); } else if (elem.attachEvent) { elem.attachEvent('on' + type, handler); } return this; }, unbind: function (elem, type, handler, capture) { type = typeof type === 'string' ? type : ''; handler = typeof handler === 'function' ? handler : function () { ; }; capture = capture || false; if (elem.removeEventListener) { elem.removeEventListener(type, handler, capture); } else if (elem.detachEvent) { elem.detachEvent('on' + type, handler); } return this; } } return Facade; } ())(); window.onload = function () { var btn1 = document.getElementById('btn1'); var btn1_callback = function () { alert('btn1'); return false; }; var btn2 = document.getElementById('btn2'); var btn2_callback = function () { alert('btn2'); return false; }; Facade.bind(btn1, 'click', btn1_callback).unbind(btn1, 'click', btn1_callback); Facade.bind(btn2, 'click', btn2_callback); }