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

Publication

Statistics Graph

Category

Recent Comment

2014.12.31 19:31 Languages/Dart

Dart는 점점 복잡해 지는 웹 애플리케이션을 좀 더 견고하고 확장 가능토록 만들기 위해 나온 언어이다. 구글의 수많은 웹 서비스를 생각해보면 자바스크립트가 아니라 좀 더 낳은 개발 언어로 웹을 개발하고 싶어할 것이고 그러한 요구에 자체적으로 Dart를 개발하고 퍼트리는 느낌이랄까. 마치 서버에서 Go를 만들어 자신들의 서비스에 광범위하게 쓰고 있는 것과 같은 이치일것 같다. 그래서 적어도 현업에서 사용하지않는다 해도 어떤 모습이 미래의 웹 개발 언어가 되어야 하는지 살펴볼 필요는 있겠다. 생각은 이렇다. 웹 프론트앤드 개발은 Dart를 서버 백앤드 개발은 Go를 구글은 실험하고 있는 단계이다. 이들 모두 3년이상 지속해서 소개되고 사용되고 구글 클라우드에 적용되고 있다. 그러나 Dart는 프론트 백앤드를 모두 개발할 수 있다. 우선은 프론트앤드에 집중해서 보도록 한다. 






Dart 개념 익히기 

  

  - Dart 언어 개발자인 길라드 브라차로 부터 다트에 대해 들어보자

    + Dart type checking system에 대해 설명하고 있다. 

    + 자바의 JVM 스팩을 쓴 개발자 답게 언어 전문가의 냄새가 물신난다.

   

  - Dart 언어 개발자의 전체 소개 동영상이다. 

    + 다트 플랫폼 전체를 간략히 잘 설명해 주고 있다. 꼭 보자 

   


  - Dart언어의 특징을 간략히 보도록 하자. (한글)

   - 처음은 무조건 사이트부터 방법해서 https://angulardart.org/ 

    + 다트 소개 영상이다. 모든 것이 잘 요약되어 있다. (시리즈 동영상들)

    + Angular의 철학에 근거해서 만들어 졌기 때문에 테스트 가능하고 간결한 웹개발을 이끈다.

    + Dart 언어를 사용하기 때문에 class, annotation, inheritance등은 자바 개발자에게 익숙함을 제공하고 확장가능한 웹을 만듦

    + 모던 웹을 위한 Shadow DOM, Web Component를 시작할 수 있다. 

    참조)  테스트 가능성은 Angular의 DI (Dependency Injection)을 통해 가능해 진다. 

             Two-way data binding을 통해 간결한 코드 개발이 가능하다.

    


  - Dart로 시작하는 AngularDart는 Web Component 스팩을 구현하고 있는 Polymer.dart와 함께 어떤 방향으로 가는지 먼저 본다. 

    + 본영상이 JavaZone에서 발표됐다는 것은 자바 개발자에게 아주 익숙한 신택스로 Dart 언어가 구성되었기 때문일 것이다. 

    


  - Dart 언어에 대해 개념을 잡자

    + https://www.dartlang.org

  - DartEditor를 사용한다. 

    + 이클립스 기반이어서 자바개발자에게 친근감 마저 든다. 

    + 패키지 import 와 이클립스 debugging 등 확장자가 .java 에서 .dart로 바뀌고 웹과 서버 모두를 개발 할 수 있다. 

    


  - 문법 요약은 Dart Tip 11개에 대한 동영상을 보자





Dart 익히기 


 - Dart를 가지고 웹을 개발할 때는 어떻게 하는지 보자 

    

  

  - 웹 애플리케이션을 개발과정을 읽어보자 다트로 어떻게 하는 거지?

    + 다트는 기본적으로 Dart VM 에서 돌어간다. 웹에서 작동하려면 두가지 방법이 있다. 

    + 첫째는 Chormium 브라우져에 Dart VM을 넣은 Dartium 브라우져에서 수행. 

       개발시 Dartium으로 수행하면 DartEditor(Eclipse기반)에서 바로 디버깅이 가능하다. 

    + 둘째는 dart2js 툴 또는 pub build를 이용해서 자바스크립트로 바꿔서 일반브라우져에서 사용하는 것이다.  

    + DartEditor에서 Tools --> Pub Build(integrated JS)를 선택하면 모던 브라우져 모두에 수행 가능한 파일이 생성된다.

       


  - 본격적으로 Dart 강좌를 들어가자

  - Dart의 유용한 글과 라이브러리는 다토스피어(http://www.dartosphere.org/) 에서 검색한다. 

    + 다크관련 블로그 글들

    + 라이브러리 업데이트 현황

    + https://pub.dartlang.org 에서 배포된 다트 라이브러리를 찾을 수 있다.




Dart 는 메이져 모던 브라우져에서 수행된다. 


  - Dart를 Javascript로 변환해 주는 과정에 대한 설명 

    + 자바스크립트로 변환하고 top level 펑션은 $.main 이다. 

    + Tree Shaking 통해 필요없는 코드를 떨구어내고 자바스크립트로 전환한다는 의미 

    + Dart의 특징을 자바스크립트 코드로 어떻게 이식하고 있는지 설명한다. 예) Class 상속

    + JS로 전환할 때 많은 알고리즘과 방법이 동원되고 있다. 역시 문제 해결을 위해 알고리즘이 중요함 

    + JS로 전환할 때 --minify 로 사이즈를 줄여서 얻을 수 있다.(45분) 

    + 손으로 작성한 JS보다 성능이 좋다. 결론은 이것이다. 모바일에서 더 낳은 성능을 얻고 싶다면!!!

     

     



  계속해서 업데이트 예정...




<참조> 

  

  - dartlang.org




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

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

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

처음으로 새로운 프레임워크를 접하게 되었을 때 어떻게 시작해야할지 막막하다. 그럴땐 공부할 꺼리들을 정리해 보고 시작하자. 새롭게 시작할 AngularDart의 컨텐츠를 정리해 보자. 






AngularJS 개발자가 AngularDart 개발하기 


  - AngularDart의 상당 부분이 실은 AngularJS v2.0에 많은 영향을 미쳤다. (미스코의 말)

    + AngularJS개발자를 위한 AngularDart 이해하기

  - Dartlang을 모르고서 AngularDart를 보면 안되겠죠?  

  - UI Framework과 연동해서 웹 애플리케이션을 만들어 본다. (깃헙 소스)

    


  - 코드랩을 따라한다.

    + 예제 데모를 돌려보면 최신 IE 11, FF, Safari, Chrome에서 잘 돌아감. 

    + HTML의 디렉티브는 AngularJS와 거의 같음. 코드만 .dart 로 작성함 

  - 개발하며 API를 참조한다.





AngularDart와 Polymer 연동하기


  - 우선 AngularDart 소개영상과 25분부터 이어지는 Polymer.Dart를 보자 

    + 보고 있으면 아마도 ng-conf 2014에서 소개한 Angular v2.0 영상의 14분 부터 보면 뭔가 떠오를지 모르겠다. 

    

 

  - 첫번째 영상에서 Web Component 개념을 이야기하는 Polymer.dart를 다시 보자. 

  - 다시 정리하고 있는 Parsley의 Web Component & Dart 동영상을 보자

  - 따라하기 하며 Dart와 Polymer.dart를 연결해 보기 


계속해서 업데이트 예정...




<참조> 


  - Dart와 Web Component에 대한 다른 영상

  - 미스코 헤베리의 AngularDart를 만든 이유 

The Angular team's mission is to make building web-applications easy on the web. We want to support as many languages as possible.

AngularJS supports: JavaScript and through transpilation CoffeeScript and TypeScript.

AngularDart obviously supports Dart. 

1) Dart is significantly different from JavaScript that transpilation approach would not create the experience we were looking for, for this reason we have rewritten it. 

2) Dart has Types, and Type annotations, and so while rewriting AngularDart we have chose to take advantage of these language features. 

3) We have also learned from our mistakes on AngularJS and taken the opportunity to correct them, such as much improved Directive API. Finally we have take advantage of the latest browser technologies and based AngularDart on top of Shadow DOM.

4) All of the learnings we have gained in building AngularDart, will be applied back to AngularJS v2. This is only expected since AngularDart is younger than AngularJS.

Angular is a philosophy on how applications should be built and we wanted to make the question of language choice orthogonal to your choice of using Angular. Any web-language you choose, there is an Angular you can use with it.



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

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

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

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

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

스위프트 심화과정을 진행해 보자. 기본 문법을 배웠다면 프로젝트를 생성하고 이제 iOS 앱을 만들어 본다. 물론 앱개발시 기본 언어는 Object-C가 아니라 Swift이다. 




프로토콜


  - 특정 임무나 기능의 일부에 적합하도록 하기 위한 목적으로 작성된 메소드, 속성 등 요구사항에 대한 설계

  - 인터페이스 : 속성 변수와 메소드 포함, 대부분이 인터페이스를 통해 다형성을 보장하는 방식으로 프로그래밍함 

  - 클래스에서 구현 

protocol <pName> {

    func <fName>() {

    }

}


// 예

protocol Sample {

    func execute(name: String) -> String

}


class SampleImpl : Sample {

    func execute(name: String) -> String {

        return "hi \(name)"

    }

}


var s = SampleImpl()

s.execute("Peter")


  - 여러 인터페이스 구현은 콤마(,)로 구분함 




익스텐션 (Extension)


  - 자바스크립트에서 prototype을 통한 객체 자체의 메소드 확장기능과 유사함 

  - 가급적 최상위 클래스 변경은 하지 말자

extension <eName> {

   <확장 대상>

}


// 예

protocol NamedProtocol {

}


extension Int : NamedProtocol {

    var description : String {

        return "current value is \(self)"

    }

    

    func desc() -> String {

        return "current value is \(self)"

    }

    

    func getFirstName(name: String) -> String {

        return "\(self) name \(name)"

    }

}


7.description

7.desc()

7.getFirstName("dowon")




앱 프레임워크


  - 스토리 보드

    + 안드로이드의 XML 환경 설정과 유사함. 대신 비쥬얼하게 인터렉티브 UI 디자인이 가능하다 

  - iOS 4계층 프레임워크 

    + Core OS -> Core Services -> Media -> Cocoa Touch

    + Cocoa Touch : 파운데이션 (Foundation), UIKit 등이 포함,  접두어 : NS - 파운데이션, UI - UIKit

    + Core Services : 코어 파운데이션

  - Cocoa Framework 

    + 맥북의 애플리케이션 개발

    + Cocoa Touch F/W은 iOS 앱 개발 

    + 80% 가량이 Cocoa F/W 과 Cocoa Touch F/W 이 겹친다. 

  - Cocoa Touch F/W = Foundation F/W (NS*) + UIKit F/W (UI*)




스플래시


  - 최초에 뜨는 스플래시 화면 제어하기 

  - AppDelegate.swift 파일이 앱의 LifeCycle을 관리한다?

  - LaunchScreen.xib를 추가할 수 있다. => 프로젝트 Deployment Info의 Main Interface에서 최초 페이지를 선택할 수 있다. 




네비케이션 뷰 컨트롤러 


  - 뷰를 스택으로 관리한다

  - 기본이 되는 Root View Controller가 있다

  - push 하면 스택에 쌓여 위에 노출되고, pop 하면 화면이 제거됨 : pushViewController

  - 상단 메뉴 : Editor -> Embed in -> Navigation Controller를 추가한다 

class NextView : UIViewController {

    

    func nextView(ctrlName: String, transition: UIModalTransitionStyle) {

        // 두번째 화면의 인스턴스를 만든다

        var uvc: UIViewController = self.storyboard?.instantiateViewControllerWithIdentifier(ctrlName) as UIViewController

        

        // 화면 전환 스타일을 지정한다

        uvc.modalTransitionStyle = transition

        

        // 화면을 호출한다

        //self.presentViewController(uvc, animated: true, completion: nil)

        self.navigationController?.pushViewController(uvc, animated: true)

    }

    

    func dismissView() {

        //self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)

        self.navigationController?.popViewControllerAnimated(true)

    }

}




세그 (Segue)


  - 화면 연결 처리 전용 객체 

  - Source : 자신이 있는 곳

  - Destination : 목적지 

  - 연결 방법

    + 첫번째 화면(Source) 버튼을 Ctrl 누른 상태에서 두번째 화면(Destination)으로 드래그 앤 드롭을 하면 Segue 연결 팝업창이 나옴

    + 두번째 화면을 선택하고 오른쪽 상단의 마지막 아이콘 (->) 을 선택하고 Presenting Segues 에서 Present modally를 선택하고 첫번째 화면으로 드래그 앤 드롭해 연결

  - 값 전달하기 

    + 직접 전달 : 두번째 화면 컨트롤러로 캐스팅

    + segue를 연결해서 전달 : prepareForSegue 재정의 내역에 segue. destinationViewController를 두번째 화면 컨트롤러로 캐스팅

// 첫번째 화면 컨트롤러 

class FirstViewController : UIViewController {

    

    // source 화면에서 버튼을 추가하고 destination 화면으로 이동할 때 값을 전달하는 방법 

    @IBAction func nextPresentation(sender: AnyObject) {

        var uvc : SecondViewController = self.storyboard?.instantiateViewControllerWithIdentifier("secondViewController") as SecondViewController

        

        uvc.param = "Direct Parameter"

        

        self.presentViewController(uvc, animated: true, completion: nil)

    }

    

    // segue로 연결해서 값을 전달하는 경우 

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        var uvc : SecondViewController = segue.destinationViewController as SecondViewController

        

        uvc.param = "Segue Parameter"

    }

}


// 두번째 화면 컨트롤러 

class SecondViewController : UIViewController {

    

    var param : String = ""

    

    override func viewDidLoad() {

        NSLog("Excute Second View Loaded value is %@", param)

    }

}


  - 세그를 커스터마이징할 수 있다. : 이동 시간, 이동 효과등을 설정할 수 있다

    + 스토리 보드에서 custom segue를 선택하고 CustomSegue를 선택

import UIKit


// 반드시 상속 

class CustomSegue : UIStoryboardSegue {

    // 반드시 구현 

    override func perform() {

        let src = self.sourceViewController as UIViewController

        let dest = self.destinationViewController as UIViewController

        

        UIView.transitionFromView(src.view, toView: dest.view, duration: 1.0, options: UIViewAnimationOptions.TransitionCurlDown, completion: nil)

    }

}




접두어 


  - NS : 파운데이션 

  - CF : Core 파운데이션 

  - IB : @IBOutlet 같은 어노테이션이 컨트롤러에 있으면 스토리보드에서 자동 인식하는 것이다. 




UIAlertView


  - iOS 메세지 전달은 델리게이트 패턴을 쓴다 

  - 이벤트 처리 담당자가 따로 있어서 발생시 현재 떠 있는 창에 알려주는 구조 

  - UIAlertViewDelegate 프로토콜(protocol)을 구현하면 Alert View Controller를 제어할 수 있다



참조 


  - 옵셔널 체인 : 코드에서 ? 사용하기

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

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

[Swift] 스위프트 배우기 - 2일차  (0) 2014.11.27
[Swift] 스위프트 배우기 - 1일차  (0) 2014.11.26
posted by peter yun 윤영식
2014.11.26 12:30 Languages/Swift

애플의 새로운 언어인 스위프트(Swift)를 배워보자. 



배경


  - 안드로이드에 빼앗긴 시장을 다시 탈환하기 위한 새로운 언어 

  - Object-C의 굴레에서 벗어나 누구나 쉽게 접근할 수 있게 하고 싶다. 

  - 2014년 6월 2일 Apple WWDC 발표이후 2014년 11월까지 문법의 20%까지 바뀌었다. (Swift GM 정식 버전이 나옴)

  - 레퍼런스 북을 보자 




개념


  - Fast 빠르다 : LLVM 컴파일러 코드 분석기를 이용하여 컴파일과 최적화를 수행

  - Cocoa Framework 접근 : Mac - Cocoa Framework, iOS - Cocoa Touch Framework 접근 가능

  - Safe 안전하다

    + 자료형 자동 추론 및 안정성 증가 : try~catch 구문이 없다 

    + 포인터에 대한 직접 접근 제한

    + ARC(Automatic Reference Counting)를 사용한 메모리 관리 자동화 (OS X 10.7, IOS 5 버전 이상부터 ARC full feature 사용가능)

  - Modern

   + 파이썬 언어에 기반한 읽고 쓰기 쉬운 문법

   + 디버깅, 유지보스에 쉬운 코드 사용 (코코아 펑션은 옆으로 너무 길다)

  - Interactive

   + Xcode 6 의 playground에서 코드 작성하면서 결과 확인이 가능 

  - Unified

   + Swift <-> Object-C 간의 연계 가능 




문법 특징 


  - 컴파일언어가 아닌 스크립트 언어

  - 데이터 타입에 대한 구분이 엄격 : 변수, 상수 선언시 타입입이 결정

  - 엔트리 포인트가 없음 (Java의 main 같은 것이 없다)

  - 세미 콜론이 필요없음 (붙여도 무방)

  - 변수의 시작은 소문자, 클래스의 시작은 대문자로 하자 (대소문자 구분)

  - 문자 하나던 문자열든 더블 쿼팅 (이중 따옴표)를 사용한다

  - import를 사용해 라이브러리를 호출 (Node.js의 require와 유사)




Playground


  - Swift 언어 전용의 프로토타입용 코드 작성툴

  - 처리결과의 stack 확인 가능 (코딩 영역과 스택 영역 존재)




문법


  - 변수 선언 var, 상수 선언 let (상수 변경 불가 및 선언과 동시 초기화)

var addr = "과천시"

var zip : String

zip = "040-234"


let name = "Peter Yun"


단, 클래스의 인터턴스 상수일 경우 선언과 초기화 분리가능 

class ConstTest {

   let name : String = "hi"

}

   또는 

class ConstTest {

    let name : String

    init() {

        name = "Peter"

    }

}


  - 이름은 대소문자 구분, 첫자 숫자 안됨

  - 변수, 상수던 초기화 값에 따라 타입이 결정됨 (타입 추론 : Type Infer)

  - 선언과 초기화가 분리 될때는 타입 선언이 필요 (타입 어노테이션 : Type Annotation)

var name = "Peter"


// 타입 어노테이션

// var 변수명 : 데이터 타입

// 또는

// var 변수명 : 테이터 타입 = 값

var addr : String

addr = "Korea Seoul"


  - 타입 : Int, UInt / Float, Double / String(문자열형) / Character(문자형) / Bool

// 문자열형을 문자형으로 출력 

let str = "This is type"

for char in str {

    println(char)

}


  - "\(변수 또는 상수명)" 문자열에 포함 가능 및 expression 연산 가능  

let name = "Peter"

let str = "Hi \(name)"


// expression

let birthYear = 1980

let nowYear = 2014

let age = "My age is \(nowYear - birthYear + 1)"


let str02 = "1+2+3 = \(1+2+3)"


  - 단항, 이항, 비교, 논리 연산자 

// != 양쪽 띄워쓰기 안하면 오류 발생

var a = 20

var b = 30

println(a!=b)


  - 닫힌 범위 연산자 (Closed range operator) :  세개 점으로 표현  예) 1...5    (1,2,3,4,5)

  - 반닫힘 범위 연산자 (Half-closed range operator) :  두개 점과 <로 표현 예) 1..<5  (1,2,3,4), 배열 순회시 사용함 

let a=1

let b=5


for row in a...b {

    println(row)

}


for row in a..<b {

    println(row)

}


  - 집합 자료형 : 다수 개의 관련된 데이터를 묶음으로 관리할 수 있는 자료형

    + 배열 : Array

    + 튜플

    + 딕셔너리 : Dictionary




배열 


  - 배열 순회

var peter = ["hi", "peter", "yun"]

peter.append("Korea")


for(var i=0 ; i<peter.count ; i++) {

    println("\(i) 번째 \(peter[i]) 이것이다." )

}


for i in 0..<peter.count {

    println("\(i) 번째 \(peter[i]) 이것이다." )

}


for row in peter {

    println("element \(row) 입니다.")

}


  - 배열 선언 및 초기화 

    + Array<> 제너릭(Generic)을 사용함 

    + insert, append를 통해 확장함 

    + Array(count: 10, repeatedValue : "default") 형식으로 인덱스 개수 확보 

// 선언 

var 배열변수명 : Array<배열원소타입>

var 배열변수명 : [배열원소타입]


// 초기화 

var 배열변수명 = Array<배열원소타입>()

var 배열변수명 = [배열원소타입]()


// 선언 + 초기화 

var 배열변수명 : Array<배열원소타입> = Array<배열원소타입>()

var 배열변수명 : [배열원소타입] = [배열원소타입]()


// 예) 

var m : Array<String>

m = Array()


m.append("hi")

m.append("Peter")

m[2] = "zzz"  // error : 인덱스가 확보되지 않았기 때문 

println(m)


var n = [String]()

n.append("hi")

n.append("pp")

println(n)


var c = Array(count: 10, repeatedValue: "dd")

c[0] = "hi"

c[1] = "peter"

c[9] = "zzz"

println(c)


  - Array : 스위프트 자료형, NSArray/NSMutableArray : 파운데이션 프레임워크 자료형 




튜플


  - 집합 자료형 : 순서가 존재하지 않으며 (for 구문 순회할 수 없다는 의미), 이형 데이터를 모두 저장할 수 있는 집합 자료형 

  - () 기호속에 나열해 정의한다 예) ("A", 3, 15.5, true)

var tuple = ("hi", "peter", 35, true)


tuple.0

tuple.1

tuple.2

tuple.3


let (a, b, c, d) = tuple


  - 튜플은 함수에서 많이 사용한다 

func getT() -> (String, String, Bool) {

    return ("hi", "peter", true)

}


  - 딕셔너리 : 키/값을 사용

let cap = ["kr":"seoul", "us":"washington"]


cap["kr"]!  / "seoul"

cap["kr"]   / {Some "seoul"}


또는 


var cap2 : Dictionary<String, String>

cap2 = ["kr":"seoul", "us":"washington"]


cap["kr"]!

cap["kr"]


또는 


var cap3 : [String: String]

cap3 = ["kr":"seoul", "us":"washington"]


cap3["kr"]!

cap3["kr"]


  - 딕셔너리는 순회할 수 있다. 단, 순회시에 튜플 형태로 순회한다. 

for row in cap3 {

    let (key, value) = row

    println("\(key) = \(value)")

}


또는 


for (key, value) in cap3 {

    println("\(key) = \(value)")

}


  - 딕셔너리 값 수정 : updateValue:forKey

cap3.updateValue("SEOUL", forKey: "kr")   // 값 Optional("seoul") 반환 


cap3["kr"]!


  - ! 느낌표의 의미 : 옵셔널,  Optional("seoul") 을 "seoul" 로 변환 - 딕셔너리의 참조 




옵셔널 


  - 오류가 발생할 가능성이 있는 값 예) "hi".toInt() 일때 에러가 있을만한 것은 Optional로 랩핑해서 반환함

    + 모든 것에 대해 랩핑해 버림 

    + Optional()

"123".toInt()  ==> {Some 123}


  - 옵셔널 만들기 : 선언시 타입뒤에 ? 를 붙이면 Optional로 랩핑하여 반환함 

    + nil 이거나 정상값 

    + 느낌표 ! 는 옵션널 랩핑된 것을 벗겨내고 값을 표현할 때  사용한다 (옵셔널 강제 해제)

    + 딕셔너리의 경우 cap["key"] 의 경우 값이 nil일 수 있으므로 Optional 처리가 자동처리된다. 따라서 값을 얻을 때 cap["kr"]! 를 해줌.

var optInt : Int? 

var optStr : String?


var optStr : String?    ===> nil

optStr = "hi"              ===> {Some "hi"}


println(optStr)           ===> Optional("hi")

println(optStr!)          ===> "hi"


  - 문자의 경우 ! 사용전에 nil 체크를 해준다 

if optStr != nil {

    optStr!

}




함수 


  - func 키워드 사용

func 함수명 (인자명:타입, 인자명:타입 ... ) -> 반환_타입 {

    실행 내용

    return 반환값 

}




클래스와 구조체


  - Cocoa Touch Framework를 통해 가장 많이 사용하는 것임 

  - class, struct 둘다 첫 문자는 대문자

  - class, struct 둘다 속성 접근은 . (점) 사용 

class CName {

  statemment

}


// 인스턴스화 

var c = CName()


struct SName {

  statement

}


// 인스턴스화 

var s = SName()


  - 클래스 만의 특징

    + 상속이 가능 

    + 타입 캐스팅이 가능 

    + 디시리얼라이즈 통해 자원 해제 가능 

    + 참조 카운팅을 통해 클래스 인스턴스에 하나 이상의 참조 가능 

  - 타입 메서드 : 클래스 소속 메소드  

class Sample {

    func getInstance() -> Int {

        return 50

    }

    class func getClass() -> Int {

        return 100

    }

}


Sample.getClass()

Sample.getInstance()  // 에러 

var s = Sample()

s.getInstance()


  - init() 클래스의 생성자, 상속, override (재정의. 단, 중복정의는 안됨)

class NamedShape {

    var numberOfSides : Int = 0

    var name: String

    

    // 생성자 

    init(name:String) {

        self.name = name

    }

    

    func simpleDescription() -> String {

        return "A shape \(numberOfSides)"

    }

}


// 상속 

class Square: NamedShape {

    var sideLength: Double

    

    init(sideLength: Double, name: String) {

        self.sideLength = sideLength

        // 부모 생성자 호출 

        super.init(name: name)

        numberOfSides = 4

    }

    

    func area() -> Double {

        return sideLength * sideLength

    }

    

    // 재정의의

    override func simpleDescription() -> String {

        return "A square with sides of length \(sideLength)"

    }

}


// 인스턴스 사용 

let test = Square(sideLength: 5.2, name: "hi dowon")

test.area()

test.simpleDescription()

test.name




UIKit Framework 


  - 앱을 만들기 위해 반드시 사용하는 프레임워크 

  - NSObject 상속




참조 


  - ARC wikipedia


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

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

[Swift] 스위프트 배우기 - 2일차  (0) 2014.11.27
[Swift] 스위프트 배우기 - 1일차  (0) 2014.11.26
posted by peter yun 윤영식
TAG Apple, tuple
2013.09.28 17:45 Languages/JavaScript

자바스크립트의 상속과 성능향상을 위하여서는 Prototype Pattern을 갖는 Prototypal Inheritance를 이용한다.




개념

  - ECMAScript 5에서 Object.create 로 가능하다 

var myCar = { name: "Ford Escort", drive: function () { console.log( "Weeee. I'm driving!" ); }, panic: function () { console.log( "Wait. How do you stop this thing?" ); } }; // Use Object.create to instantiate a new car var yourCar = Object.create( myCar ); // Now we can see that one is a prototype of the other 

console.log( yourCar.name );

 

  - 오브젝트 확장할 때 

var vehicle = { getModel: function () { console.log( "The model of this vehicle is.." + this.model ); } };

// 두번째 인자에서 확장한다 Mixin... var car = Object.create(vehicle, { "id": { value: MY_GLOBAL.nextId(), // writable:false, configurable:false by default enumerable: true }, "model": { value: "Ford", enumerable: true } }); 


  - Object.create를 사용하지 않고 Construct Function의 prototype 프로퍼티를 이용하여 prototypal inheritance 구현 

var vehiclePrototype = { init: function ( carModel ) { this.model = carModel; }, getModel: function () { console.log( "The model of this vehicle is.." + this.model); } }; function vehicle( model ) { function F() {};  // 일급 클래스 펑션의 prototype을 vehiclePrototype객체로 정의 

// 상단 이미지에서 Foo의 프로퍼티인 propertype 변수에 Foo.prototype 객체를 참조한다

F.prototype = vehiclePrototype;

// new를 하면 vechiclePrototype객체가 f 변수에 할당 된다 var f = new F(); f.init( model ); return f; } var car = vehicle( "Ford Escort" ); 

console.log(car.getModel());

다른 방법으로 proto 전달 

var beget = (function () { function F() {} return function ( proto ) { F.prototype = proto; return new F(); }; 

})();



다양한 Object creation으로 메소드 확장하기

  - 메소드안에 정의 

    + getInfo는 Car 생성때 마다 생성되므로 메모리를 차지한다 (안좋음) 

function Car(make, model, level, color, warranty) {
    this.make     = make;
    this.model    = model;
    this.level    = level;
    this.color    = color;
    this.warranty = warranty;
    
    this.getInfo = function() {
        return this.make + ', ' + this.model + ', ' + this.level + ', '+ this.color + ', ' + this.warranty;
    };
}
 
var aCar = new Car('Acura', 'TL', 'Sport', 'blue', 5);

console.log(aCar.getInfo());  //displays Acura, TL, Sport, blue, 5 


  - 메소드를 외부에서 Prototype에 지정하기 

    + 필요한 시점에 메소드를 추가할 수 있다 예) Car.prototype.accelerate 

function Car(make, model, level, color, warranty) {
    this.make     = make;
    this.model    = model;
    this.level    = level;
    this.color    = color;
    this.warranty = warranty;
}
 
Car.prototype.getInfo = function() {
  return this.make +','+ this.model +','+ this.level +','+ this.color +','+ this.warranty;
};
 
var aCar = new Car('Acura', 'TL', 'Sport', 'blue', 5);
alert(aCar.getInfo());  //displays Acura, TL, Sport, blue, 5
 
Car.prototype.accelerate = function() {
    return 'How fast?';
};

console.log(aCar.accelerate()); //displays "How fast?"


  - Prototype Pattern을 이용

    + prototype에 필요한 메소드를 Literal 객체로 지정한다 

function Car(make, model, level, color, warranty) {
    this.make     = make;
    this.model    = model;
    this.level    = level;
    this.color    = color;
    this.warranty = warranty;
}
 
Car.prototype = {
    getInfo: function () {
      return this.make +','+ this.model +','+ this.level +','+ this.color +','+ this.warranty;
    }

};


  - Revealing Prototype Pattern을 이용

    + prototype에 객체를 생성하여 할당한다 

var UsedCar = function(mileage) {
    //Define a variable unique to each instance of UsedCar
    this.mileage = mileage;
};
 

UsedCar.prototype = new Car('Honda', 'Civic', 'LX', 'gray', 2);


// Revealing Module Pattern 형식

UsedCar.prototype = function () { }();



<참조>

  - 원문 : The Prototype Pattern

  - Some Prototype Pattern 사용하기 

  - Revealing Prototype Pattern 사용하기

  - 드미트리 소스시코브의 JavaScript Core

저작자 표시 비영리 변경 금지
신고
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.30 12:33 Languages/CoffeeScript

CoffeeScript의 컴파일과 Minify, 하나의 파일로 만들기 그리고 자동 변경체크하여 컴파일 하기를 좀 더 쉽게 하는 Coffeebar를 알아보자 



1) Coffeebar 기능과 설치

  - 기능

Supports Literate CoffeeScript

Robust file watching

Cross-platform

Minification

Concatenation of multiple source files

Shows the actual source line when concatenated files have a compile error


  - 설치

$ sudo npm install -g coffeebar

/usr/local/bin/coffeebar -> /usr/local/lib/node_modules/coffeebar/bin/coffeebar

coffeebar@0.2.0 /usr/local/lib/node_modules/coffeebar

├── mkdirp@0.3.5

├── xcolor@0.1.0

├── coffee-script@1.6.2

├── commander@1.1.1 (keypress@0.1.0)

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

├── beholder@0.1.2 (async@0.2.6, minimatch@0.2.11)

└── uglify-js@2.2.5 (optimist@0.3.5, source-map@0.1.19)



2) CLI 사용법

  - 옵션들

Usage: coffeebar [options] [path ...]


Options:


  -h, --help           output usage information

  -V, --version        output the version number

  -b, --bare           compile without a top-level function wrapper

  -m, --minify         minify output files

  -o, --output <path>  output path

  -s, --silent         suppress console output

  -w, --watch          watch files for changes


  - 컴파일 하기

$ coffeebar test.coffee


  - 소스 디렉토리(src)를 지정하여 컴파일 디렉토리(lib) 지정하기 

$ coffeebar src -o lib


  - 소스 디렉토리(src)를 지정하여 하나의 파일로 합치기

$ coffeebar src -o joined.js


  - 소스 디렉토리(src)를 지정하여 컴파일 디렉토리(lib) 지정하고 .coffee 소스 파일 변경되면 자동 컴파일하기 

$ coffeebar src -o lib -w



3) API 사용법

  - coffeebar(inputPaths, [options]) : inputPaths에 소스 디렉토리 지정하면 options에 따라 수행을 결정한다 

  - 옵션들

bare - (boolean) CoffeeScript compiler option which omits the top-level function wrapper if set to true.

minify - (boolean) Minify output files. Defaults to false.

output - (string) The path to the output file. If the path has a file extension, all files will be joined at that location. Otherwise, the path is assumed to be a directory.

silent - (boolean) Suppress all console output. Defaults to true.

watch - (boolean) Watch all files and directories for changes and recompile automatically. Defaults to false.


  - 예 : output 위치와 합칠 파일을 지정

// use the api in source

var coffeebar = require('coffeebar');

coffeebar('src', {output: 'lib/app.js'});


$ npm install

$ npm test



<참조>

  - 원문 : nmpjs.org coffeebar

저작자 표시 비영리 변경 금지
신고
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.31 23:06 Languages/CoffeeScript

CoffeeScript 문법중에서 꼭 알아야 할 것들에서 정리한다. 


1) Variables

  - 변수 선언을 하지 않는다 : 자동으로 var 붙음 

  - 세미콜론 ; 을 쓰지 않는다 

  - () 넣는 것은 옵션이다

 

2) Function

  - Named Function 과 Function Expression이나 둘다 coffee(); 를 호출한다 

  - Named Function을 Function Expression으로 변환하여 표현한다 (참조)

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

// Named Function

function coffee() {

  return confirm('dowon');

}


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

// Function Expression

var coffee = function() {
  return confirm('dowon');
}

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

// CoffeeScript 변환 

1) var 제거 

2) function() 을 -> 변환

3) {..} 컬리브레이스 와 ; 세미콜론 제거 


coffee = -> 

  confirm 'dowon'


4) confirm 은 1 tab 또는 2 space 로 들여쓰기를 한다 

5) CoffeeScript는 항상 return value를 갖는다 

6) 컴파일 되면 Function Expression과 동일하다 


3) String 변환

  - #{...} 사용한다 

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

// CoffeeScript

coffee = ->

   answer = confirm 'dowon'

   "hi #{answer}"


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

// Function Expression

var coffee;

coffee = function() {

  var answer;

  answer = confirm('dowon');

  return "hi " + answer;

}


4) Function Parameters

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

coffee = ->    호출 : coffee()


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

// ( ) 넣는 것은 옵션

coffee = (message) ->     

   호출 : coffee("dowon") 또는 coffee "dowon"  


coffee = (message, other) ->   

   호출 : coffee("hi", 2)  또는 coffee "hi", 2 


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

// 파라미터 기본 할당

coffee = (message = "dowon") ->

   answer = confirm message

   "hi #{answer}"


호출 : alert coffee()  또는 alert coffee("youngsik")


5) CoffeeScript CLI (Command Line)

  - coffee -c test.coffee : test.js 컴파일 

  - coffee -cw test.coffee : 내역이 업데이트 될 때마다 재컴파일 

  - coffee -c src -o js : src 디렉토리에 있는 .coffee 파일을 컴파일해서 js 디렉토리로 옮긴다 

  - coffee -wc src -o js : 파일이 업데이트 되면 재컴파일 한다 


6) jQuery 사용하기 

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

// jQuery 원본 

jQuery(function($) {

   function changeTab(e) {

     e.preventDefault();

     $(#tabs li a.active").removeClass("active");

     $(this).addClass("active")

  }


  $("#tabs ul li a").click(changeTab);

});


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

// CoffeeScript 변환   

$ ->

  changeTab = (e) ->

     e.preventDefault()

     $(#tabs li a.active").removeClass "active"

     $(@).addClass "active"


   $("#tabs ul li a").click changeTab

  


  - jQuery(function($) {   ==>   jQuery ($) -> 또는 $ -> 

  - function changeTab(e)  ==>  changeTab = (e) -> 

  - ( ) 와 ; 생략 

  - this ==> @ 변환 



7) if 문

  - ( ) 과 { } 를 제거 한다

  - 한줄 표현시 수행 문구를 앞으로 놓을 수 있다

  - 한줄 표현시 수행 문구가 뒤로 가면 then을 사용한다 

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

// JavaScript 

if (age < 18) {

  alert('dowon');

}


// 1차 변환 

if age < 18 

  alert 'dowon'


// 2차 변환 

alert 'dowon' if age < 18


// 3차 변환

if age < 18 then alert 'dowon'


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

// if else 구문 

if (age < 18) {

  alert('yun');

} else {

  alert('dowon');

}


// 1차 변환

if age < 18

  alert 'yun'

else

  alert 'dowon'


// 2차 변환 

if age < 18 then alert 'yun' else alert 'dowon'


8) Operator 

  - 주로 if문에 많이 사용

  

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

// CoffeeScript 

if paid() and coffee() is on then pour()


// JavaScript 변환 

if(paid() && coffee() === true) {

  pour();

}


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

addCaffeine() if not Decaf()   ===  addCaffeine() unless Decaf()


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

// JavaScript

if(2 < dodo && dodo < 5) {

  alert('youngsik');

}


// CoffeeScript 1차 

if 2 < dodo < 5

  alert 'youngsik'


// 2차 

if 2 < dodo < 5 then alert 'youngsik'


9) Switch 문 변환 

  - case <조건>: 을 when <조건> then 으로 변환 

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

// JavaScript 

var message = (function() {

  switch(coffee) {

    case 0:

       return 'hi';

    case 1:

       return 'haha';

    default:

       return 'dowon';

  }

})();


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

// CoffeeScript 변환

message = switch coffee

   when 0 then 'hi'

   when 1 then 'haha'

   else 'dowon'


10) undefined 와 null 체크 하기 변환 

  - ? 로 변환 

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

// JavaScript

if (typeof coffee !== "undefined" && coffee !== null) {

  alert("dowon");

}


// CoffeeScript 1차 변환 

if coffee?

  alert "dowon"


// CoffeeScript 2차 변환

alert "dowon" if coffee?


11) Existential 연산 변환

  - if not 을 unless 변환

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

// null 또는 undefined 일 때 0 으로 설정

// 1차 

if not coffee?

  coffee = 0 


// 2차

coffee = 0 unless coffee?


// 3차 

coffee ?= 0 


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

// null 또는 undefined 아니면 호출하기 

// 즉, 그것이 존재하면 function을 호출

// 1차

if coffee?

   coffee.brew()


// 2차

coffee?.brew()


12) 배열 변환 

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

// 변수 할당

range = [1..4]  ==>  var range = [1, 2, 3, 4];


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

// 변수 할당 

range = [1...4]  ==> var range = [1, 2, 3];


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

// 변수 사용

start = 5

end = 10

range = [start..end]

          값 [5, 6, 7, 8, 9, 10]


range[1..4] 

          값 [6, 7, 8, 9]


range[1...range.length]  이것은 요것과 동일 range[1..-1]

          값 [6, 7, 8, 9, 10] 


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

// 배열 콤마 제거 

locations = ['seoul', 'kyunggi', 'jeju']

또는

locations = [

  'seoul'

  'kyunggi'

  'jeju'

]


13) Loop 문 변환 

  - forEach 문 사용

  - for .. in 문 사용 

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

// CoffeeScript

// forEach 문 

locations = ['seoul', 'kyunggi', 'jeju']

locations.forEach(location, index) ->

  alert "location: #{location}"


// for .. in 문 1차 

for location in locations

  alert "location: #{location}"


// for .. in 문 2차 

alert "location: #{location}" for location in locations


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

// JavaScript

locations.forEach(function(location, index) {

  return alert("location: " + location);

});


to be continue...

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

정규표현식과 html안에 .coffee 확장자로 작성한 스크립트를 포함시키는 방법에 대하여 알아보자 


1) 정규 표현식 

  - /// .....  ///   슬래쉬3개 앞뒤로 하여 그사이에 표현식을 넣는다 

//////////////////////////////////////////
// regex.coffee
emails = ['ysyun@yuwin.co.kr', 'nulpulum@gamil.com', 'joe.567@gmail.com', 'andrew']

emailRegex = ///
	([\w\.+-]+) 	# unique name
	@				# at-sign
	(\w+)			# domain name
	(\.\w+[\w\.]*)  # tld
///

for email in emails
	match = email.match emailRegex
	if match?
		console.log "#{email} matched"
	else
		console.log "#{email} didn't matched"

//////////////////////////////////////////
// 컴파일 내역
// Generated by CoffeeScript 1.4.0
var email, emailRegex, emails, match, _i, _len;
emails = ['ysyun@yuwin.co.kr', 'nulpulum@gamil.com', 'joe.567@gmail.com', 'andrew'];
// 한줄로 표현된다 
emailRegex = /([\w\.+-]+)@(\w+)(\.\w+[\w\.]*)/;

for (_i = 0, _len = emails.length; _i < _len; _i++) {
  email = emails[_i];
  match = email.match(emailRegex);
  if (match != null) {
    console.log("" + email + " matched");
  } else {
    console.log("" + email + " didn't matched");
  }
}


2) Coffeescript를 컴파일한 Javascript 파일을 포함한 경우의 html

  - src/dom.coffee 파일 작성

  - js/ 디렉토리 밑으로 컴파일된 .js 위치 : coffee -c --watch -o js src/dom.coffee

    + --watch 옵션 : 변경내용을 감시하여 자동 재컴파일 수행 

  - 브라우저에서 웹서버 도움없이 바로 index.html 파일을 호출하면 된다. 

    + 단, jquery.js 파일은 동일 디렉토리에 위치 (첨부파일 참조)

//////////////////////////////////////////
// index.html 파일 
<!DOCTYPE html>
<html>
	<head>
		<title> CoffeeScript in the Browser </title>
	</head>
	<body>
		<div id="menu">
			<div>Tools</div>
			<div id="dropdown">
				<ul>
					<li>Tool 1</li>
					<li>Tool 2</li>
					<li>Tool 3</li>
				</ul>
			</div>
		</div>
		<script src="jquery.js"></script>
		<script src="js/dom.js"></script> <!-- 컴파일한 dom.js 파일을 포함시킨다 -->
	</body>
</html>  
// dom.coffee 파일로 jquery 기반 코딩
$ -> 
	menu = $ '#menu'
	dropdown = $ '#dropdown'
	dropdown.hide()

	menu.on 'mouseover', (e) -> dropdown.stop().show 200
	menu.on 'mouseout', (e) -> dropdown.stop().hide 200

//////////////////////////////////////////
// 컴파일 내역
$(function() {
  var dropdown, menu;
  menu = $('#menu');
  dropdown = $('#dropdown');
  dropdown.hide();
  menu.on('mouseover', function(e) {
    return dropdown.stop().show(200);
  });
  return menu.on('mouseout', function(e) {
    return dropdown.stop().hide(200);
  });
});


3) dom.coffee 파일을 직접 html안에 포함시키기 

  - html안에 coffee-script.js 파일을 포함시킨다 (첨부파일 참조)

    + 다운로드 한 파일의 extras 디렉토리 파일임

  - dom.coffee 파일을 포함시키고 type="text/coffeescript" 타입을 넣는다 

//////////////////////////////////////////
// index2.html 파일 
<!DOCTYPE html>
<html>
	<head>
		<title> CoffeeScript in the Browser </title>
	</head>
	<body>
		<div id="menu">
			<div>Tools</div>
			<div id="dropdown">
				<ul>
					<li>Tool 1</li>
					<li>Tool 2</li>
					<li>Tool 3</li>
				</ul>
			</div>
		</div>
		<script src="jquery.js"></script>
		<script src="coffee-script.js"></script>  <!-- 컴파일한 coffee-script.js 파일을 포함 -->
		<script src="src/dom.coffee" type="text/coffeescript"></script>  <!-- dom.coffee 포함 -->
	</body>
</html>  

  - 브라우져에서 로컬파일을 불러오게 되면 오류가 발생한다

  - 실행방법 : 웹서버 구동하여 브라우져에서 호출 

    + node-static 을 설치한다 (블로그 참조)

    + $ static : dom.coffee 파일이 있는 곳에서 수행 (8080 포트로 브라우저에서 호출함)

     


  - 최종 파일 구조     

    

 

* 파일 

coffeescript-5.zip



<참조>

  - 자바스크립트 정규표현식

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

Java 처럼 Class를 쉽게 만들어 보자. 클래스끼리 상속하여 재정의(overriding)하는 부분도 알아보자 


1) Class 만들기 

  - class 로 표현한다

  - 컴파일 내역에 IIFE(즉시실행함수)안에 다시 Dog을 생성하여 호출함 

// clazz.coffee
class Dog

// 컴파일 내역 : clazz.js 
// Generated by CoffeeScript 1.4.0
(function() {
  var Dog;
  Dog = (function() {
    function Dog() {}
    return Dog;
  })();
}).call(this);


  - constructor 로 생성자를 정의한다

  - constructor를 사용하면 Dog 생성자가 생성되고 다른 프로퍼티는 prototype에 정의된다 

// clazz2.coffee
class Dog
	constructor: (@name) ->
	growl: -> console.log '*growl*'

dog = new Dog 'Dowon'
console.log dog.name
dog.growl()

// 결과
D:\Development\coffeescript\4>coffee clazz2
Dowon
*growl*

// 컴파일 내역 : clazz2.js
// Generated by CoffeeScript 1.4.0
var Dog, dog;
Dog = (function() {
  function Dog(name) {
    this.name = name;
  }
  Dog.prototype.growl = function() {
    return console.log('*growl*');
  };
  return Dog;
})();

dog = new Dog('Dowon');
console.log(dog.name);
dog.growl();


2) 상속 관계 만들기 

  - extends 사용하여 상속관계 정의 한다

  - super() 사용하여 동일 메소드에 대한 재정의(Overriding)을 한다 

// clazz3.coffee
class Dog
	constructor: (@name) ->
	growl: -> console.log '*growl*'

class BorderCollie extends Dog
	constructor: (name, @tricks = []) ->
		super name
	perform: (trick) -> console.log if trick in @tricks then "#{@name} is #{trick}" else '*whine*'	
	growl: (person) ->
		if person is @master
			console.log '*bark*'
		else
			super() # Dog.growl()
 
dog = new Dog 'Dowon'

console.log dog.name
dog.growl()

dog2 = new BorderCollie 'YoungSik', ['playing', 'catching', 'rolling']
dog2.master = "Dowon"

console.log dog2.name
dog2.perform 'rolling'
dog2.growl("Dowon")
dog2.growl("Yun")

// 결과 
D:\Development\coffeescript\4>coffee clazz3
Dowon
*growl*
YoungSik
YoungSik is rolling
*bark*
*growl*

  - BorderCollie extends Dog 으로 상속 만들어 줌 

  - BorderCollie의 constructor안에 "super name" 을 호출하여 super(name)을 넣어 줌

  - BorderCollie의 grow안에서 super() 를 호출하여 super.growl()을 넣어 줌 

// 컴파일 내역 : clazz3.js 
// Generated by CoffeeScript 1.4.0
(function() {
  var BorderCollie, Dog, dog, dog2,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

  Dog = (function() {
    function Dog(name) {
      this.name = name;
    }
    Dog.prototype.growl = function() {
      return console.log('*growl*');
    };
    return Dog;
  })();

  BorderCollie = (function(_super) {
    __extends(BorderCollie, _super);
    function BorderCollie(name, tricks) {
      this.tricks = tricks != null ? tricks : [];
      BorderCollie.__super__.constructor.call(this, name);
    }
    BorderCollie.prototype.perform = function(trick) {
      return console.log(__indexOf.call(this.tricks, trick) >= 0 ? "" + this.name + " is " + trick : '*whine*');
    };

    BorderCollie.prototype.growl = function(person) {
      if (person === this.master) {
        return console.log('*bark*');
      } else {
        return BorderCollie.__super__.growl.call(this);
      }
    };
    return BorderCollie;
  })(Dog);

  dog = new Dog('Dowon');
  console.log(dog.name);
  dog.growl();

  dog2 = new BorderCollie('YoungSik', ['playing', 'catching', 'rolling']);
  dog2.master = "Dowon";
  console.log(dog2.name);
  dog2.perform('rolling');
  dog2.growl("Dowon");
  dog2.growl("Yun");

}).call(this);

* 파일 

coffeescript-4.zip


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

객체의 function으로 호출될 때 this. 값을 어떻게 줄여서 표현 하는지와 prototype 도 알아보자. 또한 extends를 어떻게 사용하는지도 알아본다


1) this.name = name 표현하기 

  - this. 을 @ 로 표현한다 

// prototype.coffee
###
function Dog (name) {
	this.name = name;
}
Dog.prototype.growl = function() {
	console.log("*growl*");
}
r = new Dog("Dowon");
r.growl();
###

Dog = (name) -> 
	@name = name # this.name = name

d = new Dog 'Dowon'
console.log d.name

console.log '----same thing----'

Dog2 = (@name) ->  # 파라미터로 @name을 쓰면 위와 같은 표현임 

d2 = new Dog2 'Dowon'

console.log d2.name 

// 결과 
D:\Development\coffeescript\3>coffee prototype
Dowon
----same thing----
Dowon

// prototype.js 컴파일 내역
(function() {
  var Dog, Dog2, d, d2;
  Dog = function(name) {
    return this.name = name;
  };
  d = new Dog('Dowon');
  console.log(d.name);

  console.log('----same thing----');

  Dog2 = function(name) {
    this.name = name;
  };
  d2 = new Dog2('Dowon');
  console.log(d2.name);
}).call(this);


  - Tip : 만일 (function(){ 코딩내역 }).call(this)  을 없애고 싶다면 --bare 옵션을 사용하면 됨



2) prototype. 표현하기

  - prototype. 을 :: 로 표현한다  

// prototype2.coffee
Dog = (@name) ->

Dog.prototype.growl = ->
	console.log '*growl*'

d = new Dog 'Dowon'
d.growl()

console.log '----same thing----'

Dog2 = (@name) ->
	
Dog2::growl = ->   # :: 로 표현한다 
	console.log '*growl*'

d2 = new Dog2 'Dowon'
d2.growl()

//결과 
D:\Development\coffeescript\3>coffee prototype2
*growl*
----same thing----
*growl*

// 컴파일 내역 : prototype2.js
// Generated by CoffeeScript 1.4.0
(function() {
  var Dog, Dog2, d, d2;
  Dog = function(name) {
    this.name = name;
  };
  Dog.prototype.growl = function() {
    return console.log('*growl*');
  };
  d = new Dog('Dowon');
  d.growl();

  console.log('----same thing----');

  Dog2 = function(name) {
    this.name = name;
  };
  Dog2.prototype.growl = function() {
    return console.log('*growl*');
  };
  d2 = new Dog2('Dowon');
  d2.growl();
}).call(this);


3) 상속에 대한 표현

  - extends 를 통하여 상속받기

// extend.coffee
Dog = (@name) ->

Dog.prototype.growl = ->
	console.log '*growl*'

BorderCollie = (@name, @tricks) ->

BorderCollie extends Dog

BorderCollie::perform = (trick) ->
	if trick in @tricks
		console.log "#{@name} is #{trick}"
	else
		console.log '*whine*'

dowon = new BorderCollie 'Dowon', ['playing dead', 'catching', 'rolling']

dowon.perform 'catching'
dowon.growl()	

// 결과 
D:\Development\coffeescript\3>coffee extend
Dowon is catching
*growl*

// 컴파일 내역 : extend.js
// Generated by CoffeeScript 1.4.0
(function() {
  var BorderCollie, Dog, dowon,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

  Dog = function(name) {
    this.name = name;
  };
  Dog.prototype.growl = function() {
    return console.log('*growl*');
  };

  BorderCollie = function(name, tricks) {
    this.name = name;
    this.tricks = tricks;
  };

  __extends(BorderCollie, Dog);

  BorderCollie.prototype.perform = function(trick) {
    if (__indexOf.call(this.tricks, trick) >= 0) {
      return console.log("" + this.name + " is " + trick);
    } else {
      return console.log('*whine*');
    }
  };
  dowon = new BorderCollie('Dowon', ['playing dead', 'catching', 'rolling']);
  dowon.perform('catching');
  dowon.growl();
}).call(this);

 @ :: extends 를 익히자 ^^

coffeescript-3.zip


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

티스토리 툴바