블로그 이미지
윤영식
Frontend Application Architecter, Full Stacker, KnowHow Dispenser and Bike Rider

Publication

Statistics Graph

Recent Comment

2016.11.23 16:50 Electron & Ionic

Electron을 통한 테스트 자동화 접근법 세션


- 정적 테스트 프로그램은 테스트 프로그램이 있는 것, 동적 테스트는 기존 애플리케이션을 통해 테스트 하는 방식. 

- ATDD 수용성 테스트는 E2E 테스트를 한다. 

  + Selenium -> WebDriver

  + Nightwatch


- Electron 

  + Node Based Desktop Application

  + View렌더링을 위한 브라우져를 가지고 있으므로 전통적은 Hybrid는 아니다. 전통적인 Hybrid는 view를 쓰기위해 webview를 쓰고 이에 대한 브라우져가 os에 설치되어 있어야 view 표현이 가능했다. 그러나 eletron은 view를 내장하고 있고 standalone으로 application구현이 가능하다.

  + render process (chrome) + main process (node) 간에 RPC통신을 한다. 


- Psyclone: Automated Dynamic Testing

  + https://github.com/firejune/psyclone 

  + Node Canvas: main process에서 수행됨

  + Environment: PTY.js, openCV (게임의 이미지 체크)




Javascript playground 세션


- Swift playground와 같은 형태이다.

- Runtime Context Visualizer 구현하기 

  > 내가 찍어 놓은 console.log를 추적 

  > let stack = new Error().stack 강제 로그 stack-trace 남기기

  > 외계어 스터디 (구글검색하면 나옴): 개발을 모르는 사람들에게 무언가 가르칠 때 힘들다. 코딩하는 것을 비쥬얼라이징 해보자. 

- V8 엔진은 Debugging이 가능한 API를 가지고 있다. 

  > node의 vm module을 사용: v8내에서 다양하게 쓰이는 것을 외부로 노출해 준다.

     runInContext, runInNewContext 등등

- node-inspector

  > IDE 수준의 code base로 꽤 큰 프로젝트

  > DEBUG=*node-debug app.js 하면 node debugging 을 inspector로 가능하다 

  > node v6.3.1 에서만 작동한다. node에 inspector를 merge하는 작업 진행중. 

     v8-debug : node <-> inspector간 내용

     devtools : inspector <-> chrome devtools간 내용


- Node debug mode 를 이용해 자바스크립트 내용을 축출한다

  > node --debug --debug-port=5859 --debug-brk app.js

      Debugger listening:5859

  > v8 debugging protocol using http

  > 전문의 body에 seq, type 이 들어간다. 

     type = request + response + event 포함 


- Node debugger Command 

  > continue : 코드 진행 next, in, out, min

  > backtrace : 코드가 멈춰있을 때 모든 정보를 가져온다 

  > frame : 방금 실행한 것을 이전 상태로 rollback에서 수행 가능하다 

  > setVariableValue : runtime의 로컬 변수를 직접 수정

  > lookup : 로컬 변수로 watching 모니터링 할 수 있다. 


해당 명령을 tcp로 node debugger에 쏴주면 된다. @node/lib/_debugger.js 가 위의 명령어를 사용하고 있다. 

  > npm install v8-debugger


- Javascript Playground 

  > 왼쪽 자바스크립트 코드 오른쪽 결과 값을 보여주기 화면을 제작한다

  > onResponse 핸들러에서 결과 값을 받는다. 

  > 코드의 의미 파악: 식, 문을 파악해야 함 -> Javascript Parser 필요, esprima 파서 

     esprima.parse(코드) 결과는 각 진행 수선의 type을 전달 하는 메타 정보를 준다

  > Runtime Context Visualizer

     https://github.com/ibare/jsplay


 


참조


http://techblog.daliworks.net/Nightwatchjs/ 

신고
posted by peter yun 윤영식
2015.05.15 11:38 React

ReactJS(리액트)는 자바스크립트로 UI 컴포넌트를 만드는 프레임워크이다. 만들어진 컴포넌트를 사용할 수도 있고, 수정할 수 있고, 조합할 수 있으며 자신만의 UI 컴포넌트를 직접 만들 수 있다. 즉 프론트앤드 UI의 화면을 컴포넌트 조합으로 만들고, 화면의 데이터를 앵귤러처럼 자동 업데이트 해주지만 앵귤러와 틀리게 단방향 데이터 바인딩이다. 리액트는 앵귤러(AngularJS)의 지시자(Directive)와 비교되지만 훨씬 간단하고 성능 또한 월등하다. 이제 배우고 익혀 사용할 때가 되었다. 







개념잡기 


  - 쿼라(Quora)에서 이야기하는 장/단점을 살펴보자. 

     장점

       + Virtual DOM 을 JS로 구현해서 UI 컴포넌트의 속도가 엄청 빠르다. 

       + Component의 재사용과 복잡한 UI 컴포넌트 조합이 가능하다.

       + Uni-direction(단방향) 방식하에 데이터가 변경되면 관련된 모든 UI 컴포넌트가 변경된다.

       + commonJS / AMD 패턴과 잘 조합되고, 크롬 익스텐션을 통해 디버깅할 수 있다. 

     단점

       + 초보자들에겐 역시 러닝 커브가 존재한다.

       + 다른 프레임워크가 동작하기 위해선 부가적인 작업들이 필요하다. 

       + 앵귤러처럼 router, model등 Frontend Full Framework을 제공하지 않아서 꼭 다른 프레임워크와의 조합이 필요하다. 


  - React Starting 동영상으로 기본개념을 잡아 보자.

     


  - 프리젠테이션으로 정리해 보자. 재미있게 진행되니 WTF는 날리지 말자.

     

  - egghead.io 에서 리액트에 관련하여 ReactJS, React Native, Flux Architecture를 동강으로 제공한다. 물론 무료가 있다. 
    * 유료강좌를 듣길 추천한다. 앵귤러와 리액트에 대한 좋은 강좌가 많다. 한달 대략 15달러
    + Render MethodProperties, State 사용하기

  - 제이쿼리를 리액트로 바꾸는 과정을 잘 설명해 주고 있다. 글을 읽고 다시 egghead.io 를 보면 이해가 될 것이다. 

    + jQuery to React 가이드

       내용중에 앵귤러를 사용하고 있는 개발자라면 앵귤러의 지사자에서 scope: { createXXX: '&' } 방식으로 자식의 부모의 함수를 호출 할 수 있다

       그리고 자식, 부모간에 scope 객체의 상속을 통해 scope 속성을 접근할 수 있다는 것도 알 수 있다. 

    + Flux 소개 아래 영상을 보면 react가 Virtual DOM을 통해 더 낳은 성능과 단순성을 통한 버그 가능성 제거를 이룰 수 있는지 가늠할 수 있다

       * Flux 사이트

      


  - 이제 다시 설치부터 기초 개념을 문서를 통해 쭉 살펴보자. 

  - ng-conf 말고 react-conf도 있다. 동영상을 통해 향후 방향을 점쳐보자. 
    

  - 리액트 컴포넌트를 찾고 싶을 경우 


  - 리액트 자료 

    + Awesome 자료 목록들

    + 앵귤러와 결합해서 사용하기 : NGREACT 


  - 리액트 컴포넌트 프레임워크 : 트위터 부트스트랩같은 조합

   + reapp.io


  - 새 술은 새 푸대에 넣자. 리액트가 UI 컴포넌트라면 Webpack 또는 Browserify 를 이용해 모듈화 하자
    + 리액트를 위한 웹팩의 starter kit

  - 디버깅은 Chrome Extention 설치하고 시작
  - 필요에 맞는 툴과 환경을 선택한다.

 


Immutable Data에 대한 이해 

불변 데이터에 대해 알아 두어야 한다. 예로 리스트를 생성하고 거기에 새로운 값을 넣으면 리스트를 가르키는 레퍼런스는 같을까 틀릴까? 기존 방식이라면 동일한 레퍼런스이겠지만 Immutable의 세계에 오면 값이 변경 되면 새로운 객체가 된다. 리액트에서는 성능향상을 위해 Immutable.js를 사용토록 권장하고 있다. 이것에 대해 발표한 영상을 보고 영상을 요약한 블로그 글을 보도록 한다. 
  - 영상 설명 블로그 [1], [2], [3]
  - 발표 영상

  - 최근 보고 있는 Clojure는 기본적으로 Immutable Data이다. 클로져 관련 블로그를 읽어보자.



자바스크립트 개념 장착

리액트를 하다 보면 this와 bind(this)를 자주 사용할 때가 있고, ES6로 전환하다보면 좀 더 빈번히 보게 된다. 제대로 이해하고 React 코드를 보자 
  - bind를 해주는 이유 Callback 때문 그렇다면 Callback을 이해하자
  - Callback은 자바스크립트가 Funtional Programming이 가능하게 해주고 Closure이다. 클로저를 이해하자
  - React에서 Object만드는 것이 많이 나오니 자바스크립트의 Object에 대해 알아보자
  - http://javascriptissexy.com/ 에서 다른 글도 참조하시라




React 와 Data Visualization의 결합 


   


React와 Flux 아키텍쳐를 통해 모던 웹 애플리케이션에서 기존 보다 성능 우위를 가지면서 대용량 데이터를 Data Visualization 할 수 있는 길을 볼 수 있다. 플럭스 아키텍쳐를 자신의 백앤드시스템에 어떻게 구성하느냐가 중요하겠다. Minko.io의 3D 렌더링 서비스 업체는 Flux와 React를 기존의 최신 기술로 어떻게 구현했는지 프리젠테이션을 통해 볼 수 있다. 당연히 D3.js를 통해 데이터 Data Visualization 하는 방법도 있다.


  - D3.js와의 만남

    + React와 D3를 통합하여 차트를 만드는 절차


  - Flux Architecture 구성으로 Meteor, Flux, React, Minko 3D 렌더링 엔진과 결합해서 Data Visualization 하기 

  - Flux Architecture를 구성해 대용량 데이터를 Data Visualization 하기
    
 
To Be Continued... 


저작자 표시 비영리 변경 금지
신고

'React' 카테고리의 다른 글

[React] Semantic-UI를 React 컴포넌트로 만들기 - 1  (0) 2015.08.23
[React] CSS Framework 선정하기  (0) 2015.08.15
[React] AngularJS와 ReactJS 비교  (0) 2015.07.01
[React] 배우는 방법  (0) 2015.05.15
posted by peter yun 윤영식
2014.12.24 14:53 Languages/Python

빠르게 메타지식을 흡수해 변환에 적응하는 능력을 지적 겸손이라 한다. 태도의 겸손이 아닌 내가 아는 것이 전부가 아니고 더 낳은 방법과 기술이 있다면 메타지식을 빠르게 흠수할 수 있는 능력이 필요한 시대가 되었다. 새로운 웹 개발언어로 성능과 생산성 증대를 목표로 하는 Dart에 대해 공부를 해본다.






중요 개념 


  - 모든 변수는 Object 이다. 

  - 정적 타입과 동적(dynamic) 타입이 가능하다   

  - 정적 타입 오류를 컴파일 타임에 알려준다

  - main() 펑션이 있다

  - public, protected, private 같은 것이 없고 _ (underscore)로 표현한다 

  - warning 은 프로그램이 수행 안될지도 모른다 이지만 수행을 막지는 않는다. 

    error가 컴파일 타임이 나면 수행할 수 없고 런타임에 발생하면 exception이 발생한다.  

  - 런타임 모드는 production 과 checked 두가지다. 개발시에는 checked 모드로 사용한다. 

     production 모드에서는 assert 구문을 무시한 최적화를 통해 성능을 향상시켜준다. 

  - 키워드 

   

    1 : built-in indentifier : 자바스크립트를 다트로 포팅을 쉽게 해준다. 

    2 : 제한적인 예약어로 비동기 지원과 관련이 있다. 

    



변수 (Variables)


  - 예 : 'Peter' 값을 가지는 String 객체의 레퍼런스 주소값을 name이라는 변수가 가지고 있다. 

var name = 'Peter';


  - 최기화 되지 않은 변수는 null 초기값을 갖는다. 숫자가 초기값이 없어도 null 초기값을 갖는다. 

    assert 구문은 production 모드에서 무시된다. 만일 assert 구문이 true가 아니면 exception을 던진다. 

int lineCount;

assert(lineCount == null);


  - 옵셔널 타입으로 String name = 'Bob'으로 직접 지정해 줄 수도 있지만 타입 스타일 가이드에 따라 var를 사용한다. swift와 유사함 

  - final은 변수의 값을 변경하고 싶지 않을 경우 var 대신 사용한다. const는 수치값을 지정한다. 

  - numbers, strings, booleans, lists, maps, symbols 관련 빌트인 타입을 가지고 있다. (예제 참조)

    + numbers : int, double 있고 이들은 num의 서브타입이다. 다트의 int와 자바스크립트 int는 틀리다. 다트 int는 arbitrary-precision integer

    + strings : UTF-16 코드를 따르고 ''  또는 "" 사용가능. 'hi peter ${expression}' 식으로 문자안에 ${} 표현가능. swift와 유사함

    + booleans : bool 타입으로 true, false를 값을 가져야 하고 자바스크립트와 틀리다. 즉, var name='pter'; if(name)하면 false이다. 

    + lists : 다트의 배열은 List 오브젝트이다. 인덱싱은 0부터 시작한다. GenericsCollections을 살펴보자 

    + maps : key-value에 대해 Map 오브젝트를 사용한다. JSON처럼 literal 지정 

    + symbols : Symbol 오브젝트를 통해서 operator와 identifier를 표현한다. 




펑션 (Functions)


  - 예 : 스타일 가이드에 따라 파라미터와 리턴 타입 지정한다. 

// 파라미터와 리턴 타입을 명시하는게 스타일 가이드 

void printNumber(num number) { 

  print('this is $number');


// 하지만 생략도 가능 

printNumber(number) 

  print('this is $number');

 


  - => expr;{ return expr; } 표현과 같다. coffeescript 같은 축약형 좋다. 하기 표현은 위 표현과 동치 

printNumber(number) => print('this is $number');


  - 옵션널 파라미터

    + 기본 설정 : enable(bool flag1, bool flag2) { ... }

    + Optional named parameter는 paramName: value로 지정 

       예) enable({bool flag1: false, bool flag2: true}) { ... } 사용 enable(flag1: true)

    + Optional positional parameter는 [] 마크를 사용

       예) say(String from, String msg, [String device]) { ... } 사용 say('hi', 'peter') 또는 say('hi', 'peter', 'ios')

  

  - 애플리케이션은 최상위 레벨에서 main() 펑션를 갖는다. 애플리케이션의 진입점역할을 한다. 자바와 유사함

    .. 오퍼레이터는 cascade operator이다. 즉, 이어서 호출한다. 

void main() {

  querySelector('#peter')

    ..text = 'Hi dowon'

    ..onClick.listen(reservedText);


  - Functions as first-class objects 이다. 펑션을 다른 펑션에 파라미터로 전달하거나 리턴하는 것이 가능. 이건 자바스크립트부터 쭉... 

printElm(element) {

  print(element);

}


var list = [1,2,3];

list.forEach(printElm); // printElm을 파라미터로 전달 


  - 자바스크립트는 function 레벨에서 lexical scope를 갖듯 다트도 lexical scope를 갖는다. 즉, 변수의 스코프가 정적으로 정해진다. (단, 자바스크립의 this는 호출되는 시점에 결정되므로 이부분에 틀림. 아래 참조 링크를 보자) 다트는 curly raches outwards를 따른다. (자바스크립트는 변수에 var를 줌으로 로컬 변수 스코프임을 지정한다) 

  - lexical closures는 lexical scope안의 변수를 접근하는 펑션 오브젝트이다. 

closure is a function object that has access to variables in its lexical scope, even when the function is used outside of its original scope.


  - 모든 펑션은 리턴값을 갖고 지정하지 않으면 return null; 이다. 




연산자 (Operators)


  - 연산자 종류 

    


  - 타입 테스트 오퍼레이터 

    



제어 흐름 (Control Flow Statement)


  - if(){ ... } else if() { ... } else { ... }

  - for ( 초기값 ; 비교 ; 증분 ) { ... } 또는 for in 

  - while() { ... } 또는 do { ... } while ()

  - while에서 break, for 에서 continue 

  - switch ~ case ~ default




예외처리 (Exceptions)


  - 다트의 예외는 unchecked exception 이다. 

  - 다트는 ExceptionError 타입을 제공한다. 

  - throw 하면 에러를 일으킨다. 

  - on catch 으로 exception을 catch 하고 전파되는 것을 막는다. 

try {

  aa();

} on OutofException {  // known exception

  bb();

} on Exception catch (e) { // anyting else that is an exception

  print('exception is: $e');

} catch (e) {

  print('really unknown : $e');

}

 

  - finally : finally가 수행된 후에 exception이 전파된다 




클래스 (Classes)


  - 다트는 객체지향 언어이다. 

  - new 키워드로 클래스의 인스턴스인 오브젝트를 생성한다. 

  - 클래스는 펑션과 데이터를 멤버로 갖고 특히 오브젝트의 펑션을 메소드라 부른다. dot(.)로 호출한다. cascade operator(..)은 싱글 객체의 멤버를 연속적으로 호출할 때 사용한다.

  - 생성자는 클래스와 같은 이름을 자고 this는 현재 인스턴스를 가르킨다. 자바와 유사

  - 생성자를 선언하지 않으면 아규먼트 없는 기본 생성자가 자동 제공됨. 자바와 유사 

  - 생성자는 상속되지 않는다. 

class Point {

  num x;

  num y;


  Point(this.x, this.y);

}


  - get, set 키워드를 통해 프로퍼티를 만들 수 있다. 

class Rectangle {

  num left;

  num top;


  Rectangle(this.left, this.top);


  num get right   => left;

         set right(num value) => left = value - left;

}


  - abstract class를 만들 수 있다. 상속은 extends를 사용함.  자바와 유사 

abstract class Door { 

  void open();

}


  - 연산자도 오버라이드 할 수 있음 

  - 모든 클래스인 암묵적으로 interface를 정의할 수 있다. 만일 A 클래스가 B의 구현체를 상속받지 않고 B의 API만을 사용하고 싶을 경우 implements 키워드를 사용한다. 자바에는 없는 재미난 부분

// A person. The implicit interface contains greet().

class Person {

  final _name;          // In the interface, but visible only in this library,

  Person(this._name);   // Not in the interface, since this is a constructor.

  String greet(who) => 'Hello, $who. I am $_name.'; // In the interface.

}


// An implementation of the Person interface.

class Imposter implements Person {

  final _name = "";      // We have to define this, but we don't use it.

  String greet(who) => 'Hi $who. Do you know who I am?';

}


greetBob(Person person) => person.greet('bob');


main() {

  print(greetBob(new Person('kathy')));

  print(greetBob(new Imposter()));

}


  - extends 키워드로 상속을 하고 super는 부모 클래스를 가르킴. 자바와 유사

  - 상속시 부모 메소드에 대한 @override를 명시적으로 사용해 오버라이딩이 가능하다. 

  - 클래스에 @proxy라고 하면 @override시에 warning을 준다. 

  - 다중 상속시에 mixin 개념의 클래스 코드 재사용이 도입. with 키워드를 사용한다. mixin 할때는 upser, 생성 선언이 없다. 

class Musicain extends Performer with Musical, Aggressive, Demented { 

  ...

}


  - 클래스 소속 메소드와 변수는 static 키워드를 사용한다. 자바와 유사




제네릭 (Generics)


  - 다트에서 타입은 옵셔널이다. 의도를 명확히 하기 위해 공식적으 타입 파라미터를 같는 타입이다. (generic == parameterized) type

    예에서 문자로 지정을 한다는 의도를 분명히 한다. 

var names = new List<String>();

names.addAll(['Seth', 'Kathy', 'Lars']);

// ...

names.add(42); // Fails in checked mode (succeeds in production mode).


  - type variables로는 통상 E, T, S, K, V 같은 단일 문자를 갖는다. 

  - 제네릭은 코드의 중복을 방지해 준다. 상속하여 구현 하면 됨 

// Object 경우 

abstract class ObjectCache {

  Object getByKey(String key);

  setByKey(String key, Object value);

}


// String 경우 

abstract class StringCache {

  String getByKey(String key);

  setByKey(String key, String value);

}


// 하나로 줄여줌 

abstract class Cache<T> {

  T getByKey(String key);

  setByKey(String key, T value);

}


  - Collection literal에도 사용가능하다. 

var names = <String>['Seth', 'Kathy', 'Lars'];

var pages = <String, String>{

  'index.html': 'Homepage',

  'robots.txt': 'Hints for web robots',

  'humans.txt': 'We are people, not machines'

};


 


라이브러리와 가시성 (Libraries and visibility) 


  - import, part, library 지시자(Directives) 사용한다. 

  - 라이브러리는 Pub Package and Asset Manager인 pub 툴로 패키지를 사용 배포한다. 

  - import 'dart:html';  형식으로 import는 URI 형시그로 라이브러리를 지정한다. 

  - 빌트인은 'dart:xxx' 로 시작한다. 

  - pub 툴 배포로 제공되는 것은 import 'package:<file path>'; 로 지정한다. 예) import 'package:utils/utils.dart';

  - as로 aliasing이 가능 예) import 'package:lib2/lib2.dart' as lib2; 

  - show, hide 통해 라이브러리 일부만 가져오기 가능 예) import 'package:lib2/lib2.dart' show foo;

  - 라이브러리의 Lazily loading이 가능하다. deferred as 키워드를 사용한다. AngularJS의 $q를 보자  

    + 애플리케이션 초기 시작시간을 줄이기 위해 사용

    + A/B 테스트를 수행하기 위해

    + 사용이 적은 것들 로딩할 때 

    예) import 'package:deferred/hello.dart' deferred as hello;  하기에 then 구문으로 비동기적 호출을 한다.

hello.loadLibrary().then((_) {

  hello.printGreeting();

});


  - 다른 방법으로는 async 키워드를 사용한다. loadLibrary()는 Future를 리턴한다. 

greet() async {

  await hello.loadLibrary();

  hello.printGreeting();

}


  - library <라이브러리명칭>; 으로 사용한다. part는 라이브러리의 첨부된 파일을 지칭한다. 

library ballgame;   // Declare that this is a library named ballgame.


import 'dart:html'; // This app uses the HTML library.


part 'ball.dart';  // ballgame의 일부이다. 


 


비동기 지원 (Asynchrony support)


  - async 와 await 키워드를 사용한다. 

  - 다트 라이브러리는 Future 오브젝트를 리턴하는 펑션셋을 가지고 있다.  

  - dart 또는 dartanalyzer에서 async 지원을 위해 옵션을 주어야 한다. DartEditor (Eclipse기반)에도 넣어줌 

    

dart --enable-async async_await.dart

dartanalyzer --enable-async async_await.dart


  - async 펑션선언 

check() async {

  //...

}


look() async => //...


  - await <expression> 에서 expression은 타입 Future를 가지고 있고 이는 오브젝트를 리턴하기 위한 promise이다. 리턴된 오브젝트가 유효할 때까지 실행은 멈춘다. 




Typedefs


  - 다트에서 펑션, 문자, 숫자 모두 오브젝이다. 

  - typedef 또는 function-type alias 는 필드나 리턴타입을 선언할 때 사용할 수 있는 펑션타입에 이름을 준다. 

// f를 compare로 할당할 때 int f(Object, Object)의 타입정보가 사라진다.

class SortedCollection {

  Function compare;


  SortedCollection(int f(Object a, Object b)) {

    compare = f;

  }

}


// typedef로 펑션타입을 정의한다.

typedef int Compare(Object a, Object b);


class SortedCollection {

  Compare compare;


  SortedCollection(this.compare);

}




메타데이터 (Metadata)


  -  메타데이터는 추가적인 정보를 주기위해 사용한다. @ 키워드로 애노테이션을 사용한다. 

  - @deprecated, @override, @proxy 등의 메타데이터 애노테이션을 사용한다. 

  - 커멘트는 한줄 // 사용하고 다중은 /* */을 사용한다. 




참조 

  

  - 다트 기초 

  - 구글 취업이 원하는 인재상 : 지적 겸손에 대하여

  - 자바스트립트에서의 lexical scope와 this의 의미 번역 (원문)

  - 컴퓨터 사이언스에서 Lexical Scope 위키피디아

  - Dart Slides 및 동영상

  - Dart VM으로 서버 만들기 Framework 종류

저작자 표시 비영리 변경 금지
신고

'Languages > Python' 카테고리의 다른 글

[Dart] Dart 배우는 방법  (0) 2014.12.31
[AngularDart] 앵귤러다트 배우는 방법  (0) 2014.12.24
[Dart] 다트 언어 개념잡기  (0) 2014.12.24
posted by peter yun 윤영식
2013.09.14 12:18 Languages/JavaScript

Mediator 패턴은 충돌을 해결하고 협력할 수 있도록 해주는 것이다. 즉 시스템에 많은 컴포넌트들이 있다면 서로의 커뮤니케이션을 중재하고 제어한다. 예로 공항 관제실을 생각해 보자. 비행기가 컴포넌트이고 이들의 이착륙을 관리하는 관제실이 Mediator가 된다. 




개념 이해하기 

  - Mediator

    Colleague 오븐젝트와 통신하기 위한 인터페이스를 정의한다 

  - ConcreteMediator

    Colleague 클래스를 알고 Colleague 오브젝트의 레퍼런스를 가지고 있는다. 

    Colleague 끼리 메세지를 전달하고 통신토록 해준다 

  - Colleague Classes

    Mediator 오브젝트에 레퍼런스를 유지한다. Mediator를 통하여 다른 Colleague와 통신한다 



PubSub 만들기 

  - Mediator Core

  - publish() 와 subscribe() 

var mediator = (function(){

    // Storage for topics that can be broadcast or listened to

    var topics = {};


    // Subscribe to a topic, supply a callback to be executed

    // when that topic is broadcast to

    var subscribe = function( topic, fn ){

        if ( !topics[topic] ){ 

          topics[topic] = [];

        }

        topics[topic].push( { context: this, callback: fn } );

        return this;

    };


    // Publish/broadcast an event to the rest of the application

    var publish = function( topic ){

        var args;

        if ( !topics[topic] ){

          return false;

        } 


        args = Array.prototype.slice.call( arguments, 1 );

        for ( var i = 0, l = topics[topic].length; i < l; i++ ) {

            var subscription = topics[topic][i];

            subscription.callback.apply( subscription.context, args );

        }

        return this;

    };


    return {

        publish: publish,

        subscribe: subscribe,

        installTo: function( obj ){

            obj.subscribe = subscribe;

            obj.publish = publish;

        }

    };


}());

  - Jack Lawson의 Mediator.js 를 가져다 쓰면 된다 

/*! * Mediator.js Library v0.9.5 * https://github.com/ajacksified/Mediator.js * * Copyright 2013, Jack Lawson * MIT Licensed (http://www.opensource.org/licenses/mit-license.php) * * For more information: http://thejacklawson.com/2011/06/mediators-for-modularized-asynchronous-programming-in-javascript/index.html * Project on GitHub: https://github.com/ajacksified/Mediator.js * * Last update: June 13 2013 */ (function(global, factory) { 'use strict';

// 다양한 환경에서 적용할 수 있도록 모듈에 대한 export if(typeof exports !== 'undefined') { // Node/CommonJS exports.Mediator = factory(); } else if(typeof define === 'function' && define.amd) { // AMD define('mediator-js', [], function() { global.Mediator = factory(); return global.Mediator(); }); } else { // Browser global global.Mediator = factory(); } }(this, function() { 'use strict'; // We'll generate guids for class instances for easy referencing later on. // Subscriber instances will have an id that can be refernced for quick // lookups.

// 글로벌 유니크 아이디를 생성하는 로직이다. 등록된 Colleague 오브젝트에 (즉, Subscriber Instances)

// 아이디를 부여해 준다 function guidGenerator() { var S4 = function() { return (((1+Math.random())*0x10000)|0).toString(16).substring(1); }; return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); } // Subscribers are instances of Mediator Channel registrations. We generate // an object instance so that it can be updated later on without having to // unregister and re-register. Subscribers are constructed with a function // to be called, options object, and context. // Colleague인 Subscriber 펑션 정의 function Subscriber(fn, options, context){ if(!(this instanceof Subscriber)) { return new Subscriber(fn, options, context); } this.id = guidGenerator(); this.fn = fn; this.options = options; this.context = context; this.channel = null; }

// Subscriber Prototype 객체 정의

// Subscriber에 등록한 fn, context, options를 변경할 수 있다 Subscriber.prototype = { // Mediator.update on a subscriber instance can update its function,context, // or options object. It takes in an object and looks for fn, context, or // options keys. update: function(options){ if(options){ this.fn = options.fn || this.fn; this.context = options.context || this.context; this.options = options.options || this.options; if(this.channel && this.options && this.options.priority !== undefined) { this.channel.setPriority(this.id, this.options.priority); } } } }; // 채널을 통하여 Subscriber 의 등록/제거 관리 

// Subscriber에 정보 publish function Channel(namespace, parent){ if(!(this instanceof Channel)) { return new Channel(namespace); } this.namespace = namespace || ""; this._subscribers = []; this._channels = []; this._parent = parent; this.stopped = false; } // A Mediator channel holds a list of sub-channels and subscribers to be fired // when Mediator.publish is called on the Mediator instance. It also contains // some methods to manipulate its lists of data; only setPriority and // StopPropagation are meant to be used. The other methods should be accessed // through the Mediator instance. // Mediator 채널이 sub-channel 목록을 가지고 있다 

// Channel Prototype 객체 정의 Channel.prototype = { addSubscriber: function(fn, options, context){ var subscriber = new Subscriber(fn, options, context); if(options && options.priority !== undefined){ // Cheap hack to either parse as an int or turn it into 0. Runs faster // in many browsers than parseInt with the benefit that it won't // return a NaN. options.priority = options.priority >> 0; if(options.priority < 0){ options.priority = 0; } if(options.priority >= this._subscribers.length){ options.priority = this._subscribers.length-1; } this._subscribers.splice(options.priority, 0, subscriber); }else{ this._subscribers.push(subscriber); } subscriber.channel = this; return subscriber; }, // The channel instance is passed as an argument to the mediator subscriber, // and further subscriber propagation can be called with // channel.StopPropagation().

// Mediator에 등록한 Subscriber에 아규먼트 전달 멈춤 stopPropagation: function(){ this.stopped = true; },


getSubscriber: function(identifier){ var x = 0, y = this._subscribers.length; for(x, y; x < y; x++){ if(this._subscribers[x].id === identifier || this._subscribers[x].fn === identifier){ return this._subscribers[x]; } } }, // Channel.setPriority is useful in updating the order in which Subscribers // are called, and takes an identifier (subscriber id or named function) and // an array index. It will not search recursively through subchannels. // subchannel을 돌면서 우선순위를 업데이트 한다 setPriority: function(identifier, priority){ var oldIndex = 0, x = 0, sub, firstHalf, lastHalf, y; for(x = 0, y = this._subscribers.length; x < y; x++){ if(this._subscribers[x].id === identifier || this._subscribers[x].fn === identifier){ break; } oldIndex ++; } sub = this._subscribers[oldIndex]; firstHalf = this._subscribers.slice(0, oldIndex); lastHalf = this._subscribers.slice(oldIndex+1); this._subscribers = firstHalf.concat(lastHalf); this._subscribers.splice(priority, 0, sub); },

// sub channel 등록/삭제 addChannel: function(channel){ this._channels[channel] = new Channel((this.namespace ? this.namespace + ':' : '') + channel, this); }, hasChannel: function(channel){ return this._channels.hasOwnProperty(channel); }, returnChannel: function(channel){ return this._channels[channel]; }, removeSubscriber: function(identifier){ var x = this._subscribers.length - 1; // If we don't pass in an id, we're clearing all if(!identifier){ this._subscribers = []; return; } // Going backwards makes splicing a whole lot easier. for(x; x >= 0; x--) { if(this._subscribers[x].fn === identifier || this._subscribers[x].id === identifier){ this._subscribers[x].channel = null; this._subscribers.splice(x,1); } } }, // This will publish arbitrary arguments to a subscriber and then to parent // channels. // 퍼블리싱 : subscriber에 아규먼트 전달 publish: function(data){ var x = 0, y = this._subscribers.length, called = false, subscriber, l, subsBefore,subsAfter; // Priority is preserved in the _subscribers index. for(x, y; x < y; x++) { if(!this.stopped){ subscriber = this._subscribers[x]; if(subscriber.options !== undefined && typeof subscriber.options.predicate === "function"){ if(subscriber.options.predicate.apply(subscriber.context, data)){ subscriber.fn.apply(subscriber.context, data); called = true; } }else{ subsBefore = this._subscribers.length; subscriber.fn.apply(subscriber.context, data); subsAfter = this._subscribers.length; y = subsAfter; if (subsAfter === subsBefore - 1){ x--; } called = true; } } if(called && subscriber.options && subscriber.options !== undefined){ subscriber.options.calls--; if(subscriber.options.calls < 1){ this.removeSubscriber(subscriber.id); y--; x--; } } } if(this._parent){ this._parent.publish(data); } this.stopped = false; } };

// Mediator 펑션 function Mediator() { if(!(this instanceof Mediator)) { return new Mediator(); } this._channels = new Channel(''); } // A Mediator instance is the interface through which events are registered // and removed from publish channels. Mediator.prototype = { // Returns a channel instance based on namespace, for example // application:chat:message:received // sub channel은 namespace 기반으로 만들어 진다 getChannel: function(namespace){ var channel = this._channels, namespaceHierarchy = namespace.split(':'), x = 0, y = namespaceHierarchy.length; if(namespace === ''){ return channel; } if(namespaceHierarchy.length > 0){ for(x, y; x < y; x++){ if(!channel.hasChannel(namespaceHierarchy[x])){ channel.addChannel(namespaceHierarchy[x]); } channel = channel.returnChannel(namespaceHierarchy[x]); } } return channel; }, // Pass in a channel namespace, function to be called, options, and context // to call the function in to Subscribe. It will create a channel if one // does not exist. Options can include a predicate to determine if it // should be called (based on the data published to it) and a priority // index. // sub channel에 namespace 기반으로 Subscriber 등록하기 subscribe: function(channelName, fn, options, context){ var channel = this.getChannel(channelName); options = options || {}; context = context || {}; return channel.addSubscriber(fn, options, context); }, // Pass in a channel namespace, function to be called, options, and context // to call the function in to Subscribe. It will create a channel if one // does not exist. Options can include a predicate to determine if it // should be called (based on the data published to it) and a priority // index. // 한번 호출하고 끝내기 once: function(channelName, fn, options, context){ options = options || {}; options.calls = 1; return this.subscribe(channelName, fn, options, context); }, // Returns a subscriber for a given subscriber id / named function and // channel namespace // 아이디와 명칭으로 Subscriber 얻어오기 (identifier === GUID) getSubscriber: function(identifier, channel){ return this.getChannel(channel || "").getSubscriber(identifier); }, // Remove a subscriber from a given channel namespace recursively based on // a passed-in subscriber id or named function. remove: function(channelName, identifier){ this.getChannel(channelName).removeSubscriber(identifier); }, // Publishes arbitrary data to a given channel namespace. Channels are // called recursively downwards; a post to application:chat will post to // application:chat:receive and application:chat:derp:test:beta:bananas. // Called using Mediator.publish("application:chat", [ args ]); // 퍼블리싱 publish: function(channelName){ var args = Array.prototype.slice.call(arguments, 1), channel = this.getChannel(channelName); args.push(channel); this.getChannel(channelName).publish(args); } };

// 일반적으로 사용하는 이름으로도 Aliasing // Alias some common names for easy interop Mediator.prototype.on = Mediator.prototype.subscribe; Mediator.prototype.bind = Mediator.prototype.subscribe; Mediator.prototype.emit = Mediator.prototype.publish; Mediator.prototype.trigger = Mediator.prototype.publish; Mediator.prototype.off = Mediator.prototype.remove; // Finally, expose it all. Mediator.Channel = Channel; Mediator.Subscriber = Subscriber; Mediator.version = "0.9.5"; return Mediator; })); 



사용해 보기 

  - Plunker에서 수행한 내역 보기 : http://plnkr.co/edit/k9dT9Ms7xzbx77GhVraA?p=preview

  - HTML

<!DOCTYPE html>

<html>


  <head>

    <script data-require="jquery@*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>

    <link data-require="bootstrap-css@*" data-semver="3.0.0" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />

    <link data-require="bootstrap@*" data-semver="3.0.0" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />

    <script data-require="bootstrap@*" data-semver="3.0.0" src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>

    <link rel="stylesheet" href="style.css" />

    <script src="mediator.js"></script>

    <script src="script.js"></script>

  </head>


  <body>

    <h1>Chat</h1>

    <form id="chatForm">

      <label for="fromBox">Your Name:</label>

      <input id="fromBox" type="text" />

      <br />

      <label for="toBox">Send to:</label>

      <input id="toBox" type="text" />

      <br />

      <label for="chatBox">Message:</label>

      <input id="chatBox" type="text" />

      <button type="submit">Chat</button>

    </form>

    <div id="chatResult"></div>

  </body>


</html>


  - JavaScript

// create Mediator.js

var mediator = new Mediator();


$("#chatForm").submit(function(){

    // Collect the details of the chat from our UI

    var text = $( "#chatBox" ).val(),

        from = $( "#fromBox" ).val(),

        to = $( "#toBox" ).val();

        

    // newMessage 채널로 퍼블리싱 하기 

    // Publish data from the chat to the newMessage topic

    mediator.publish( "newMessage" , { message: text, from: from, to: to } );

    return false;

});


// Append new messages as they come through

function displayChat( data ) {

    var date = new Date(),

        msg = data.from + " said \"" + data.message + "\" to " + data.to;

  

    $( "#chatResult" ).prepend("<p>" + msg + " (" + date.toLocaleTimeString() + ")</p>");

}


// Log messages

function logChat( data ) {

    if ( window.console ) {

        console.log( data );

    }

}


// newMessage 명칭으로 Subscriber 등록하기 

// Subscribe to new chat messages being submitted

// via the mediator

mediator.subscribe( "newMessage", displayChat );

mediator.subscribe( "newMessage", logChat );


  - 수행내역



<참조>

  - 원문 : Mediator Pattern

  - OODesign : Mediator Pattern

  - http://thejacklawson.com/Mediator.js/

  - 오늘의 명언 : 내가 감동하면 남도 감동할 수 있다. 그것이 SNS정신이다 

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2013.09.07 17:32 Languages/JavaScript

Publish/Subscribe 를 위한 Observer 패턴을 알아보자. JavaScript은 Web의 Virtual Machine이다. JavaScript는 웹앱이다. 




개념

  - Observable

     Client에 observers를 붙였다 띄었다 하는 동작을 가진 추상 클래스 또는 인터페이스  (Publisher)

    ConcreteObservable

     오브젝트의 상태정보를 가지고 있다가 상태가 변경되면 등록된 Observers 에게 변경 정보를 알려준다 

    Observer

     정보를 알려줄 Operation을 정의한 추상 클래스 또는 인테페이스 (Subscriber)


  - 어떤 오브젝트가 오브젝트 목록을 관리하다가 어떤 상태의 변화가 감지되면 해당 오브젝트 목록들에 변경값을 Notify한다 

  - 상태 정보 변경에 관심을 갖는 오브젝트를 Observer Object라 하고 Observer Object를 register/remove 한다 

  - GoF의 정의 

"One or more observers are interested in the state of a subject and register their interest with the subject by attaching themselves. When something changes in our subject that the observer may be interested in, a notify message is sent which calls the update method in each observer. When the observer is no longer interested in the subject's state, they can simply detach themselves."



구현 

  - Observer Pattern 구현을 위해 필요한 컴포넌트 

    > Subject : observers 목록을 제어(register/remove)한다 

    > Observer : Subject로부터 상태변화를 받을 오브젝트 인터페이스를 제공한다 

    > ConcreteSubject : 상태 변경을 observers 에게 notify를 수행한다 

    > ConcreteObserver : ConcreteSubject에 Observer 인터페이스를 생성하여 등록한다 

// Object 목록 관리 Constructor Function

function ObserverList(){

this.observerList = []; } ObserverList.prototype.Add = function( obj ){ return this.observerList.push( obj ); }; ObserverList.prototype.Empty = function(){ this.observerList = []; }; ObserverList.prototype.Count = function(){ return this.observerList.length; }; ObserverList.prototype.Get = function( index ){ if( index > -1 && index < this.observerList.length ){ return this.observerList[ index ]; } }; ObserverList.prototype.Insert = function( obj, index ){ var pointer = -1; if( index === 0 ){ this.observerList.unshift( obj ); pointer = index; }else if( index === this.observerList.length ){ this.observerList.push( obj ); pointer = index; } return pointer; }; ObserverList.prototype.IndexOf = function( obj, startIndex ){ var i = startIndex, pointer = -1; while( i < this.observerList.length ){ if( this.observerList[i] === obj ){ pointer = i; } i++; } return pointer; }; ObserverList.prototype.RemoveAt = function( index ){ if( index === 0 ){ this.observerList.shift(); }else if( index === this.observerList.length -1 ){ this.observerList.pop(); } }; // Extend an object with an extension

function extend( extension, obj ){ for ( var key in extension ){ obj[key] = extension[key]; } }


  - Subject 구현, Observer에는 Update메소드를 구현하면 된다

// 1. Subject Constructor Function을 정의한다

// (Constructor Pattern의 prototype 방식 사용)

function Subject(){ this.observers = new ObserverList(); } Subject.prototype.AddObserver = function( observer ){ this.observers.Add( observer ); }; Subject.prototype.RemoveObserver = function( observer ){ this.observers.RemoveAt( this.observers.IndexOf( observer, 0 ) ); };

// Observer가 상태 정보를 받는다 
Subject.prototype.Notify = function( context ){
  var observerCount = this.observers.Count();
  for(var i=0; i < observerCount; i++){
    this.observers.Get(i).Update( context );

};



// 2. Observer 구현 

// The Observer
function Observer(){
  this.Update = function(){
    // ...
  };
}


  - ConcreteSubject, ConcreteObserver

// HTML

1) button을 클릭하면 observable checkbox를 페이지에 추가

2) checkbox가 subject로 동작한다. check가 되면 모든 checkbox에 상태변경을 알려준다(notify) 

3) 새로운 checkbox를 container에 추가한다 

<button id="addNewObserver">Add New Observer checkbox</button>
<input id="mainCheckbox" type="checkbox"/>
<div id="observersContainer"></div>

// Script 

// References to our DOM elements var controlCheckbox = document.getElementById( "mainCheckbox" ), addBtn = document.getElementById( "addNewObserver" ), container = document.getElementById( "observersContainer" ); // 3. Concrete Subject

// Subject의 notify 메소드를 호출하는 구문이 존재 // Extend the controlling checkbox with the Subject class extend( new Subject(), controlCheckbox ); // Clicking the checkbox will trigger notifications to its observers controlCheckbox["onclick"] = new Function( "controlCheckbox.Notify(controlCheckbox.checked)" ); addBtn["onclick"] = AddNewObserver;

// 4. Concrete Observer function AddNewObserver(){ // Create a new checkbox to be added var check = document.createElement( "input" ); check.type = "checkbox"; // Extend the checkbox with the Observer class extend( new Observer(), check ); // Override with custom update behaviour check.Update = function( value ){ this.checked = value; }; // Add the new observer to our list of observers // for our main subject controlCheckbox.AddObserver( check ); // Append the item to the container container.appendChild( check ); }



Publish/Subscribe

  - Publish/Subscriber와 유사하다. Observer나 Pub/Sub 사용이유는 틀린 계층간의 결합시 Loose Coupling으로 관계설정에 유용한다 

var pubsub = {};

(function(q) {

    var topics = {},
        subUid = -1;

    // Publish or broadcast events of interest
    // with a specific topic name and arguments
    // such as the data to pass along
    q.publish = function( topic, args ) {

        if ( !topics[topic] ) {
            return false;
        }

        var subscribers = topics[topic],
            len = subscribers ? subscribers.length : 0;

        while (len--) {
            subscribers[len].func( topic, args );
        }

        return this;
    };

    // Subscribe to events of interest
    // with a specific topic name and a
    // callback function, to be executed
    // when the topic/event is observed
    q.subscribe = function( topic, func ) {

        if (!topics[topic]) {
            topics[topic] = [];
        }

        var token = ( ++subUid ).toString();
        topics[topic].push({
            token: token,
            func: func
        });
        return token;
    };

    // Unsubscribe from a specific
    // topic, based on a tokenized reference
    // to the subscription
    q.unsubscribe = function( token ) {
        for ( var m in topics ) {
            if ( topics[m] ) {
                for ( var i = 0, j = topics[m].length; i < j; i++ ) {
                    if ( topics[m][i].token === token) {
                        topics[m].splice( i, 1 );
                        return token;
                    }
                }
            }
        }
        return this;
    }; 

}( pubsub ));



<참조>

  - 원문 : Observer Pattern

  - OODesign : Observer Pattern

  - PubSubJS for JavaScript

  - RadioJS for Pub/Sub

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2013.09.07 17:11 Languages/JavaScript

클래스의 인스턴스를 오직 하나만 생성하는 Singleton Pattern을 알아보자. 기술은 향기와 같다. 막아도 냄새를 맡을 수 있는 것이다. 옳바른 향기를 피워보자. 




개념

  - Java에서의 싱글톤 정의 패턴 

    1) 자신을 private 멤버변수로 선언

    2) private 생성자 정의

    3) public static synchronized 형태 getInstance() 메소드 정의

    4) 자신의 변수가 null인지 아닌지 체크 

class Singleton

{

    private static Singleton instance; // 1) 

    private Singleton() // 2) 

    {

        ...

    }


    public static synchronized Singleton getInstance() // 3)

    {

        if (instance == null) // 4) 

            instance = new Singleton();

        return instance;

    }

    ...

    public void doSomething()

    {

        ... 

    }

}


  - Global Scope에 격리되고 내부 변수를 공유한다

    > Constructor Function을 정의한다 

    > Closure 객체안에서 Constructor Function을 한번만 new하는 로직을 넣고 Closure객체를 return한다 

var mySingleton = (function () {

// Instance stores a reference to the Singleton var instance; function Init() { // define Constructor Function // Singleton // Private methods and variables function privateMethod(){ console.log( "I am private" ); } var privateVariable = "Im also private"; var privateRandomNumber = Math.random(); return { // Public methods and variables publicMethod: function () { console.log( "The public can see me!" ); }, publicProperty: "I am also public", getRandomNumber: function() { return privateRandomNumber; } }; }; return { // return the Closure Object // Get the Singleton instance if one exists // or create one if it doesn't getInstance: function () {

// 생성이 안되었으면 최초에 한번만 init 한다 if ( !instance ) { instance = Init(); } return instance; } }; })();


// 잘 못된 예제 var myBadSingleton = (function () { // Instance stores a reference to the Singleton var instance; function init() { // Singleton var privateRandomNumber = Math.random(); return { getRandomNumber: function() { return privateRandomNumber; } }; }; return { // Always create a new Singleton instance getInstance: function () {

instance = init(); return instance; } }; })(); var singleA = mySingleton.getInstance(); var singleB = mySingleton.getInstance(); console.log( singleA.getRandomNumber() === singleB.getRandomNumber() ); // true var badSingleA = myBadSingleton.getInstance(); var badSingleB = myBadSingleton.getInstance(); console.log( badSingleA.getRandomNumber() !== badSingleB.getRandomNumber() ); // true



<참조>

  - 원문 : Singleton Pattern

  - OODesign : Singleton Pattern

 - 널리 Singleton을 사용해 보자

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2013.09.07 16:53 Languages/JavaScript

SNS의 정신은 감동, 배려, 책임이다. 기술이 아니다, 자바스크립트를 행복하게 사용하려면 모듈단위의 개발이 되어야 한다. 모듈 패턴을 알아보자.



종류

  - 견고한 애플리케이션을 개발하기 위하여 모듈단위 개발이 필요하다 

  - 모듈을 구현하기 위한 방법

    > The Module pattern

    > Object literal notation

    > AMD modules

    > CommonJS modules

    > ECMAScript Harmony modules



Object Literals

  - curly braces {} 를 사용한다 

  - new 키워드가 필요없다 

  - 오브젝트에 프로퍼티의 동적 추가가 가능하다. 예) myObjectLiteral.sencondKey = value; 

var myObjectLiteral = {

  variableKey: variableValue,

  functionKey: function() {...},

  someObject: {...}

}



Module Pattern

  - class처럼 private, public를 캡슐화 하여 정의하는 방법이다 

  - 별도 name space 사용으로 global scope의 오염을 방지한다 

  - ClosureIIFE (Immediately Invoked Function Expression) 을 사용한다 

var testModule = (function() {

  var counter = 0;

  return {  // Closure

    incrementCounter: function() {

      return counter++;

    },

    resetCounter: function() {

      console.log('counter is', counter);

      counter = 0;

    }

  };

})(); // IIFE


testModule.incrementCounter();

testModule.resetCounter();

// output : counter is 1

  - 예제에서 counter는 global scope에서 숨겨져이다. 즉, private variable같다, counter 접근은 두개의 method로만 가능하다. 물론 function도 private 으로 정의가능하다 

var myNamespace = (function () {

  var myPrivateVar, myPrivateMethod;

  // A private counter variable
  myPrivateVar = 0;

  // A private function which logs any arguments
  myPrivateMethod = function( foo ) {
      console.log( foo );
  };

  return {

    // A public variable
    myPublicVar: "foo",

    // A public function utilizing privates
    myPublicFunction: function( bar ) {

      // Increment our private counter
      myPrivateVar++;

      // Call our private method using bar
      myPrivateMethod( bar );

    }
  };
 

})();



Module Pattern 변형 

  - Import mixins : global scope의 변수를 module에 import 하는 방법

    jQuery 와 Underscore 객체를 익명함수의 파라미터로 받아서 import 한다

// Global module
var myModule = (function ( jQ, _ ) {
  
    function privateMethod1(){
        jQ(".container").html("test");
    }

    function privateMethod2(){
      console.log( _.min([10, 5, 100, 2, 1000]) );
    }
    
    return{
        publicMethod: function(){
            privateMethod1();                
        }            
    };
   
// Pull in jQuery and Underscore
}( jQuery, _ ));
 

myModule.publicMethod();  

  

  - Export : global module 만들기 

    var module = {} 객체를 만들어서 return 하여 export 한다 

// Global module
var myModule = (function () {

    // Module object 
  var module = {},
    privateVariable = "Hello World";
  
  function privateMethod() {
    // ...
  }

  module.publicProperty = "Foobar";
  module.publicMethod = function () {
    console.log( privateVariable );
  };
  
  return module;
 

}());



<참조>

  - 원문 : 모듈패턴

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2013.09.07 16:07 Languages/JavaScript

구글러 오스마니님의 JavaScript Design Pattern 글에서 패턴을 요약해 본다. 생성자 패턴에 대해 알아보자 



개념

  - 자바스크립트는 모든것이 오브젝트이다 

  - Object constructor가 지정한 타입의 오브젝트를 생성하는데 사용한다 

 


Object Creation

  - 오브젝트를 만드는 3가지 기본 방법 

    비어있는 오브젝트를 만들어 리턴하는 것이다 

var newObject = {};


var newObject = Object.create( null );


var newObject = new Object();


  - 오브젝트에 Key, Value 할당하는 4가지 방법

// 1. Dot syntax

newObject.someKey = "hi dowon";

var key = newObject.someKey;


// 2. Square bracket syntax

newObject["someKey"] = "hi youngsik";

var key = newObject["someKey"];


// ECMAScript 5 olny

// 3. Object.defineProperty

Object.defineProperty( newObject, "someKey", {

  value: "hi dowon",

  writable: true,

  enumerable: true,

  configurable: true

});


var defineProp = function( obj, key, value ) {

  config.value = value;

  Object.defineProperty( obj, key, config);

};


var person = Object.create( null );

defineProp( person, "car", "Seoul");

defineProp( person, "house", "apt");


// 4. Object.defineProperties

// set properties

Object.defineProperties( newObject, {

   "someKey": {

     value: "hi dowon",

     writable: true

   }, 

   "anotherKey": {

      value: "youngsik",

      writable: false

    }

});



Basic Constructors

  - Constructor Function에 new 키워들 사용하여 신규 오브젝트를 생성한다

  - Constructor Function안의 this는 새로 생성된 오브젝트의 레퍼런스이다 

// define constructor function

function Car(model, price) {

  this.model = model;

  this.price = price;

  

  this.toString = function() {

    return this.model + ', ' + this.price;

  }

}


// new로 생성하면 Car.prototype을 통하여 신규 오브젝트를 만들어 주소를 넘겨주면 hd가 주소 레퍼런스를 가진다

var hd = new Car('santafe', 1000);


// 찍어보자

Car {model: "santafe", price: 1000, toString: function}


  - Function은 prototype 프로퍼티를 가지고 있다. prototype은 객체를 레퍼런스를 하는데 별도로 지정하지 않으면 자신의 property 객체를 레퍼런스 한다. 여기서 Car.property 는 Car.property 객체를 레퍼런스 한다  

function Car(model, price) {

  this.model = model;

  this.price = price;

}


Car.prototype.toString = function() {

  return this.model + ', ' + this.price;

}


console.log(hd.toString());

kia, 5000


  Car Constructor Function은 {this.model: <value>, this.price: <value>, prototype: Car.prototype}  가 되고, Car.prototype 객체는 {constructor: Car, toString: function() {...}} 이다. Car Constructor Function의 prototype 프로퍼티는 Car.prototype 객체를 레퍼런싱하고, Car.prototype객체의 constructor 프로퍼티를 통하여 Car Constructor Function을 레퍼런싱하여 상호 참조한다. prototype와 constructor 프로퍼티는 writable이다. 이를 이용해 JavaScript의 Prototypal Inheritance 방식을 사용할 수 있다.



<참조>

  - 오스마니 생성자패턴

  - JavaScript Prototype

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2013.08.30 17:24 Languages/JavaScript
자바스크립트 개발시 피해야하는 중요한 3가지 사용패턴에 대해서 알아보자 


1. Object 상속에 의한 오염

  - Object의 prototype을 통하여 확장을 하지마라

  - 예를 보자 

    두번째 Object.prototype.e 를 확장하면 모든 오브젝트에 e="E"가 불필요하게 반영된다. 즉 모든 오브젝트에 상속된다 

var obj = {a: "A", b: "B", c: "C", d: "D"};
for (var key in obj) {
   alert(key +': '+obj[key]); //displays "a: A", "b: B", "c: C", "d: D"
}
 
// Anti-Pattern
Object.prototype.e = "E";
for (var key in obj) {
   alert(key +': '+obj[key]); //displays "a: A", "b: B", "c: C", "d: D", "e: E"
}
 
var obj2 = {a2: "A2", b2: "B2", c2: "C2", d2: "D2"};
for (var key in obj2) {
   alert(key +': '+obj2[key]); //displays "a2: A2", "b2: B2", "2c: C2", "d2: D2", "e: E"

}

  - 상속의 방법

function Person(name, sex) { 

  Person.prototype.populationCount++; 
  Person.prototype.getName=function(){ return name }; 
  Person.prototype.getSex=function(){ return sex }; 
  Person.prototype.setSex=function(newSex){ sex = newSex; }; 
  Person.prototype.die=function(){ Person.prototype.populationCount -- ; };
}
Person.prototype.populationCount=0;
 
var rob = new Person('Rob','male');
var jeanie = new Person('Jeanie','female');
alert(rob.populationCount);  // displays 2
 
//the following creates a new public property for rob and sets it to 12
rob.populationCount+=10;
alert(rob.populationCount); //displays 12
alert(jeanie.populationCount); //still displays 2
 
Child.prototype = Object.create(Person.prototype);
Child.prototype.constructor = function Child(name, sex, age) {
    //call the parent constructor
    Person(name, sex);
    Child.prototype.getAge = function() { return age; };
}
var child = new Child('Ralph', 'male', 3);
 
alert(child.getName()); //displays "Ralph"
alert(child.getAge());  //displays 3



2. Global Namespace에 의한 오염

  - 보통 var를 사용하지 않고 x=2 처럼 하면 window.x=2가 되어 전역영역을 오염시킨다. 따라서 변수선언시 반드시 var 를 사용한다 

  - Group 변수를 통해서 오염을 방지하자 

   var Finance = {};

Finance.INTEREST_RATE = 2.5;
Finance.calcAnnualizedInterest(startVal, endVal) {
  //...
}

  - 또는 ECMAScrpt 5 "use strict"를 script 맨위체 포함시킨다. 또는 function 안에 놓고 제한된 scope에서 strict mode를 사용할 수도 있다

  function strictFunc(){

  "use strict";
  // code ...
}

  - 예를 보자 

    i 의 결과값으로 5가 나온다. Global Namespace를 오염시키는 function - foo, bar -, variable - i - 같은 것은 절대 사용하지 말자 

function foo() { return 1; }

function bar() { for (i=0; i<5; i++) {} }

 

i = foo();

bar();



3. True, False에 대한 부적절한 사용에 의한 오염 

  - 자바스크립트에서 zero (0), empty string (""), null, undefined, NaN 은 모둔 false 값이다 

  - 비교문이나 루프문에서 조건 사용시 축약한다  

// Anti-Pattern

if (testString != undefined && testString != '') {

  //do something

  }


// 변경 : 위 조건절과 동일 

if (!testString) {

  //do something
}

  - ===, ==! 를 항상 사용한다 

// 주의

   var zero = 0;

if (zero === false) {
  // doesn't execute because zero is 0, not false
}



<참조>

  - 원문 : Three JavaScript Anti-Patterns and How to avoid them

  - Another Anti-Patterns 

  - Anti-Patterns를 피하고 성능을 향상시키는 방법들 : Slide 및 동영상

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2013.06.28 21:33 Languages/JavaScript

오늘은 강남토즈에서 김영보선생님의 자바스크립트 객체지향 세미나를 듣고 있다. 간단히 요약해 본다 




1. OOP

  - object.method() : 전형적인 OOP 형태 

  - Object is "{}" 즉, JSON 포멧

     object is "new Function"

  - 자바스크립트에서 function은 함수가 아니라 키워드일 뿐이다 

    ex) function sales() {}  -->  { "sales" : function(){} } 으로 대치가능하다

  - 수행 순서

     + 소스

       function A() {

   function B() {}

       } 

     + A() 호출하면 A안의 내용만 { "A" : function(){} } 만 만든다 { "B": function(){} } 은 안만든다.

       즉 수행하는 시점에 해석되고 객체로 적재되어 수행한다 

     + 초기 랜더링에 필요한 부분만 해석되어 수행하면 성능 향상을 할 수 있다

  - oop의 information hiding을 위하여 closure를 사용한다 



2. 메커니즘

  - 메모리 stack 생성 -> Execution Context 저장하고 EC단위로 수행한다 

  - Executable Code type : global code, function code, eval code (eval 코드는 쓰지말라! 5차부터 에러남)

  - Execution Context : Executable code의 실행 단위.  Context : 문맥, 처리단위, 묶음 

  - Stack안에 EC가 들어가는데 가장 먼저 만들어진것이 stack의 바닥부터 위로 채워넣는다. 수행은 위에서 빼서 수행 그때 GC 발생

  - object를 EC에 바인딩 : EC = { VO : { key: value } }   *VO = Variable Object

     모든 EC는 VO와 연동한다 

  - VO 구성요소 : variable, function, function parameter 

    예) 펑션을 만나면 Variable Object를 만든다. { key: value } 이런 형태임



3. VO 메커니즘

  - Global Context, function context로 분리  

  - Global Context : 하나만 존재, Global object도 VO와 연동. 즉, Global object와 VO는 같음

  - 코드가 Hoisting되어서 function -> variable 순으로 호출됨. 즉, function 호출

  - VO의 function context는 AO와 같음 *AO = Activation Object : function 호출시 AO를 만들어 수행하는 것이다 

  - function 실행되면

    + AO 생성 : function & AO 바인딩

    + function에 아규먼트 갯수와 상관이 없으므로 arguments 객체를 만들어줌 (배열아님)

    + 내부 function을 설정, 실행하는 것이 아니다 { key: value } 로 설정

  - scope chain은 scope binding의 추상개념이다



4. Property 탐색 & 클로져

  - property = { key: value } 형태 추상개념

  - Global Context -> Inner Function AO에서 탐색 

  - 클로져 (참조)

    + 내부변수를 참조하는 함수를 리턴함 == function code + [[Scope]]의 조합

    + function 생성 시점에 클로져 설정 



5. This

  - 모든 EC와 this와 관련이 있다

  - function단위로 this 오브젝트를 만든다 (this value)

  - this는 AO에 생긴다. AO는 function이다. 따라서 this는 function안에 존재한다 

  - EC = {VO/AO, value, this: value} 형태  

  - null : 프로세싱 한것. 값이 undefine에서 null이 된것이다 

    undefine : 프로세싱 안한것

  - this.a 했을 때 a가 undefine이면 this생성이 안된 경우일 것이다 (참조)



6. Prototype 

  - object는 prototype을 갖음 

  - [[function]].prototype.property_name 형식

  - this.property_name 으로 접근가능

  - prototype chain이 된다 : 상속개념 사용가능 -> 사용자제 

  - 렌더링시에 생성되어 수행되게 할려면 new 사용을 자제한다?

  - 사용이유 : prototype을 사용하면 new이후 this로 정의한 것을 접근할 수 있기 때문이다 

  - 객체를 1차레벨로 수평화 하라 -> 오브젝트를 불러서 사용한다 (Node.js의 require와 비슷하겠다) -> 접근성이 용이해 진다 


다음 강좌가 있으면 또 교육을 받아봐야 겠다. 정말 설명을 명확하게 잘 해주신다.



<참조>

  - MSDN 자바스크립트 객체지향 이야기

  - NHN이 말하는 자바스크립트의 클로져 이야기

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2013.03.09 17:47 Languages

Underscore.js 프레임워크를 보면 소스에 대해 왼쪽에는 주석을 오른쪽은 소스를 보여주며 설명을 한다. 이러한 문서를 자동으로 만들어 주는 툴이 Groc 이다. 또한 루트에서 수행을 하면 하위의 모든 소스에 대한 문서화를 자동으로 만들어 주고, GitHub과 통합할 수 있다 


1. Groc 설치하기 

  - 주석을 Markdown 형태로 작성한다

  - 마크다운 포멧은 배우기 쉽고 GitHub에서도 사용하므로 반드시 익혀두자 

  - GitHub의 페이지 publishing 과 통합된다 : GitHub에서 OSS(Open Source Software) 개발한 것을 공짜로 웹 서비싱 해준다

  - 검색 테이블을 제공한다 



2. 설치하기 

  - npm (Node Package Manager)가 설치되어 있어야 한다 

sudo npm install groc -g

npm http GET https://registry.npmjs.org/groc

npm http 304 https://registry.npmjs.org/groc

... 중략 ...

groc@0.3.2 /usr/local/lib/node_modules/groc

├── colors@0.6.0-1

├── spate@0.1.0

├── underscore@1.4.4

├── coffee-script@1.6.1

├── autorequire@0.3.4

├── showdown@0.3.1

├── optimist@0.3.5 (wordwrap@0.0.2)

├── jade@0.28.2 (commander@0.6.1, mkdirp@0.3.5)

├── uglify-js@2.2.5 (source-map@0.1.9)

├── glob@3.1.21 (inherits@1.0.0, graceful-fs@1.2.0, minimatch@0.2.11)

└── fs-tools@0.2.9 (async@0.2.6, lodash@1.0.1)


// syntax highlighting module pygments 설치하기

$ sudo easy_install Pygments

Best match: Pygments 1.6

Downloading http://pypi.python.org/packages/2.7/P/Pygments/Pygments-1.6-py2.7.egg#md5=1e1e52b1e434502682aab08938163034

... 중략 ...

Installing pygmentize script to /usr/local/bin   <== groc가 사용함



3. 문서만들기 

  - * 사용할 수 있다

  - 여러 옵션을 적용할 수 있다

  - CLI 명령으로 수행한다 : groc [js명칭]

  - github에서 groc를 다운받아서 직접 만들어 보자 

//////////////////////////////

// groc 소스 받아 문서 생성하기 

$ git clone https://github.com/nevir/groc.git

Cloning into 'groc'...

remote: Counting objects: 1215, done.

...중 략 ...


groc index.js

publish_to_github null https://github.com/nevir/groc origin

  Generating documentation...

✓ /Users/git-repositories/groc/.git/groc-tmp/languages.html

✓ /Users/git-repositories/groc/.git/groc-tmp/project.html

..중략..

✓ /Users/git-repositories/groc/.git/groc-tmp/styles/default/docPage.html

✓ Documentation generated


//////////////////////////////

// 디렉토리별로 .js 또는 .coffee 파일을 .html 파일로 문서화 한다

// git clone 후 

$ cd groc 디렉토리 이동후 모습 

// groc 를 수행한 후의 디렉토리 : lib 디렉토리에 있는 폴더를 상위 폴더로 올린다



///////////////////////////

// static 웹서버 구동 (참조)

$ static

serving "." at http://127.0.0.1:8080

17:35:09 [200]: /

17:35:09 [200]: /assets/style.css

17:35:09 [200]: /assets/behavior.js

17:35:09 [404]: /favicon.ico


  - 문서보기 : http://localhost:8080  Groc의 홈페이지 문서가 로컬에 만들어 졌다!


4. 사용 아이디어

  - GitHub에서 소스를 개발한다면 GitHub Page와 통합하여 API를 웹서비스 형태로 배포한다

  - 개발 소스에 대한 Code Review시에 Groc 문서로 만들어서 소스를 리뷰한다 

  


<참조>

  - Outsider dev 의 groc 소개

  - Pygments 설치하기

저작자 표시 비영리 변경 금지
신고

'Languages' 카테고리의 다른 글

[문서화 도구] Groc 사용하기  (0) 2013.03.09
APM 설치하기  (0) 2012.11.27
posted by peter yun 윤영식
2013.02.20 16:27 Languages/JavaScript

자바스크립트 개발자가 되고 싶다면 이렇게 배우자. 


1) 이럴때 자바스크립트를 배우자

  - 모던 웹 애플리케이션을 만들고자 할때

  - Backbone.js, Node.js, MongoDB와 같은 프레임워크나 자바스크립트 인터프리터를 탑재한 곳에서 개발 할때


2) 이렇게 배우진 말자

  - 온라인에서 튜토리얼이나 동영상 보고 배우지 말자

  - 초보자에게 더글라스 클락포드의 "JavaScript: The Good Parts" 책은 적합하지 않다 


3) 1~ 3주간 이렇게 배우자 

  - 공부할 책들

    + Professional JavaScript for Web Developers

    + JavaScript: The Definition Guid 6th (번역서 : 자바스크립트 완벽 가이드)

    + 코드아카데미 강좌 이용

  - 코드아카데미 Web Fundamentals 공부

  - Professional JavaScript 책 1장에서 3장까지 공부

  - 코드아카데미 JavaScript Fundamentals 공부

  - Professional JavaScript 책 4장에서 5장까지 쭉 공부

  - Definition Guide는 6장까지 쭉 공부 (번역본 읽어보니 주옥같은 내용이다. 강추)

  - Professional JavaScript 책 18장까지 공부 (원문에 챕터를 너무 분류했다)

  - Definition Guide를 다시 12장까지 공부 (서버사이드 자바스크립트 마스터)


4) 4~5주간 이렇게 배우자 

  - 코드아카데미 jQuery 배우기

  - Professional JavaScript 책 18장부터 끝까지 공부

  - Definition Guide 13장부터 끝까지 공부 (클라이언트 사이드 자바스크립트 마스터)

  - 이후엔 애플리케이션을 만들어 본다 


5) 6주차

  - Node.js를 이용하여 서버 코딩을 한다

  - Backboen.js를 이용하여 클라이언트 코딩을 한다 


6) 이후 좋은 참조 사이트들 공부하기 

  - 자바스크립트 디자인 패턴

  - 자바스크립트 Garden (번역)



<참조>

  - 원문 : http://javascriptissexy.com/how-to-learn-javascript-properly/

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2013.01.27 20:10 Languages/JavaScript

this를 자바스크립트에서 만나게 되면 이게 어느 인스턴스의 this인지 파악하기가 난해하다. this는 context(Execute Context)와 Scope(유효범위)에 대한 부분을 잘 알아야 한다. 


1) function안에서 변수 접근 권한

function someFunc() {
    var _this = this;
    something.on("click", function() {
        console.log(_this);
    });
};

  - var _this = this; 문구는 왜 사용하는 것일까?

  - 첫번재 유효범위(First Scope)는 Global Scope 이다

    + 모든 변수(Variable)과 함수(Function)은 global이다. 

    + Global Scope는 window 객체이다 

    + window.x = 9; 라고 property를 설정하면 어디서나 접근이 가능하다 


function myFunc() {
    var x = 5;
});
console.log(x); // undefined

  - x 는 myFunc()안에서 초기화 되었고, myFunc()안에서만 접근이 가능하다 

  - var 키워드를 사용하지 않으면 자동으로 global 유효범위로 만들어진다 

  - var 키워드를 사용하면 function이 호출 될때 생성되는 context에 지역변수로(local variable) 포함된다

function myFunc() {
    x = 5;
});
console.log(x); // 5


  - Outer Function에 정의된 모든 변수는 다른 Inner Function에서 접근을 할 수 있다

function outer() {
   var x = 5;
   function inner() {
      console.log(x); // 5
   }
   inner();
}


  - Outer Function에서는 Inner Function의 변수를 접근 할 수 없다 

function outer() {
    var x = 5;
    function inner() {
        console.log(x); //5 
        var y = 10;
    }
    inner();
    console.log(y); //undefined
}


2) this의 유효범위 

  - this는 function이 호출될 때 자동으로 설정되는 변수이다 

  - 변수의 값은 function이 어떻게 호출되냐에 따라 틀려진다

  - 자바스크립트에서 함수를 호출하는 주된 몇가지 방법을 가지고 있다. (주로 사용하는 3가지 방법)

    + function이 method처럼 호출하기 : when a function is called as a method === 오브젝트.function은 메소드라 칭함

    + 자기자신위에 호출하기  : when a function is called on it's own === function 자체가 호출 오브젝트.function이 아닐 경우

    + event handler로서 호출하기 : when a function is called as an event handler == 이벤트 핸들러 수행시 호출되는 function

function foo() {
   console.log(this); //global object
};

myapp = {};
myapp.foo = function() {
   console.log(this); //points to myapp object
또는 (같은 내용)
myapp = {
   foo: function() {
     console.log(this); //points to myapp object
   }
}

var link = document.getElmentById("myId");
link.addEventListener("click", function() {
   console.log(this); //points to link
}, false);

  - addEventLister를 사용하여 function을 붙이면 this의 값이 변경된다 : this값은 caller로 부터 function에 전달된다 



$("myLink").on("click", function() {
    console.log(this); //points to myLink (as expected)
    var _this = this;  //store reference
    $.ajax({
        //ajax set up
        success: function() {
            console.log(this); //points to the global object. Huh?
            console.log(_this); //better!
        }
    });
});

  - myLink을 click하면 function이 수행된다. 이때 이벤트 핸들러로서 펑션의 this는 myLink DOM element의 참조로 설정된다

  - 그러나 ajax 정규호출의 this는 global object로 this 값을 설정한다. 이는 "event handler"도 "오브젝트 method"도 아닌 function이기 때문이다

  - 위와 같이 하는 것이 function을 호출하는 곳에서 this에 대한 값을 정확히 사용하기 위한 방법이다



3) Crockford on JavaScrpt

  - 백박의 중년 신사분이 JavaScript 언어에 대해 설명을 하고 있다. 우리나라에선 상상할 수 없는 일이겠지, 큰 세미나에 가봐야 젊은 친구들의 열정만을 엿볼 수 있는 부분을 생각해 보면 그들의 환경이 참 부럽다.

  - 15분경의 동영상에서 this의 호출에 대해서 보자 

  - 31분경에서 정확한 Closure 사용법 설명



<참조> 

  - 원문 : Scope and this in JavaScript

  - Scope 한글 블로깅 연재

  - Naver Dev JavaScript 클로져, 유효범위

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2012.12.23 21:51 Languages/JavaScript

Java에서 할 수 있다면 ECMAScript에서도 할 수 있지 않을까? 테스트를 어떻게 하는지 알아보자 


  - named function을 사용하라 (가급적 anonymous function 사용 배제)

  - namespace를 사용한다

  - 속성, 펑션은 return {key:value} 클로저 객체로 리턴한다

  - 펑션 내부 계산로직에 대해 return 하여 검증할 수 있게 한다

  - Functional Testing

    + gebish.org

    + zombie.labnotes.org

    + phantomjs.org


  - 단위 테스트 

    + QUnit ( docs.jquery.com/QUnit )

    + sinonjs.org

    + mocha

    + JsTestDriver

    + YUITest


> JsTestDriver를 통한 효율적인 JavaScript 테스팅하기



  - JsTestDriver와 Maven 연결 테스트하기

  - JsTestDriver 설정을 통하여 Jenkins에 xUnit Plugin 연동하여 테스트

  - 여러 브라우저에 대하여 테스트하기 

  - http://tddjs.com 참조


> BDD(Behavior Driven Development) JavaScript 


저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2012.12.13 16:48 Languages/JavaScript

NHN의 자바스크립트 성능 이야기 Chapter 3을 간략히 정리한다. jsMatch 도구를 통한 성능 측정 수치를 제공하여 신뢰를 준다.



▶ 성능우위 문법


  - 배열 생성시 : var arr = new Array(); 보다 var arr = []; 를 사용한다

  - 배열 접근시 : arr.push(i) 보다 arr[i] = value 를 사용한다

  - 객체 생성시 : var obj = new Object(); 보다 var obj = {}; 를 사용한다

  - 객체 접근시 : obj["a"] = 1 보다 obj.a = 1; 를 사용한다 

  - 문자열 생성시 : var str = new String("aaa"); 보다 var str = "aaa"; 를 사용한다 

  - 문자열 연산시 : loop문에서 문자열 조작시에 str += "test"; 보다 arr=[]; loop{ arr[i]="test"; } arr.join(""); 을 사용한다 (String과 StringBuffer개념과 유사)

  - 정규표현식 : 탐색 대상을 축소한다. loop 문 안에 정규표현식 넣지 말고 밖에 놓아 한번만 컴파일 처리되게 한다. loop문에 있으면 계속 컴파일됨 



▶ 스코프 체인 탐색 줄이기

  - 스코프 체인 : 탐색 성능을 높이는 것이 본질 (자바스크립트 실행성능 저하는 변수, 객체, 함수의 메모리상 위치 탐색 작업임)

  - 스코프 체인 구성 = 활성화 객체(Activate Object) + 전역 객체(Global Object)

  - 활성화 객체 : 함수 내부 접근시 생성 (지역변수, this, arguments 객체) -> 함수 빠져 나오면 활성화 객체 제거 됨 

  - 실행 문맥(Execution Context) -> 스코프 체인 (1, 2) -> 활성화 객체 (1) -> 전역 객체 (2) 로 프로그램 수행됨 

  - 함수가 전역 속성 참조 순서 : 실행문맥 > 스코프 체인 > 활성화 객체 (함수) > 스코프 체인 > 전역 객체의 속성 참조 

  - 활성화 객체에서 전역 변수 사용시 : 함수 내부에 var LocalVariable = GlobalVariable;  식을 첨부 (전역속성 탐색을 제거함)



▶ 프로토타입 체인 탐색 줄이기

  - new 연산자로 생성된 인스턴스 객체는 생성자의 프로토타입을 참조하게 된다

  - var obj = new Object(); obj는 Object의 프로토타입 속성에 접근 할 수 있다

  - 자신의 객체만 접근하고 할 경우는 hasOwnProperty를 이요한다 (추가)



▶ 반복문 & 조건문


  - for~in 문은 가급적 쓰지 말라

  - for(~) 문안에 Array.length 구하는 함수등을 호출하지 말고, 외부에서 var length = Array.length를 설정한다. 스코프체인의 활성화 객체를 찾아가는 탐색 경로를 거치게 되므로 응답성능이 느려진다. 

  - 조건절을 빠른 탐색을 위한 알고리즘을 적절히 적용한다 : quick-sort, merge-sort, breadth first search, depth first search등 

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2012.11.12 16:26 Languages/JavaScript

JavaScript를 하면서 어려웠던 새로운 개념이 Closure이다. 이참에 조금 정리해 보도록 하자 


▶ Closure 개념

  - 로컬 변수를 참조하고 있는 함수 내의 함수 (JavaScript 마스터북, Jpub출판, p180)

  - 즉, 클로저는 자신의 범위(Scope) 밖에 있는 변수들에 접근할 수 있는 함수를 의미한다 

  - inner function을 return 할때 closure가 된다 (원문)

function outerFn() {

var count=1;

return function (cnt) {

      count += cnt;

console.log(count);

}

}


var func = outerFn();

func(10); // 결과 값 11

func(10); // 결과 값 21

  1) func가 closure가 됨 : 내부 변수들 closure, private 변수 생성됨

  2) func(parameter) 호출해 줘도 내부 변수들은 다시 생성되는 것이 아니라 상태를 유지시켜서 참조 됨 

  3) 즉, 클로저가 만들어 지면서 내부 변수들은 별도로 유지되면서 상태값을 유지함

  4) 클로저의 참조를 제거하고 GC할려면 명시적으로 func=null; 함



다른 예제를 보자 
예) closure가 아님 
function foo(x) {
  var tmp = 3;
  function bar(y) {
    console.log(x + y + (++tmp));
  }
  bar(10);
}
foo(2); // 결과 값 16
foo(2); // 결과 값 16
foo(2); // 결과 값 16

예) closure 임
function foo(x) {
  var tmp = 3;
  return function (y) {
    console.log(x + y + (++tmp));
  }
}
var bar = foo(2); // bar is now a closure.
bar(10); // 결과 값 16
bar(10); // 결과 값 17
bar(10); // 결과 값 18

var bar2 = foo(2);
bar2(10); // 결과 값 16
bar2(10); // 결과 값 17

  - 로컬 변수를 계속 생성하지 않고 상태를 유지하면 사용할 수 있다 (마치 객체처럼 var bar2 = foo(2); 하면 또 다른 closure가 생성되면서 bar와 별도의 상태공유 변수 x와 tmp가 생성된다. 마치 클래스에서 객체생성하는 것 처럼 된다. closure 생성시에 arguement와 var로 선언된 variable 에 대한 참조가 가능해 진다. 결국 참조자들-x, tmp-가 일정 메모리에 저장되어 상태를 유지한다)


  - 위의 예에서 var bar = foo(2);를 하는 순간 foo function 객체의 x, tmp 변수의 레퍼런스를 closure 가 가진다 (즉, x, tmp 에 대한 변수 상태값이 유지되고, y 값은 bar(10)을 호출할 때 넘겨주는 값이 된다)


  - 클로저는 간단한 객체이다 (엄밀히 따져서 객체는 아니지만 객체식으로 치환해서 살펴보면 다음과 같다)

    + 클로저 : 객체 = 클로저를 감싸고 있는 부모 함수 foo : 생성자

    + 클로저 : 객체 = 클로저로 부터 참조되는 로컬 변수 tmp :  프로퍼티

    + 클로저 : 객체 = 클로저 자신 bar, bar2 : 메소드

    + 클로저 : 객체 = var bar = foo(2) 함수 호출 : 인스턴스화

    + 클로저 : 객체 = 클로저를 대입하는 변수 bar(10), bar2(10) : 인스턴스 <-- 요거 애매함


  - function 내부에 for문을 돌면서 function을 호출하여 callback 을 셋팅하는 오류 제거 (원문1, 원문2)


실제 사용해 보면서 좀 더 이해를 해나가야 겠다. JavaScript Master북의 글이 좀 더 쉽게 이해가 가니, 햇갈릴 때 책을 다시 정독해 보자. 


<참조>

  - 소스니 코브 : Closure 이해하기

  - Closure 정리 : 한글이라 이해하기 쉬울것임

  - Inside.JS : 한글 정리 예제 포함

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2012.11.12 11:34 Languages/JavaScript

자바스크립트의 Function에는 Expression (FE) 과 Declaration (FD) 가 있다고 한다. 이에 대한 차이를 연구해 보자. 우선 존경해 맞이하는 소스니코브의 정리 내역과 구글링한 사이트를 읽고 정리한다 



▶ Function Declaration


  - 변수 할당 없는 이름있는 함수를 정의

  - "var"로 시작하지 않고 "function"으로 시작해야 한다(must)

- 명확한 이름을 가져야 한다
- 소스코드중에 오고 function body를 가지면 다른 function 안에도 위치한다
- entering the context stage에서 생성된다 (즉, function 안에 FD 존재않음)
- variable object(VO)에 영향을 준다 
function bar() {
return 3;

}


or


// 1) directly int the global context

function globalFD() {

// inside the body of another function

function innerFD() {}

}




▶ Function Expression


  - 변수 할당이 있는 표현식으로서 함수를 정의

  - 이름있는 또는 익명(anonymous) 함수 가능

  - FE는 "function"으로 시작하지 않아야 한다(must)

- 소스중에 expression position에 정의된다 
- 함수명은 optional 이다 
- variable object(VO)에 저장되지 않는다 
- code execution stage에서 생성된다 
// anonymous function expression
var a = function() {
return 3;
}

// named function expression
var a = function bar() {
return 3;
}

//self invoking function expression or immediately invoked function expression (IIFE, 즉시실행함수)
(function sayHello() {
alert("dowon hi");
})();

// in parentheses (grouping operator) can be only an expression
(function foo() {});

// in the array initialiser - also only expressions
[function bar() {}];

// comma also operators with expressions
1, function baz() {};


// FE is not available neither before the defintion

// because it is created at code execution phase.

alert(foo); // foo is not defined

(function foo() {});

// nor after, because it is not in the VO

alert(foo); // foo is not defined


// parentheses로 grouping 하기 

(function {}) ();

(function {}());


* Name Fuction Expression (NFE)

  - 재귀 호출을 위해 이름으로 자기자신을 호출할 수 있다 (이때 함수를 Variable Object에 저장할 필요가 있을까? 없다!)

  - 부모 context에서 생성할까? 노우!

  - FE로 하면 VO에 영향을 미치지 않는다 

(function foo(bar) {
if(bar) {
return;
}
foo(true); //foo name is available
})();

// but from the outside, correctly, is not  
// 즉, foo는 부모 scope에 없고 function의 [[Scope]]안에 specialObject에 저장한다 (하기 설명 참조)
foo(); // foo is not defined


위 소스 해석 (원문)

  - Interpreter가 code execution stage에서 FE를 만나면 FE를 생성하기 전에 special object를 만들고 현재 scope chain 앞에 놓는다 

  - FE 자신을 생성하고, 자신의 scope 프로퍼티에 scope chain 을 한다 (referencing)

  - special object에 unique 프로퍼티로 FE를 추가한다

  - 마지막에 parent scope chain으로 부터 special object를 제거 한다 

specialObject = {};

Scope = specialObject + Scope;

foo = new FunctionExpression;
foo.__scope__ = Scope;  // or foo.[[Scope]] = Scope;
specialObject.foo = foo; // [DontDelete], {ReadOnly}

delete Scope[0]; // remove specialObject from the front of scope chain



* FE의 특징

  - Variable Object (VO)에 속하지 않다 (스크립트 수행시 Execution Context-EC- 에 한 부분 = VO)

  - 따라서 FE는 Hoist안되고 FD만 Hoist 된다 (원문)

  - 그리고 FE는 자신의 내부 Scope에만 의미가 있지 외부(Outside)에는 의미가 전혀 없다 

  - VO = Function Declaration + Variable Declaration(var) + Arguments 들이 속한다 (FD가 최우선 순위 -> VD 순서로 Hoist됨)

  - FE로 하면 VO를 오염시키지 않기에 사용이 늘어나고 있다

예1)

bar(); // hoist 되어 정상 처리됨 

foo(); // error 발생 


function bar() { .... } // FD 

var foo = function() { .... }; // FE


예2)

var myFunction = function sameFunction() {

return myFunction === sameFunction; // true

};

console.log(myFunction()); // true 

console.log(sameFunction());  // [ReferenceError: contents is not defined] 에러 발생 



* FE에 사용하는 Grouping Operator 와 Immediately Invoked Fuction Expression (IIFE) 특징 

  - Grouping Operator인 () 은 variable과 function을 global scope와 격리된 private scope로 만드는 방법을 제공한다

  - IIFE는 jQuery, Underscore, Prototype, Dojo 등에서 global  scope을 깔끔하게 유지키 위해 private scope로 캡슐화, 모듈화에 중요하게 사용된다

  - 하기 예제는 외부세계로 부터 숨겨진 코드를 정의할 수 있고, private scope에서 동작하는 library variable을 만드는 것이다.

var Box = (function () {
    var contents = [];
    return {
        insert: function (thing) {
            contents.push(thing);
            return this;
        },
        count: function () {
            return contents.length;
        }
    };
})();

console.log(Box.insert('abc').insert(123).insert({
    width: 640, height: 360
}).insert(function () {
    return 'Hello!';
}).count()); // 4 를 출력

// This throws a ReferenceError since the JavaScript engine can't
// resolve the `contents` identifier.
// [ReferenceError: contents is not defined] 를 출력 
try {
    console.log(contents);  
} catch(err) { 
    console.log(err); 


  - IIFE는 function 호출처럼 arguements를 받고, 실행시간에 in-scope에 있는 모든 데이터에 대한 access가 가능한 Closure를 반환할 수 있다 (variable 상태 저장 가능)

var d, Saved, testSubject, i, l, x;

// Capture a start time.
d = new Date().getTime();

// `Saved` exposes a single API method `get` which returns that
// start time: the variable `d` is supplied as the argument
// identified within the function definition as `start`.
// 최기의  시작시간값을 저장하고 있다 
Saved = (function (start) {
    return {
        get: function () {
            return start;
        }
    };
})(d);

testSubject = {
    level1: {
        level2: {
            level3: {
                level4: {
                    val: 'value'
                }
            }
        }
    }
};

for (i = 0, l = 1000000; i < l; i++) {
    x = testSubject.level1.level2.level3.level4.val;
}

// Capture the time after diving five levels into the `testSubject`
// object literal one million times.
// 현재 시간을 구한다 
d = new Date().getTime();

// Output the current value of `d`.
// 현재 시간이 찍힘 
console.log(d); 

// Output the original value of `d`.
// 초기 IIFE의 시간이 찍힘
console.log(Saved.get());

// Output the difference which indicates how many seconds it took
// to do that object crawl.
console.log(d - Saved.get());

//------ 결과 
1352699019341 // d 현재 시간 
1352699019322 // Saved.get() IIFE 시간 
19  // 차이 값 



<참조>

  - javascript 블로그 : 간단하고 명확하게 정의내림 (표현형식만 설명)

  - 소스니 코브 : 너무 심도 있게 설명해서 집중하지 않으면 놓치기 쉬움 (왜 구별해서 사용하는지 설명)

  - 예제로 보는 javascript : Function Expression을 사용하는 이유를 가장 잘 설명함

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
2012.10.12 17:45 Languages/JavaScript

드미트리 소스니코브의 JavaScript Core에 대한 내용을 간략히 요약해 보자. 




▶ 오브젝트 (객체, An Object)

  - 오브젝트는 한개의 프로토타입 오브젝트를 가지고 있으면서 프로퍼티들의 집합이다. 

  - 오브젝트의 프로토타입은 내부 [[Prototype]] 프로퍼티에 의해 참조된다.

  - [[Prototype]] 보다는 __<internal-property>__ 를 사용하나, 특별히 프로토타입 오브젝트는 __proto__ 프로퍼티 변수로 표시한다.


예)

  var foo={

          x: 10,

          y: 20

   }

   해당 객체에는 3개의 프로퍼티가 존재하게 된다.

 



▶ 프로토타입 체인


  - 프로토타입 체인은 상속/공유되는 프로퍼티들의 구현에 사용되는 객체들의 유한 연결이다. 

  - ECMAScript는 자바와 같은 일반적인 class-based 상속이 아니라 prototype chain을 통하여 상속은 한다. 이를 위임형 상속(delegation based inheritance) 또는 프로토타입형 상속(prototype based inheritance)이라 한다. 

  - 이는 ECMAScript에는 class라는 개념이 없기 때문이다. 속성(프로퍼티)/메소드등을 동적으로 할당할 수 있기 때문에 class정의 자체가 필요없음

  - 예로 b, c의 공통영역에 a 객체를 저장하면, b, c는 자신에게 추가적인 프로퍼티와 메소드를 저장할 수 있는 것이다.  


  - b가 calculate 메소드를 찾아가는 방법 : b 객체안에 메소드가 없을 경우, prototype chain을 거쳐서 찾는다. 메소드를 찾는다. 찾지 못할 경우 undefined 값이 리턴된다.  (최상위 오브젝트 Object.prototype 값은 null 이다.) 

  - 주의 할것중 상속하여 사용시 this는 원래 객체를 가르킨다. 

  - 예로 this가 가르키는 객체로 this.y 는 b, c 객체이고, this.x는 a 객체를 가르킨다.  



▶ 생성자 (Constructor)


  - 생성자를 통해 객체를 생성시 유용한 것들이 있다. 

생성자를 사용하면 펑션의 prototype 프로퍼티가 <생성자 함수명칭>.prototype 객체를 가르킨다.  (그림 3.A)

예로 constructor function을 사용하여 b, c에 생성한 객체의 주소를 할당하면 b, c의 __proto__는 Foo.prototype 객체를 참조하게 된다. Foo.prototype 객체의 constructor는 원형의 constructor function 인 Foo를 가르키게 된다.

* 참조 : 자바스크립트의 new 의미 (http://zero.diebuster.com/zero/?p=36)



그림으로 그리면 다음과 같다 


  - Foo 자신의 __proto__는 Function.prototype 을 갖는다. 

  - Foo.prototype 오브젝트의 constructor는 자동 생성되어 Foo를 참조한다

  - Foo.prototype은 b, c 오브젝트의 prototype에 참조되는 Foo의 프로퍼티이다. (프로퍼티에 .x .calculate가 붙으면서 별도 객체가 되었다)


▶ Execution Context Stack

  - runtime program execution에 대해서 알려면 ECMAScript의 실행컨텍스트스택의 동작방식을 알아야 한다 

  - 3가지 타입 존재 : global code, function code, eval code 

  - 3가지 code는 execution context 인스턴스안에서 검증되어 진다. 

  - global context는 1개만 있고, function과 eval execution context들이 여러개 있게 된다. 만일 function이 호출되면 function execution context안으로 들어가 function code가 검증되어 진다. eval function은 특별히 eval execution context안에 들어서 eval code를 검증한다.  

  - Execution Context(EC)는 Stack에 담겨서 EC1 -> EC2 로 호출할 때마다 자기자신은 caller와 callee가 되어 코드 끝까지 수행이 되는 것이다. 

  글로벌 EC가 최소 caller가 되어 다음 foo(10) EC callee를 활성화 하고, foo(10) EC가 caller 되어 foo(20) EC callee를 활성화 하는 식으로 옮겨가는 구조를 Stack안에 구현되어 수행되는 것이다. 이른 execution context stack이라 한다. 


  - ECMAScript의 코드 동작방식에서 Global EC는 하나가 생성되어 있고, 펑션 EC는 Stack이 넣어져서 수행되고 완료되면 다시 Stack에서 빠지게 된다. 

  - 모든 EC를 Object로 간주되고, EC안의 code를 수행하는 주체가 된다. 



▶ Execution Context


  - EC는 context상태를 저장하기 위한 프로퍼티와 관련 코드 수행 경로 추적을 위한 프로퍼티등을 가지고 있는 단순 객체(오브젝트)이다.  

  - Variable Object (VO)는 EC와 관련된 scope of data 이다. (A variable object is a scope of data related with the execution context.)

  - 변수(variable)과 펑션선언(function declaration)을 저장한다. function expression은 저장하지 않는다. 



baz는 function expression이어서 Global Variable Object 에 저장되지 않는다. 


  - Activation Object (AO)는 Function context에서의 Variable Object이다. 

  - caller에 의해 function context가 활성화 되면 activation object가 생성되고 function이 호출된다. 

  - 호출시에 arguments객체-indexed map-에 파라미터 값를 담아서 넘겨준다.

  - activation object도 variable object이므로 variable, function declaration, 일반 파라미터, arguments 객체를 저장한다. 




▶ Scope Chain


  - 스코프 체인은 컨텍스트의 코드를 표현하는 식별자(identifiers)를 찾기위한 오브젝트 목록이다. (A scope chain is a list of objects that are searched for identifiers appear in the code of the context)

  - 규칙인 prototype chain과 동일하다. 

  - 즉, 자신의 스코프에서 variable/activation object를 못찾으면 부모의 VO/AO를 찾는다.

  - 스코프 체인은 일반적으로 부모 VO들의 목록(list)이다. 

  - context입장에서 식별자는 variable, function declaration, formal parameter들의 명칭이다. 


  - scope chain은 __parent__ 내장 프로퍼티로 연결된다. 또는 [[Scope]]로 나타내기도 한다.

이를 통해서 내부의 펑션이 외부의 변수 값을 참조할 수 있게 된다. 

반대로 만일 내부 펑션이 외부로 리턴되어 부모가 해당 펑션을 활성화하여 VO를 사용한다면 어떻게 될까? 요건 Closure 에서...




▶ Closure


  - ECMAScript에서 펑션은 일급 객체이다. (function is the first-class object)

  - 이말은 function을 다른 function에 argument로 전달 할수 있다는 것이다. - funargs- functional arguments라고 함

  - 또한 function을 리턴 할 수도 있다. functional value 라고 한다. 

  - funarg 문제는 closure 개념으로 풀어간다. 

  - Closure는 좀 더 상세하게 다른 쳅터에서 다룬다. 


▶ This 

  - This 값은 execution context와 관련을 맺는 특별한 오브젝트이다. 그래서 context object라고 불릴 수도 있다. 

  - 즉, an object which context the execution context is activated. 

  - this 값은 execution context의 프로퍼티이지 VO의 프로퍼티가 아니다. ( a this value is a property of the execution context, but not a property of the variable object.). 즉, this는 scope chain에 참여하지 않는다. look up 대상이 아니라는 것이다.

  - this 값은 caller에 의하여 제공받는다. 즉 EC1 -> EC2를 호출할때 EC1이 caller가 도고 EC2안에 this가 있다면 EC1의 오브젝트가 되는 것이다. 

  - 좀 더 자세한 사항은 다른 쳅터에서 다룬다. 


저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
prev 1 next