레이블이 javascript인 게시물을 표시합니다. 모든 게시물 표시
레이블이 javascript인 게시물을 표시합니다. 모든 게시물 표시

2014년 8월 11일 월요일

프론트엔드 웹 개발을 위한 자동화 관리 툴: Yeoman, Grunt, Bower

오전 6:54 Posted by jonnung , , , No comments
이미지 출처: http://yeoman.io/learning

최근에 개인적인 스터디 그룹 프로젝트에 Grunt와 Bower를 적용 해봤는데 정말 재밌었고, 나름대로 상당히 만족을 하고 있다.

잘 배워두고 자주 사용하면 기본적인 구조를 잡는 것부터 각종 라이브러리 설치와 의존성 관리, 그리고 각종 빈번한 작업들(소스 코드 합치기, 압축 등등)을 편리하게 수행하고 관리 할 수 있을 것 같다.

이번 포스팅은 Grunt, Bower와 더불어 Yeoman에 대한 간단한 소개와 참고 링크 정도를 남겨 본다.

Grunt

  • 자바스크립트 프로젝트를 위한 테스크 기반의 커맨드 라인 빌드 툴
  • 테스크(task)란 무엇인가?
    작업의 단위라고 생각하면 되겠다.
    js, css, html 같은 static 파일들을 하나로 합치고(concat) 압축을 해서 파일 사이즈를 줄이는(minification) 작업들, 테스트, 배포 등등을 각각 하나의 테스크라고 생각하면 쉽다.
    Grunt는 이런 빈번한 작업들을 사용자가 미리 정의해 놓은대로(Gruntfile.js) 자동으로 빌드해주는 툴이다.
  • Node.js로 만들어져 있다. 따라서 Node.js가 설치 되어 있어야 하고, npm에 등록 되어 있으며 global로 설치 한다.

Bower

  • 프론트엔드 컴포넌트 의존성 관리 툴 이다. 쉽게 말해 위에서 Grunt를 설치하기 위해 사용한 npm과 비슷한 것이다.
  • 예를 들어, 새로운 프로젝트를 시작하거나 진행하던 프로젝트에 bootstrap3을 설치한다고 했을때 bootstrap 웹사이트에 가서 소스코드를 다운 받고, 프로젝트의 적당한 디렉토리에 복사할 것이다.
    하지만 이미 설치 되어 있는 jquery 버전과 bootstrap에 포함된 jquery 버전과 차이에 의한 의존성 관계가 문제 될 수도 있다.
  • bower는 이런 상황에서 각종 컴포넌트들의 설치도 간편하게 해주겠지만, 의존성 부분도 말끔하게 관리해준다.

Yeoman

  • 일단은 스캐폴딩 기능만 사용해 봤기 때문에 웹 어플리케이션의 기본 구조를 쉽고, 편하게 잡아줄 수 있는 도구로 생각하고 있다.
  • Generator 라는 것을 이용해서 개발하려는 프로젝트 종류(webapp, bootstrap, angularjs 등등)에 따라 기본적인 구조를 알아서 잡아준다.
  • 내부적으로 Grunt, Bower를 사용하고 있다.

설치와 사용법 참고 사이트


스터디 그룹 프로젝트에 적용해 보면서 생각 한건데 Python Flask 웹앱을 스캐폴딩 해주는 Yeoman Generator가 있었으면 좋겠다는 생각이 들었다.

그랬는데 역시나 있었다. github에서 2개 정도 찾았는데 한개는 angularjs와 flask 조합 제너레이터(generator-angular-flask) 이고, 나머지 하나(flask-app-generator)는 package.json 도 없고, 기타 등등 없는게 많은지 제대로 동작을 안한다.

바로 python virtual 환경 세팅(virtualenv)랑 flask 설치, 그리고 테스트 웹서버 실행까지 Grunt랑 조합해서 가능할 것 같은 생각이 드는데...

간단하게 하나 만들어 봐야겠다.

2014년 6월 30일 월요일

javascript 상속(Inheritance) - 의사 클래스 방식과 Object.create 메소드 의 연관성

오전 6:08 Posted by jonnung 1 comment
객체지향 프로그래밍에서 상속은 너무나 자연스럽게 다뤄지는 프로그래밍 기법이다.
상속은 코드 재사용의 한 형태이고, 부모 객체의 데이터 타입 체계를 그대로 전달 받기 때문에 개발 비용을 감소 시켜주는 장점이 있다

하지만 일반적인 객체지향 프로그래밍 언어와 다르게 자바스크립트는 클래스(class)가 없다. 상속(Inheritance) 메커니즘을 구현하기 위해서는 자바스크립트의 특징이라고 할 수 있는 프로토타입(prototype)을 기반으로해서 부모 객체를 자식에게 상속 할 수 있다.
이것은 다시 말해 객체가 다른 객체로 바로 상속 된다는 것을 의미 한다.

이번 포스트에서 정리할 내용은 자바스크립트의 상속 패턴중에서 함수의 프로토타입 프로퍼티를 활용한 방식이다.

지난번 javascript 함수 - 함수 객체의 프로토타입 프로퍼티 이해하기 에서 정리한 함수의 프로토타입 프로퍼티(prototype property)을 먼저 살펴보면 좋을 것 같다.

의사 클래스 방식 Pseudoclassical


의사 클래스(Pseudo class, 슈도 클래스라고 읽음)는 가짜 클래스 정도로 이해하자. 사실 이번에 처음 알게된 표현인데 너무 어렵게 생각했던 것 같다.
자바스크립트에서의 의사 클래스 방식은 클래스가 없는 자바스크립트가 클래스를 흉내내기 위해 작성하는 패턴이라고 생각하면 된다.

자바스크립트는 프로토타입적 특성에 맞게 객체에서 다른 객체로 직접 상속하는 방법을 갖기는 하지만 생성자 함수를 통해서 객체를 생성해야하는 조금 혼란스러운 단계가 있다.

좀 더 자세히 설명하자면, 객체의 프로토타입은 해당 객체가 생성 될때 사용한 객체의 원형에 대한 연결을 담고 있기 때문에 이미 생성된 객체의 프로토타입에 다른 객체를 바로 상속할 수는 없다.
다른 객체를 새로운 객체에 상속하기 위해서는 객체가 생성되기 전에 생성자 함수에서 함수객체의 프로토타입 프로퍼티에 객체를 직접 할당하는 식으로 상속을 구현하는 것이다.
(함수 객체의 프로토타입 프로퍼티에는 자신을 통해 생성될 객체가 참조할 객체의 원형을 갖고 있다.)

자, 그럼 이제 자바스크립트의 상속을 구현하기 위해 의사 클래스 방식으로 예제를 작성해보겠다.

다음 코드는 '여자친구가 당분간 연락하지 말자'고 했을때 당분간의 정확한 기간을 계산해주는 객체를 생성한다.

var Love_anger_formula = function () {
    this.__swear_word_constant = 18;  // 욕주율
    this.get_swear_word_constant = function () {
        return this.__swear_word_constant;
    };
};

var do_not_contact = function (contact_stop_time, lie_count) {
    this.contact_stop_time = contact_stop_time;  // 연락 두절 시간
    this.lie_count = lie_count;  // 거짓말 횟수
};

// do_not_contact 함수의 prototype property 객체를 Love_anger_formula 의 인스턴스로 대체한다.
do_not_contact.prototype = new Love_anger_formula();

var how_long = new do_not_contact(24, 2);

// how_long 객체에 새로운 메소드를 추가한다.
// '당분간'의 기간을 계산한 결과를 돌려준다.
how_long.get_remain_period = function () {
    var  swear_word_constant = this.get_swear_word_constant();
    return this.contact_stop_time * this.lie_count * swear_word_constant;
};

console.log(how_long.get_remain_period());
Do_not_contact 라는 생성자 함수를 정의 하고, 이 함수의 prototype을 Love_anger_formula 의 인스턴스로 대체하는 방식으로 의사 클래스 만들어서 객체를 상속했다.

더글라스 크락포드는 이런 의사 클래스 패턴을 객체지향처럼 보이게 고안 됐지만 마치 어디 외계에서 온 패턴과 같다고 말했다.
자바스크립트에 익숙하지 않는 개발자에게 친숙한 방식이 될 수도 있겠지만, 자바스크립트의 장점을 가리게 되는 방법이라는 말도 덧붙였다.

아무튼 이렇게 생성된 객체의 최대의 문제점은 바로 모든 속성들이 public 이라는 것이다. private은 없다.
how_long.__swear_word_constant로 부모 객체의 속성에 바로 접근해서 읽거나 값을 변경할 수 있다.

또한 생성자 함수를 new 연산자로 실행하지 않으면 this는 새로운 객체에 바인딩 되지 않고, 전역 객체(window)에 연결된다. new 연산자를 빼먹어도 어떠한 에러도 발생하지 않기 때문에 매우 심각한 문제가 발생할 수 있다.

이 문제에 대한 해결책(?)으로 더글라스 크락포드가 추천하는 방법은 2가지가 있는데 new 연산자로 실행해서 객체를 생성하는 생성자 함수의 이름은 첫글자를 대문자로 표기하는 것이다.
그리고 나머지 한가지는 new 연산자 사용을 피하는 것이다.

언어의 특징을 비교하는 차원에서 위 예제 코드와 동일한 기능을 하는 파이썬(python) 코드를 작성해 보았다.
LoveAngerFormula 클래스의 __swear_word_constant 변수는 완전 안전한 private 이다.

# -*- coding: utf8 -*-


class LoveAngerFormula():
    __swear_word_constant = 18  # 욕주율

    def get_swear_word_constant(self):
        return self.__swear_word_constant


class DoNotContact(LoveAngerFormula):
    def __init__(self, contact_stop_time, lie_count):
        self.contact_stop_time = contact_stop_time  # 연락 두절 시간
        self.lie_count = lie_count  # 거짓말 횟수
        self.swear_word_constant = self.get_swear_word_constant()

    def get_remain_period(self):
        """
        '당분간 연락하지 말자' 했을때 당분간의 정확한 기간을 계산
        :return: 기간(일)
        :rtype: integer
        """
        return self.contact_stop_time * self.lie_count * self.swear_word_constant


how_long = DoNotContact(24, 2)
print(how_long.get_remain_period())

Object.create() 전달한 객체를 프로토타입으로 새로운 객체를 생성하는 메소드


Object.create() 메소드로 만들어지는 객체는 프로토타입을 직접 지정해서 생성할 수 있는 편리한 기능을 제공한다.
이런게 있는지도 몰랐었는데 이미 표준에 포함되어 있는 메소드 이다!
크롬(Chrome)과 파이어폭스(Firefox)에서는 당연히 제공하고 있었고, IE는 뒤늦게 9부터 지원한다.

Object.create() 메소드가 생기게 된 배경은 new 연산자 사용이 '자바스크립트 스럽지 못하다'는 의견이 나오게 되면서 new 연산자 사용을 자제하기 위해 만들어졌다고 한다.

그런데 이 메소드를 지원하지 않는 브라우저를 위해서 작성하는 코드를 보면 조금 웃긴 사실을 알 수 있다.

if (typeof Object.create !== 'function' ) {
    Object.create = function (obj) {
        function F();
        F.prototype = obj;
        return new F();
    }
}
결국 Object.create()메소드도 내부적으로 F()라는 빈 함수를 만들고, 위에서 살펴본 의사 클래스 방식으로 F 함수의 프로토타입 프로퍼티에 전달받은 객체를 대체한다.
그리고 new 연산자로 생성한 객체를 돌려준다.

new 연산자 사용을 자제하기 위해서 만들어진 메소드는 결국 손바닥으로 하늘을 가리는 꼴이다.

마무으리


자바스크립트의 프로토타입 특징을 활용한 상속에 대해 정리 해봤는데 조금 찝찝한 느낌을 지울 수 없는 것은 사실이다.
하지만 함수의 프로토타입 프로퍼티로 클래스를 흉내내는 의사클래스방식과 Object.create()메소드의 연관성에 대한 부분은 확실히 알고 간다는 것에 매우 만족한다.




2014년 6월 23일 월요일

javascript 함수 - 함수 객체의 프로토타입 프로퍼티 이해하기

오전 8:17 Posted by jonnung No comments
앞으로 몇번에 걸쳐서 자세히 알아볼 부분은 모든 개발 언어에서 굉장히 많이 사용하고, 자바스크립트에서도 핵심이라고 할 수 있는 함수에 대한 부분이다.
그리고 이번 정리에서는 함수 객체와 프로토타입 연결 특성과의 관계에 대해서 중점적으로 알아볼 것이다.

객체의 프로토타입(prototype)


자바스크립트에서 숫자, 문자열, 불리언(true/false), null, undefied를 제외한 모든 값은 객체이다. 생소한 표현이지만 숫자나 문자열, 불리언은 메소드를 갖기 때문에 유사객체라고도 한다. 이 유사객체에 대한 부분은 다음 기회에 좀 더 조사해 볼 것이다.

더글라스 크락포드의 'Javascript The Good Parts'에서는 함수 객체에 대해 설명한 부분에서 프로토타입과 관련해서 설명한 부분을 요약해서 정리하자면 아래와 같다.
프로토타입에 대해 어느정도 알고 있더라도 이것을 보게 되면 상당히 혼란을 일으킬 가능성이 높다.

함수는 객체이다. 객체는 프로토타입 객체(Prototype Obeject)로 숨겨진 연결을 갖는 이름/값 쌍들의 집합이다. 객체 중에서 객체 리터럴로 생성되는 객체는 Object.prototype에 연결 된다.  반면 함수 객체는 Functon.prototype에 연결 된다. Function은 다시 Object.prototype에 연결 된다.  모든 함수 객체는 prototype이라는 속성이 있다. 이 속성의 값은 함수 자신 자체를 값으로 갖는 constructor라는 속성이 있는 객체이다. 이는 Function.prototype으로의 숨겨진 연결과는 다른 의미 이다.
자바스크립트 개발을 해본 경험이 있다면 대부분 프로토타입(Prototype)에 대해서 들어봤을 것이다. 프로토타입은 클래스가 없는 자바스크립트에서 객체지향적인 프로그래밍을 하기 위해서 사용하는 특징이라고 할 수 있다.
좀 더 쉽게 말하자면 상속(Inheritance)을 구현하여 객체가 다른 객체에 속성들을 물려줄 수 있도록 하기 위해 프로토타입을 사용할 수 있는 것이다.

위 인용문의 내용을 살펴보면 크게 객체와 프로토타입과의 관계함수와 프로토타입과의 관계 부분으로 구분되는 것을 알 수 있다.

간단하게 객체를 만들어서 차이점을 확인해 보면 좋을 것 같다.
var func = function () {
    this.one = 'Hello';
    return {
        one: one,
        two: 'world'
    };
};
var obj1 = func();

var obj2 = {
    one: 'Hello',
    tho: 'world'
};

console.dir(obj1);
console.dir(obj2);
위 예제를 실행 결과로 나오는 obj1과 obj2는 완전히 똑같다. 객체 생성 방법에 대한 다른 표현 방식이 있다는 것을 보여주기 위해 똑같은 객체를 생성했을 뿐이지 사실 여기서 중요하게 봐야하는 부분은 console.dir()의 결과로 콘솔에 출력되는 내용이다.


인용문에서 언급된 '객체 리터럴로 생성된 객체는 Object.prototype에 연결된다'는 부분은 위 그림에 나타나있는 __proto__를 말한다.
어렵다. 이렇게 하면 이해하기가 쉽지 않다. 이해를 해야 사용할 수 있고, 누구에게나 설명할 수 있기 때문에 이 개념을 좀 더 명확한 예제로 확인해 볼 필요가 있다.

var Func = function () {
    this.prp = 'Jonnung';
}

var ins = new Func();

console.dir(ins);
이 예제 코드는 new 키워드를 사용해서 객체를 생성할 수 있는 생성자 패턴으로 작성된 함수이다.
생성된 ins라는 객체 내부를 살펴본 모습은 아래와 같다.

ins 객체의 __proto__.constructor를 확인 해보면 Func() 생성자 함수가 들어 있는 것을 알 수 있다. 한마디로 ins 객체는 Func() 라는 생성자 함수를 원형(프로토타입)으로 생성된 객체라고 할 수 있다.
이제 그림이 조금 명확히 보이기 시작하는 느낌이다.
위에서 객체 리터럴로 생성된 객체는 __proto__.constructor 속성에 Object()가 있던 것은 리터럴 표기법으로 생성 된 객체는 리터럴의 특성상 즉시 객체화가 되기 때문에 직접적인 객체의 원형이라고 할 수 있는 대상이 없고, 바로 최상위 원형인 Object이 원형이 되는 것이다.

함수는 객체이다.


객체의 프로토타입에 대해 정리가 끝났다고 프로토타입에 대한 이해가 끝난것은 아니다.
이전 단락의 인용문에서 말하듯 함수도 역시나 객체이다. 이제부터 혼란을 방지하기 위해 함수를 함수 객체로 표현하도록 하겠다.
이번에 살펴볼 내용은 함수객체만이 갖고 있는 프로토타입 프로퍼티(prototype property) 라는 것이다.

위 단락의 두번째 예제의 console.dir()을 객체가 아닌 생성자 함수에 대해 실행해 보도록 하겠다.

var Func = function () {
    this.prp = 'Jonnung';
}

var ins = new Func();

console.dir(Func);

위에서 객체의 내부에 __proto__가 객체의 원형인 프로토타입이라고 했는데 이 함수 객체에는 __proto__도 있고, prototype 이라는 속성도 있는 것을 확인 할 수 있다.

이 prototype property는 함수 객체만이 갖고 있는 속성이다. 그리고 위에서 설명한 객체의 프로토타입과는 의미가 전혀 다르기 때문에 절대로 착각해서는 안된다. 우리가 흔히 상속의 개념으로 생각하는 객체의 원형인 프로토타입은 전 단락에서 설명한 객체가 생성되기 위해 사용한 원형이라는 의미의 프로토타입이 맞다.

그럼 함수 객체만이 갖고 있는 이 prototype property는 무엇인가!
바로 자신을 통해 만들어질 객체들이 원형(프로토타입)으로 사용할 객체 이다.

일단 정의 자체가 다르기 때문에 혼란스러워할 이유는 없다. 그리고 이런 흐름을 증명할 수 있는 증거는 이미 위 코드의 결과에서 확인한 것이나 다름없다. (갑자기 반전스러운 말투)

마무으리


  1. Func() 생성자 함수는 자신을 원형으로 해서 생성될 객체가 참조할 객체를 프로토타입 프로퍼티(prototype property)에 갖고 있다.
  2. Func() 생성자 함수로부터 탄생한 객체 ins는 흔히 프로토타입이라고 하는 자신이 만들어질 때 원형으로 사용한 객체에 대한 연결 정보를 갖고 있다.

참고