TypeScript 언어 핵심 요약 사항

TypeScript 핵심 요약은 ES6 에 추가된 기능과 중복된 항목이 있다. TypeScript 는 Javascript 의 슈퍼셋(Superset)이라고 하지만, 아직 ES6 를 완벽하게 지원하지 않는다. 그래서 본 글의 핵심 요약은 TypeScript 에서 추가된 기능이자 ES6 와 중복된 내용이 있다.

ES6 의 새로운 기능은 다음의 링크에서 참고하기 바란다.

TypeScript 2.1 최신이고 아직 꾸준히 업데이트 중이며, 1.8 버전을 기준으로 비교된 ES6 와 호환 테이블이다.

TypeScript 의 모든 언어 사양은 아래의 링크를 참고하기 바란다.


1. var vs let 키워드

var 키워드는 Javascript 의 그 var 키워드와 동일한 역할을 한다. var 키워드는 function scope 단위로 할당이 된다. 그래서 아래의 예제와 같이 원하지 않는 결과를 얻을 수도 있다.

일반적으로 사용하는 방법은 Javascript 의 var 와 동일하게 사용하면 되고, TypeScript 에서는 되도록 let 을 쓰도록 권장하고 있다.

var 키워드

for (var i = 0; i < 10 ; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
10
10
10
10
10
10
10
10
10
10

let 키워드

for (let i = 0; i < 10 ; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
0
1
2
3
4
5
6
7
8
9

2. Indexable 타입

C# 의 인덱서와 동일한 역할을 하는 Indexable 타입이 있다. Cars 인터페이스가 배열/컬렉션 객체가 아니지만, 마치 배열/컬렉션 객체의 아이템을 가져오는 것처럼, 인덱서를 사용할 수 있다.

interface Cars {
    [num: number]: string;
}

let cars: Cars;
cars = ["Cadillac", "Benz", "BMW", "Audi"];

console.log(cars[0]);

3. Hybrid 타입

인터페이스에 함수를 인터페이싱 하는 방법 중의 하나다. (start: number): string; 는 익명 함수를 선언하고 있고, reset() 은 명시적으로 함수를 선언하고 있다. <Counter> 는 캐시팅을 명시적으로 지정하였으며 counter 변수는 Counter 객체로 캐스팅 된다.

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start: number) { };
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

4. protected 키워드

객체지향언어의 protected 키워드와 동일한 역할을 한다. 클래스 맴버가 상속받은 자식 클래스에만 노출이 된다.

class Person {
    protected name: string;

    constructor(name: string) {
        this.name = name;
    }
}

class Student extends Person {
    constructor(name: string) {
        super(name);
    }

    say(): void {
        console.log(this.name);
    }
}

let student: Student = new Student("POWERUMC");

student.say();
student.name = "POWERUMC"; // Error

5. Optional and Default 파라메터(Parameters)

Optional 파라메터(Parameters)

기본적으로 TypeScript 는 Javascript 함수처럼 가변적인 매개변수를 지정하여 함수를 호출할 수 없다. (아래 6번에서 가능한 방법을 설명한다.) 여타 객체지향언어처럼 매개변수와 타입에 맞게 호출하는 것이 객체지향언어의 규약이다.

마찬가지로 TypeScript 에서도 함수를 호출하려면 타입에 맞아야 한다.

function test(src:string, dest:string): boolean {
    return src === dest;
}

test("P", "P");
test("P");          // Error

이를 Optional 매개변수로 만들기 위해서 dest? 로 지정하면 된다. dest? 매개변수에는 undefined 가 된다.

function test(src:string, dest?:string): boolean {

    console.log(dest);
    return src === dest;
}

test("P", "P");
test("P");          // Ok

Default 파라메터(Parameters)

Default 파라메터로 만들기 위해 dest = "" 와 같이 리터럴 상수값을 선언하면 된다.

function test(src:string, dest = ""): boolean {

    console.log(dest);
    return src === dest;
}

test("P", "P");
test("P");          // Ok

6. 가변적인 매개변수(Rest Parameters)

...restOfName 처럼 매개변수 이름 앞에 ...을 붙이면 가변적인 매개변수가 된다.

function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}

let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;

7. 오버로드(Overloads)

첫 번쨰 pickCard 함수는 명시적으로 object 리터럴로 감싸고 number 타입을 반환하는 함수이고, 두 번째 pickCard{suit: string; card: number; } 타입을 반환하는 함수이다.

세 번째 pickCard 함수가 메인 함수인데, 타입을 체크하여 각각 처리 후 결과를 반환하는데 반환 타입이 다르다는 것을 알 수 있다.

let suits = ["hearts", "spades", "clubs", "diamonds"];

function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
    if (typeof x == "object") {
        let pickedCard = Math.floor(Math.random() * x.length);
        return pickedCard;
    }
    else if (typeof x == "number") {
        let pickedSuit = Math.floor(x / 13);
        return { suit: suits[pickedSuit], card: x % 13 };
    }
}

let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

8. 제네릭(Generics)

C# 의 '제네릭(Generics)' 또는 C++ 의 '템플릿(Tempaltes)' 는 코드 재사용성을 높이고, 타입 안정성, 그리고 성능에서 큰 이점을 준다.

TypeScript 또한 이러한 이점을 그대로 얻을 수 있다.

제네릭 함수(Generic Functions)

function identity<T>(arg: T): T {
    return arg;
}
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <T>(arg: T) => T = identity;
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <U>(arg: U) => U = identity;
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: {<T>(arg: T): T} = identity;
interface GenericIdentityFn {
    <T>(arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn = identity;

제네릭 클래스 (Generic Classes)

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

9. Nullable Types

let s = "foo";
s = null; // error, 'null' is not assignable to 'string'
let sn: string | null = "bar";
sn = null; // ok

sn = undefined; // error, 'undefined' is not assignable to 'string | null'
function f(x: number, y?: number) {
    return x + (y || 0);
}
f(1, 2);
f(1);
f(1, undefined);
f(1, null); // error, 'null' is not assignable to 'number | undefined'
class C {
    a: number;
    b?: number;
}
let c = new C();
c.a = 12;
c.a = undefined; // error, 'undefined' is not assignable to 'number'
c.b = 13;
c.b = undefined; // ok
c.b = null; // error, 'null' is not assignable to 'number | undefined'

10. for..of 과 for..in 구문(statements)

for..in 구문은 배열의 키 값을 반환하는 한편, for..of 구문은 배열의 항목을 반환하는 다른점이 있다.

따라서 for..of 구문을 사용하는 것을 권장한다.

let list = [4, 5, 6];

for (let i in list) {
   console.log(i); // "0", "1", "2",
}

for (let i of list) {
   console.log(i); // "4", "5", "6"
}

11. 데코레이터(Decorators)

데코레이터(Decorators)는 C# 의 특성(Attributes), Java 의 어노테이션(Annotations) 와 같이 클래스나 함수에 선언적으로 정보를 지정할 수 있다.

reflect-metadata 모듈을 이용하면 런타임에 리플랙션을 이용하여 이 데코레이터의 정보를 얻어와서 처리를 하는 방법도 있다.

function f() {
    console.log("f(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("f(): called");
    }
}

function g() {
    console.log("g(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("g(): called");
    }
}

class C {
    @f()
    @g()
    method() {}
}
f(): evaluated
g(): evaluated
g(): called
f(): called


Posted by 땡초 POWERUMC

댓글을 달아 주세요

인터넷 웹 서비스들이 느려졌다

HTML5 구현체가 속속 모습을 보이면서 웹 서비스들은 다양한 시도를 하고 있다. 과거에는 인터넷을 통해 콘텐트를 생산하여 전파를 했고, 이 콘텐트가 사람들을 모이게 했다. 웹을 통해 커뮤니케이션이 이루어 지면서 비슷한 관심사의 유저들에 의해 인터넷 커뮤니티가 속속 등장했다.

이것이 개인화로 이어지면서 개인이 운영하는 블로그가 많은 인기를 얻었다. 블로그를 열심히 잘 운영하면 사회 지위적인 약자도(a weak person), 잘 알려지지 못한 무림속의 전문가도 여러 사람의 관심을 받을 수 있는 발언권을 가질 수 있게 되었다. 웹 서비스가 자신을 PR하고 개인의 비즈니스 모델이 될 수 있음이 증명되었다.. 필자도 그런 부류 따위의 한 사람이다.

하지만 최근 인터넷 웹 서비스는 예전 보다 더 쾌적한 환경을 제공하는 지 의심이 된다. 방문하는 웹 사이트마다 괴롭다. 네트워크 대역은 더 용량은 더 커졌고, 개인 PC와 스마트폰의 CPU는 더 빨라짐에도 여전히 브라우저로 인터넷 서비스를 이용하는 것은 더 느려졌고 더 많이 기다려야 한다.

이런 몇 가지 주요 요인은 다음과 같이 정리된다.

1. Javascript 언어 본질적인 문제라기 보다

브라우저에서 동작하는 Javascript가 주요 원인이다. 브라우저에서 동작하는 Javascript는 운영 체제의 커널(kernel)이나 드라이버(driver)에 접근할 수 없으므로 가장 빠른 네이티브 함수를 사용할 수 없다.

Javascript 에서 thread(스레드)와 process(프로세스)를 그 외에 GPGPU(General-Purpose computing on Graphics Processing Units) 와 같은 네이티브 함수에 접근할 수 있다면, 브라우저는 '터보 엔진'을 장착한 것이다.

2. 또, 브라우저는 인터넷의 리소스를 동시에 다운로드 할 수는 있으나

Javascript는 동시에 처리할 수 없다. 

다운로드 받은 여러 개의 Javascript 파일은 빠르다고 소문난 크롬의 v8 엔진이 제공하는 context 객체에서 순차적으로 실행이 된다. 그 안에서 function을 만나면 scope 가 생성이 되는데, 이 scope을 병렬로 처리할 수 없고 blocking 되어 실행되어야 context안의 scope의 atomicity(원자성)이 보장된다. 풀어서 다시 정리하자면, javascript는 concurrents 일 수는 있으나 parallels 할 수 없다.

3. 이번 것은 필자가 제일 싫어하는 문제다.

HTTP/HTTPS는 stateless protocol 이므로 브라우저가 redirect/submit마다 매번 인터넷 리소스나 Javascript 를 reload 하게 된다. 브라우저 랜더링 성능을 향상시키기 위해 Javascript 파일을 HTML 문서 하단에 두는 추세이다. 그 결과 브라우저에 표현될 요소들은 모두 표시되었으나 자바스크립트 컴파일이 가장 마지막에 수행되므로 마우스나 키보드 동작 이벤트가 바로 발생하지 않는다. 

한 마디로, 굼떠진다. 브라우저의 화면은 다 떴는데, 마우스 휠과 움직임 그리고 클릭 같은 동작이 툭~툭~ 끊기거나 freezing 되어 버린다.

4. 프로그래밍 측면에서 오버 엔지니어링도 문제다.

웹 페이지에서 [AngularJS]와 같은 라이브러리를 사용하는 것도 성능 저하와 밀접한 관련이 있다. (nodejs 제외)

AngularJS 라이브러리는 공식 페이지에서 다음과 같이 소개한다.

HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications.

AngularJS의 가장 best practices 는 정적 페이지다. SPA(single page application)에 최적화 되어 있다. 하지만, 웹 응용 프로그램에 쓴다고 하더라도 문제가 될 것은 없다.

하지만 AngularJS를 MVC 웹 응용 프로그램과 같이 쓰게 되면 동일한 패턴을 관리하는 포인트가 하나 더 생긴다. 웹 응용 프로그램 레벨에서 MVC 패턴과 View 레벨에서 한번 더 AngularJS와 같은 MV(C) 패턴이 추가 된다. 필자 경험으로 웹 페이지에서 controlling이 필요한 view는 자주 보기 힘들다.

웹 페이지에서 model binding이 필요한 건지, view-model, templating이 필요한 건지 controlling이 필요한 건지, 다시 생각해 볼 수 있는 문제다.

결론

우리나라 속담에 '뱁새가 황새 쫓다가 가랑이 찢어진다'가 있다.

웹이 네이티브 쫓다가 가랭이 찢어진다. 인터넷 웹 서비스가 발전하고 있는 경향은 웹 브라우저에서 네이티브 데스크탑 응용 프로그램(desktop application)과 같은 사용자 경험(user experiences)을 제공하고 싶어 한다.

앞으로도 웹의 기술적인 진화는 네이티브 데스크탑 응용 프로그램 처럼 동작하기 위한 요소들이 추가될 것이다.

AJAX(asynchronous javascript and xml), web socket, web db, comet 과 같은 기술은 분명 웹을 진화시켰다. 하지만 웹 다워 졌다가 아니라, 네이티브 처럼 표현하기 위한 수단이 되었다. 그리고 지금은 많은 웹 서비스들이 네이티브 응용 프로그램을 웹 서비스로 그대로 옮겨 놓았다. 혁신적이기는 하지만 굳이 웹을 통해서 이용할 생각은 없다. 가끔 필요할 때 유용하게 이용하긴 하지만... 브라우저라는 sandbox 환경에서는 절대 네이티브와 같은 사용자 경험을 제공하지 못한다.

많은 모바일 네이티브 앱들이 브라우저에서 돌아가도록 갈아 탔고, 다시 네이티브로 귀환하는 경우를 가끔 본다. 모바일 브라우저에서 페이스북을 즐기긴 여간 까다롭지만, 페이스북 전용 앱을 사용하면 더 큰 재미를 얻는 느낌과 비유해도 될 것 같다.

아직 필자도 결론을 내릴 만큼 정리되지 않았다. 그리고 이런 추이를 지켜보는 것도 재미있다. 

다만 인터넷 웹 서비스는 네트워크 응답 속도와 체감 속도의 향상이 전부가 아니다. 사용자 경험 측면에서 좋은 성능을 내야 함이 분명한 결론이 될 것이다.

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. muy.kr 2014.04.08 02:11 신고 Address Modify/Delete Reply

    정말 좋은 정보네요.. 잘 보고 갑니다^^

  2. A TearDrop 2014.04.08 03:22 신고 Address Modify/Delete Reply

    잘보고갑니다

  3. 업글 2014.04.08 04:04 Address Modify/Delete Reply

    정말 도움이 많이 되었습니다.
    요즘 추세인 역동적이고 멋진 이펙트들로 느려지는 문제를 제외한다면 요즘 웹은 만들기가 참 편해져갑니다.
    단, 구형브라우저들을 다 버린다는 가정하에 말이지요 ㅋㅋ

  4. 이승근 2014.04.08 12:39 Address Modify/Delete Reply

    AngularJS 의 소개 글은 html은 정적페이지를 위해 최고이지 동적페이지 작성에는 좋지 못하다 따라서 AngularJS를 만들었다 라는 내용인데요.
    정적 페이지가 AngularJS의 best practices라고 말하지 않습니다.

  5. 이승근 2014.04.08 12:58 Address Modify/Delete Reply

    그리고 모든 이벤트 드리븐 기반의 프로그래밍 모델( event loop )에서, 이벤트 핸들러는 event thread에 대해 serialize되어야 합니다.
    이는 모든 UI프로그래밍에서 UI접근은 ui thread(aka main thread/event thread )에서만 수행되어야한다는 제약과 동일합니다. DOM객체를 UI객체로 생각하시면 다른 native 프로그래밍 모델과 크게 다를바는 없습니다.

    그리고 web worker를 제공해서 별도의 thread에서 computing logic을 수행 할 수 있습니다.


    "concurrents 일 수는 있으나 parallels 할 수 없다."
    라는 말은 무슨 의미로 작성하셨는지 이해하기가 어렵네요

    • 땡초 POWERUMC 2014.04.08 17:26 신고 Address Modify/Delete

      읽어 주셔서 고맙습니다.

      '그리고 모든 이벤트 드리븐'은 자바스크립트를 말하시는 건가요?
      이벤트 드리븐이 race condition 하는데, 핸들러가 왜 serialize가 필요한가요?

      그리고 concurrents와 parallels의 의미는 컴퓨터 사이언스의 사전적 의미와 동일합니다.

  6. 이승근 2014.04.08 18:16 Address Modify/Delete Reply

    자바스크립트를 포함 모든 이벤트 드리븐 프로그래밍을 말하였습니다.

    이벤트 드리븐이 race condition이라는 말은 어떤 의미로 하신건지는 모르겠네요,
    race condition은 제가 아는 한에서는,
    같은 자원을 동시에 2개 이상의 thread에서 접근하는 상황인데요,
    이벤트 드리븐 모델에서는 이벤트 자체가 하나의 큐를 통해서 serialize되므로 핸들러간 race condition이 발생하지 않습니다. 그런 의미로, serialize되어야 한다는 말이었구요, 핸들러 안에서 serialize가 필요하다는 말은 아니였습니다.

    그리고, 제가 아는 concurrents는 "동시에 수행 할수 있는"을 의미하고, 자바스크립트의 경우 보통 모두 이벤트 핸들링에 의해서 하나의 thread에 의해서 수행되고, 더구나 DOM이라는 객체 자체가 concurrent한 접근을 허용하지 않기 때문에 concurrent하다고 말하기 어려울듯하네요,

    parallel은 물리적으로 동시에 수행하는 CPU 파이프라인이나,
    물리적으로 여러대의 PC에서 컴퓨팅을 수행하는것에 대해 일컷는 말이라고 알고 있어서, 무엇을 말하려고 하셨는지 잘 이해하기가 어렵습니다.




    • 땡초 POWERUMC 2014.04.08 20:39 신고 Address Modify/Delete

      내용 잘 보았습니다.
      허나 이런 방식으로 논쟁을 계속 해야 할 지 모르겠네요.

      먼저 이벤트 드리븐의 직렬화에 대해서 아래의 링크로 보아도 무방하겠죠?
      https://www.artima.com/weblogs/viewpost.jsp?thread=84958
      같은 메모리 프레임 안에 있는 객체의 포인터 객체를 왜 직렬화 해야 하는지요?
      이벤트는 포인터 함수를 통해 위임을 하고, 이런 방식으로 프로그래밍 하는 것을 이벤트 드리븐으로 알고 있습니다.
      serialize는 네트워크 통신이나 프로세스간, 또는 이기종 간에 데이터를 전송하기 위해 직렬화하는데, 왠 이벤트 드리븐에서 직렬화 얘기가 나오는지 이해가 가지 않네요.
      이것과 관련된 내용이 있으면 링크좀 부탁 드립니다.

      concurrents, 즉 non-blocking을 concurrents로 표현한 것입니다.
      잘못된 비유인가요?

  7. 이승근 2014.04.08 20:47 Address Modify/Delete Reply

    용어 측면에서, synchronization을 썼어야 하는데, serialize를 잘못사용해서 답글을 이해하시는데 혼란을 드린것 같네요.
    결국 event handler는 event thread에 대해 synchronization되며, 이는 모든 event driven기반 프로그래밍 모델에 동일한 사항인데, 자바스크립트의 문제점이라고 하시기에 답글을 달았습니다.

  8. 성현 2014.04.08 20:53 Address Modify/Delete Reply

    잘보구감니다.
    개발당시 요구사항도 요즘은 네이티브처럼 만들어달라는데. 그리하면 정말 검나 느림 ㅡㅡ

  9. Rachel:) 2015.01.22 10:45 신고 Address Modify/Delete Reply

    좋은글 감사합니다! 잘읽고가요~~

필자가 github를 통해서 제공하는 자바스크립트 두 가지 패키지 모두 npm과 관련된 버그가 픽스 되었다.
각각 npm package 버전이 업데이트 되었고, nuget은 금주 중으로 패키지를 재배포 할 예정이다.
또한, Unity 게임 개발 및 Mono 개발에 필요한 MonoDevelop 한국어 버전도 몇 주 전 최신 저장소 코드로 업데이트가 완료 되었다.

Bugs related to npm both packages provided the author through the github has been fixed.
npm is updated each, nuget is a plan to re-distribute the package later in the week.
In addition, the update is complete code of the store also MonoDevelop Korean version a few weeks ago.


MonoDevelop 한국어 버전을 제공하면서 발생하는 (나만 알고 있는..) 한 가지 문제가 있는데, 아직 해결하지 못한 상태이나 곧 업데이트 후 push 예정이다. 벤더가 직접 배포하는 Xamarin Studio를 쓰는 분들은 MonoDevelop 소스 저장소에 머지되기 전에는 해결되지 않을 예정이다.

그리고 azure 클라우드를 통해 호스팅되는 monodevelop-korea.com 사이트가 곧 복구될 예정이다. (생각 없는 클릭 한 방이 사이트를 날려 버린답니다. ㅠㅠ)

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. wlthd 2014.02.21 13:30 Address Modify/Delete Reply

    역시 대단하시네요. 좋은 하루 되세요.

  2. mizix 2014.04.08 16:01 Address Modify/Delete Reply

    monodevelop-korea.com 사이트가 어서 복구되기를....

현재 사용하는 크롬 브라우저 버전은 32.0.1700.77. 이 버전에서 팝업창에서 스크롤바가 비활성화되는 버그가 있다. 이 버그는 윈도우 운영체제에서 발생한다. 필자가 사용하는 맥OS 버전의 크롬에서는 발생하지 않는다.

버그 환경 재연 방법

The Pro Shop 웹 사이트에서 상품 상세 페이지에서 ‘Size Chart’ 링크를 클릭하여 팝업창을 열어 마우스 휠로 스크롤이 잘 되는 것을 확인할 수 있다. 하지만 클릭을 하거나 드래그를 하면 가로/세로 스크롤바가 비활성화된 것처럼 반응하지 않는다. ( 테스트를 하려면 이 링크를 클릭하세요 )


[그림1] Size Chart 링크의 팝업창에서 스크롤바가 비활성화 되어 있음. (활성화 되어야 정상)


[그림2] 스크롤바가 비활성화 된 상태


문제 원인

이 버그에 대해 토론되는 스레드를 통해 답을 얻을 수 있다. 스레드 이슈의 버그 332797 번은 윈도우 운영체제에서 Aura 테마에서 발생한다. Chromium 소스 코드의 Side by Side Diff: ui/events/win/events_win.cc에서 수정이 되었다.


[그림3] 버그의 원인 및 버그 픽스 커밋


[그림4] Chromium Canary 빌드에서 쿠팡 웹사이트 또한 비활성화된 스크롤바가 정상적으로 활성화가 됨


(윈도우 테마를 고전 테마로 변경하면 크롬 브라우저의 버그가 나타나지 않음)

아직 최신 크롬 브라우저에는 반영이 되지 않은 상태이며, Chromium Canary 버전을 사용하면 버그가 수정이 되어있다. 크로미움 카나리어 빌드(Chromium Canary Build) 버전은 기존의 크롬이나 크로미움 브라우저와 다른 폴더에 중복 설치가 가능한 버전이다.

현재 크롬 브라우저 버전에서는 아직 이 버그의 해결 방법은 없다. 따라서 이 문제가 발생한다는 보고를 받았다면 차기 업데이트 버전을 기다려겠다.

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. icar... 2016.05.27 23:48 Address Modify/Delete Reply

    안녕하세요ㅜㅜ 혹시 스마트폰의 크롬앱에도 이렇게 스크롤바 작동하도록 하는 방법은 없을까요?? 크롬어플로 인터넷을 하는데 설정창에서는 스크롤바가 터치로 땡겨지거든요 그런데 블로그같은 인터넷창(웹페이지)에서는 스크롤바 끌어내리기/올리기가 안되고 그냥 터치할 때 보여지기만 해요ㅠㅠ 혹시 이걸 고치고 싶다면 뭘 배워야하나요ㅠㅠ정말 이런 언어?쪽은 문외한인지라...실낱같은 희망 붙들고 몇자 적어 도움을 구해봅니다ㅠㅠ


필자는 최근 자바스크립트(Javascript)를 자주 만지게 되면서 몇 가지 팁 또는 가이드 정보를 공유하고자 한다. 자바스크립트(Javascript)를 좋아하지만 잘 하지는 못한다. 그래서 먼저 개념적으로 잘못된 부분이 있으면 정중하게 미리 양해를 구하고자 한다.

1. 익명의 즉시 실행 함수로 스크립트를 시작하자

익명(Anonymous)의 즉시 실행 함수(Immediately Invoked Function Expression)는 다음의 코드와 같이 정의된다.

(function() {
       // ... 코드 생략 ...  
}());  

익명 함수(Anonymous Function)는 자바스크립트(Javascript)가 런타임(Runtime)에 구문을 해석하여 실행한다. 이는 외부의 접근을 제한함을 의미한다. 그러므로 외부 코드에서 익명 함수의 내부 코드를 임의적이나 악의적으로 수정할 수 없다.

즉시 실행 함수(Immediately Invoked Function Expression)는 선언과 동시에 실행이 된다. 익명 함수가 런타임에 사용될 준비가 되면 즉시 함수의 초기화 코드를 실행할 수 있기 때문이다. 예를 들어, 아래와 같은 코드는 악의적으로 전역 변수의 영향을 받지 않도록 함수(Function) 을 보호할 수 있다.

만약 익명 함수에 정의된 undefined 매개 변수에 진짜 undefined 가 전달되기를 기대하는 경우가 있는데, 즉시 실행 함수(Immediately Invoked Function Expression) 중간에 undefined = true 에 의해 원하는 결과를 얻을 수 없게 된다.

var undefined = true;  

(function(undefined) {
   console.info(undefined);
   console.info(undefined === true);  
})(undefined)  

// 실행 결과  
true  
true  

만약, 외부 코드에 의해 undefined 가 완벽하게 변경되길 바라지 않는 경우 다음과 같이 undefined 가 반환되는 결과를 매개변수로 사용하여 외부 코드에 의한 원치 않는 결과의 충격에서 보호할 수 있게 된다.

var undefined = true;  

(function(undefined) {  

console.info(undefined);  
console.info(undefined === true);  

})( function() {}() );  

// 실행 결과  
undefined  
false  

2. 모듈화 패턴은 한 가지만 사용하라

Javascript 를 모듈화하기 위한 패턴은 여러 가지 방법이 있다. 그런데 여러 패턴을 섞어 사용하다 보면 코드를 보기가 더 난해해 진다. 때문에 필자는 private과 public 접근 제한 방법을 제공하는 모듈 패턴(Module Pattern)을 주로 사용한다. [1]

이 외에도 효과적인 패턴들이 많이 존재하므로 적당한 패턴을 선정하여 모두가 함께 같은 패턴으로 사용하는 것이 현명할 것 같다.

var umc = umc || (function() {

    var privateFunction1 = function() {
        // ... 생략 ...
        return true;
    };

    return {
      "version"   : "3.0.0.0",
      "name"      : "Umc.Core Frameworks",
      "getObject" : function() {
          var result = (privateFunction1() ? "POWERUMC" : "HTTP://BLOG.POWERUMC.KR");
          return result;
      }  
};
})();  

console.info( umc.version );    // 결과 : 3.0.0.0  
console.info( umc.name );      // 결과 : Umc.Core Frameworks  
console.info( umc.getObject() );    // 결과 : POWERUMC     
console.info( umc.privateFunction1() );    // 오류  

[코드1] Self-Contained 모듈화 패턴

var umc = umc || (function() {  

   var _version = "3.0.0.0";
   var _name = "POWERUMC";
   var _getObject = function() { /* 코드 생략 };

   return {
      "version"   : _version,
      "name"      : _name,
      "getObject" : _getObject
   }  
})();  

[코드2] Imports 모듈화 패턴

var umc = umc || (function() {  

   var module = { };

   var _version = "3.0.0.0";
   var _name = "POWERUMC";
   var _getObject = function() { /* 코드 생략 };

   module.version = _version;
   module.name = _name;
   module.getObject = _getObject;

   return module;  
})();  

[코드3] Exports 모듈화 패턴

모듈 패턴(Module Pattern)을 정의하는 방법은 몇 가지가 있다.

  1. Self-Contained
    바로 위의 예시로 제시한 코드가 바로 Self-Contained 인데, public 함수를 직접 구현하는 방법이다.

  2. Imports-mixin
    아래와 같은 코드가 Imports 하는 방법으로 정의하는 모듈 패턴(Module) 패턴이다. 코드는 return 코드 부분만 보면 된다.

    1번과 2번의 경우는 함수가 익명(Anonymous) 함수로 정의 된다.

  3. Exports
    아래와 같은 코드는 module 을 외부로 공개하여 쉽게 확장이 가능하도록 한다.

3. 함수의 매개변수는 맨 먼저 초기화 하라

자바스크립트(Javascript)는 매우 관대하다. ‘오래 꽥꽥(Duck Typing)’은 동적 언어(Dynamic Languages)의 가장 큰 매력이라고 할 수 있다. 혹시라도 강아지가 ‘꽥꽥’ 거리면 자바스크립트는 강아지를 오리로 취급한다.

정의되지 않은 변수나 매개변수(Arguments), 아래의 코드 처럼 write("ERROR"); 와 같이 매개 변수의 개수가 맞지 않아도 너그럽게 실행이 된다. 하지만 코드에 정의되지 않은 undefined에 의해 실행은 얼마든지 오동작이 가능하므로, 가능하면 매개변수는 항상 올바르게 넘겨주지 않는다는 가정하에 작성하는 것이 좋다.

만약, message = message || "-";과 같이 초기화 또는 방어 코드가 없다면 로그는 ''Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : ERROR / undefined 와 같은 결과를 보여준다.

var write = function(category, message) {

    category = category || "INFO";
    message  = message  || "-";

    var date = new Date();;

    console.info( date + " : " + category + " / " + message );  
};

write("INFO", "시작 메시지");  
write("WARN", "경고 메시지");  
write("ERROR");  

// 실행 결과  
Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : INFO / 시작 메시지  
Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : WARN / 경고 메시지  
Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : ERROR / -  

4. 매개변수가 있지만 없어도 동작하도록 해라

함수의 매개변수는 맨 먼저 초기화 하라’ 에서 본 write("ERROR"); 와 같이 매개 변수가 맞지 않아도 잘 동작하도록 방어적인 초기화 코드를 작성하였다.

하지만, write(); 의도적으로 호출을 할 경우 다음의 코드처럼 올바르게 로그 기록이 남지 않게 된다.

write("실행 종료");  

// 실행 결과  
Sun Jun 02 2013 13:14:01 GMT+0900 (KST) : 실행 종료 / -  

category 에 로그 형식이 전달되어야 하는데, 로그 메시지 ‘실행 종료’가 category 항목으로 초기화되어 엉뚱한 결과가 나오게 된다.

이런 경우는 좀 더 매개 변수가 전달되는 가능성을 좀 더 열어두어, 매개 변수의 개수에 따라 매개 변수를 직접 할당하도록 하는 아래의 코드와 같은 방법을 사용하면 된다.

var write = function(category, message) {

    category = category || "INFO";
    message  = message  || "-";

    if( arguments.length === 1 ) {
        message = category;
        category = "INFO";
    }

    var date = new Date();;
    console.info( date + " : " + category + " / " + message );
}  

write("INFO", "실행 시작");  
write("WARN", "실행 중 경고");  
write("실행 종료");  
write();  

// 실행 결과  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : INFO / 실행 시작  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : WARN / 실행 중 경고  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : INFO / 실행 종료  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : INFO / -  

5. 띄어쓰기 스타일(Intent Style)은 반드시 K&R Style 을 사용하자.

K&R 스타일은 전세계의 커뮤니티에 따라 다르지만, C, C++, C#, Java 등의 언어에서 사용된다고 한다. 참고로, 마이크로소프트(Microsoft)가 추천하는 띄어쓰기 스타일은 ‘Allman Style’ 이라고 부른다.

위키피디아(Wikipedia)에 따르면 K&R 스타일은 다음과 같은 유래가 있다고 한다.

The K&R style, so named because it was used in Kernighan and Ritchie’s book The C Programming Language, is commonly used in C. It is also used for C++, C#, and other curly brace programming languages.

K&R 스타일의 이름의 유래는 Kernighan씨와 Ritchie씨의 저술서 The C Programming Language의 C 코드에서 일반적으로 사용했다. 또한 C++, C#, 그리고 중괄호(curly brace)를 사용하는 프로그래밍 언어에서도 K&R 스타일을 사용한다.

자바스크립트(Javascript)는 K&R 스타일의 띄어쓰기 스타일을 사용한다.

필자는 자바스크립트에서 K&R 스타일을 추천하는 것이 아닌, 반드시 K&R 을 쓰는 것이 좋다고 믿는다. 다음의 코드를 보면 왜 K&R 스타일을 사용하는지 알 수 있다.

// K&R 띄어쓰기 스타일  
function getdata\_1() {  
return {
    name: "POWERUMC"  
};
}  

// Allman 뜨어쓰기 스타일  
function getdata\_2()
{  
return
{
    name: "POWERUMC";
}
}  

console.info("getdata_1() - " + getdata_1());  
console.info("getdata_2() - " + getdata_2());  

// 실행 결과  
getdata_1() - [object Object]     // 올바른 결과  
getdata_2() - undefined     // 올바르게 return 되지 않은 결과  

결론

이 외에도 몇 가지 더 있지만, 자바스크립트(Javascript) 내공을 좀 더 쌓은 후에 더 정확하게 쓰는 것이 낫겠다고 생각하여 5개의 팁 정도를 공유했다. 하지만, 예제로 제시한 코드에 대해 성능적인 면이나 익명 함수 또는 즉시 실행 함수 등의 메모리 누수 등에 대해서는 언급하지 않을 예정이다.

내용면으로 부족한 부분이 있겠지만, 이 정도의 팁과 가이드면 바로 현업에서 깔끔하고 잘 동작하는 자바스크립트(Javascript) 코드를 작성하기에는 전혀 문제가 없다고 생각한다.

디자인 패턴(Design Pattern) 부분에서 더 많은 정보를 얻길 원한다면, 필자의 언급한 ‘Learning JavaScript Design Patterns A book by Addy Osmani Volume 1.5.2’ 를 참고하기 바란다.


  1. Module Pattern 참고 : Learning JavaScript Design Patterns
    http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript  ↩


Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 2013.06.24 11:41 Address Modify/Delete Reply

    비밀댓글입니다

  2. 2015.05.22 23:56 Address Modify/Delete Reply

    비밀댓글입니다

    • 땡초 POWERUMC 2015.06.13 21:38 신고 Address Modify/Delete

      함수 안에 매개변수를 선언하는 것이 아닙니다.
      변수에 대입(assign) 하는 것이죠 ^^
      변수는 이미 함수 매개변수에 선언이 되어있으니까요.

  3. 2015.08.07 14:27 Address Modify/Delete Reply

    비밀댓글입니다

  4. 나그네 2017.09.15 13:13 Address Modify/Delete Reply

    [코드3] Exports 모듈화 패턴 에 name 오타가 있네요. 감사합니다