자바스크립트의 'this' 키워드 이해하기

자바와 C++ 등을 주로 이용하던  개발자에게 자바스크립트의 this는 마치 '미지의 똥' 같은 느낌입니다. 습관대로 쓰다보면 어느새 질퍽하게 밟아버리곤 하죠. 결국 다시 한번 제대로 이해하기로 하고 웹을 너울거리다가 마침 좋은 자료를 발견하여 주요 액기스를 간추려 올려봅니다.

원본: Understanding the “this” keyword in JavaScript

우선 몇 가지 먼저 기억해 둘 사항들입니다:
  1. 자바스크립트에서 코드는 다음 세 가지 영역에서 수행됩니다: 
    • global 영역 
    • function 영역 
    • eval 영역
  2. this 키워드는 다음 두 가지 조건에 의해 값이 결정됩니다. 
    • 어떤 영역에서 수행되었는가 
    • 호출자가 누구인가 
  3. global 객체에 대해 이해해야 합니다: 
    • 자바스크립트가 구동 될 때에는 언제나 global 객체가 존재합니다. 브라우저에서는 window 객체가 그 역할을 하고 있고, node.js에서는 그냥 global object로 불리는 놈이 하나 있습니다.

자, 이제 this 키워드를 파악하기 위한 4가지 규칙을 살펴봅니다:

  1. 기본적으로 this는 global 객체이다.
    다음 3가지 케이스가 아닌 경우 언제나 global 객체를 가리킵니다.
  2. function 영역에서의 this는 부모 객체이다. 단, 그 부모의 자식으로서 불렸을 때에만. 
    • 이해가 쉬운 예제: increment 메소드 안의 this는 그 부모 객체인 counter를 가리키죠.
      var counter = {
        val: 0,
        increment: function () {
          this.val += 1;
        }
      };
      counter.increment();
      console.log(counter.val); // 1
      counter['increment']();
      console.log(counter.val); // 2
      
      
    • 아리까리한 예제: 하지만, 이 메소드를 counter의 자식으로서가 아니라 직접 호출하면 어떻게 될까요? this는 더 이상 counter가 아니라 global 객체가 됩니다. 
      var inc = counter.increment;
      inc();
      console.log(counter.val); // 2
      console.log(val); // NaN
      
      
  3. new 연산자로 생성된 function 영역의 this는 새로 생성된 객체 그 자신이다. 
    • 이해가 쉬운 예제: 여타의 언어와 비슷한 패턴이라 어렵지 않죠? 
      function F (v) {
        this.val = v;
      }
      var f = new F(“Woohoo!”);
      console.log(f.val); // Woohoo!
      console.log(val); // ReferenceError
      
      
    • 아리까리한 예제: new로 생성하지 않으면 그냥 보통의 함수를 호출하는 것과 다르지 않습니다. 따라서, this는 global 영역입니다. 
      var f = F(“Oops!”);
      console.log(f.val); // undefined
      console.log(val); // Oops!
      
      
  4. call 혹은 apply로 호출 된 함수의 경우 call, apply의 첫번째 인자로 명시 된 객체이다. 
    • 예제:
      var add = function (x, y) {
            this.val = x + y;
          },
          obj = {
            val: 0
          };
      add.apply(obj, [2, 8]);
      console.log(obj.val); // 10
      add.call(obj, 2, 8);
      console.log(obj.val); // 10
      


그 외에, eval 내에서 명시한 this는 조금 머리아픈 구석이 있습니다. 얼마나 최신의 ECMAScript 규약을 따르냐에 따라 브라우저끼리도 서로 다른 동작을 취하기 때문에 이 부분에 대해서는 상세한 참고 자료를 살펴 보실 것을 권장합니다. 원 사이트에서는 “Global eval. What are the options?”라는 문서가 도움이 될거라고 하네요.

제게는 위 문서가 명쾌하게 다가왔는데 여러분은 어떠실지 모르겠습니다.
혹시 제가 잘못 이해하고 있는 부분이 있다면 알려주시기 바랍니다.

SlideShare에서 2014년 히트율 1% 됐네요.



생각지도 못한 재미랄까요.

Slideshare의 제 슬라이드들의 view가 전체 1% 내에 들었네요. 아마 3월에 올린 'svn 능력자를 위한 git 개념 가이드'가 인기 있었던 모양입니다. 그래프를 보니 6월에 어딘가 꽤 영향력 있는 곳에서 소개가 된 모양인지 피크를 쳤네요.

이 알림을 받았을 때 처음 든 생각은, "컨텐츠 플랫폼은 이런 이벤트들을 적극적으로 활용하여 컨텐츠 제공자를 기쁘게 할 수 있어야 한다"였습니다. 사실, 누적된 데이터들을 조금만 적극적으로 활용하면 이런 수치들을 이용한 자동화된 이벤트들을 적극적으로 유치 할 수 있을텐데요.

조금 부끄럽지만 이 뉴스를 제가 직접 페북에 공유하게 만든 건 쉽지 않은 일인데, 이 이벤트는 그걸 해냈어요. ㅎㅎ

다른 도메인의 socket.io 서버 접근 시, XMLHttpRequest 로드가 실패하는 문제

문제 원인을 찾는 데, 꼬박 하루 걸렸습니다.

자초지종을 이야기 하기 전에 간단히 배경 설명을 드리자면,

웹 페이지는 보안 이슈로 인해 로드 된 자신의 것과 다른 도메인의 Ajax 접근에 대해서는 기본적으로 허용하지 않도록 설계되어 있습니다. 이에 대한 표준은 Cross Origin Resource Sharing(CORS)이라는 이름으로 W3C에서 정의해두었는데, 이로 인해 웹 사이트 개발 시에는 이 점이 고려되지 않으면 상당히 큰 제약이 따르게 됩니다. 특히 요즘은 웹 서비스가 다양하게 분화되면서 각각 다른 목적의 서버들이 별개로 동작하는 경우가 많은데 이런 상황에서 CORS 이슈가 해결되지 않으면 메인이 되는 웹 사이트에서 각 서버들로 접속이 되지 않는 난감한 상황이 발생합니다.

웹으로 간단한 채팅 서비스를 만드는데, 웹 페이지에서 기본적인 UI를 제공하고 실제 채팅을 담당하는 서버는 독립적으로 운영되도록 설계하였습니다. 이런 경우 웹 페이지가 로드 된 서버와 다른 도메인으로 채팅 서버가 운영되는 경우, 위에서 이야기 한 CORS의 제약 사항에 걸리게 됩니다. 이를 해결하는 방법은 추가적인 도메인의 서버에서 '이러 이러한 도메인의 접근을 허용해줄게!’라는 선언을 해주는 것입니다.

위와 같은 이슈들은 Cross-Domain 이라는 명칭으로 불리는데 인터넷 검색을 조금만 해봐도 다양한 상황에서 해결하는 방법들이 소개되어 있습니다. 이 글은 이보다 덜 상식적인 이슈를 이야기합니다. socket.io로 네트워크 기능을 구현 시에 이 문제가 발생한다면 어떻게 대처해야 하는가가 이 글의 주제입니다.

결론부터 말씀드리면, socket.io에는 이 이슈와 관련된 open bug가 존재합니다. 버그가 있을거라고는 전혀 생각지도 못한 채 하루를 꼬박 문제 해결을 위해 고생했는데요, 이게 버그였음을 확인한 이상 후에 저처럼 고생하는 분이 없기를 바라는 마음에 글을 남겨둡니다.

오류 메시지는 다음과 같은 구문으로 보여집니다:
XMLHttpRequest cannot load [socket.io 서버]. Origin [웹 서버] is not allowed by Access-Control-Allow-Origin.  

그리고 이 이슈에 대한 해결책은 socket.io의 github 이슈에서 확인 할 수 있었습니다.

 just ran into what I think is the exact same issue and after a lot of code digging, I've found a work around. Long story short, when you tell Socket.io to listen on a port (i.e. not let it default to 80), a default HTTP request handler is created (line 69 of socket.io.js). This default handler automatically writes to and ends the request which prevents the Access-Control-Allow-Origin header from being written to the request by the Manager request handler. The solution I'm using for now is to dynamically remove this default handler in my own code (so not editing any Socket.io code here):

io = io.listen(8888);
io.server.removeListener('request', io.server.listeners('request')[0]);

This works for me. I still think there should be some sort of fix or added option around this though as I don't feel the above to necessarily be stable in the wake of future Socket.io code changes. 

socket.io로 서버를 구동하면 listen을 시작하면서, 기본 HTTP request handler가 만들어지는데, 이 핸들러가 HTTP 헤더에 Access-Control-Allow-Origin 항목을 넣는 것을 막아버리는 것 같네요. 해결 방법은 기본 핸들러를 직접 지워버리는 겁니다. 바로 이 구문이요:

io.server.removeListener('request', io.server.listeners('request')[0]);

이 이슈가 왜 아직까지 해결되지 않은채 유지되는지 모르겠습니다. 어쨌거나 제 하루를 갉아먹은 이 버그가 다른 분들에게는 손쉽게 넘어갈 수 있는 간단한 이슈로 남길 바라는 마음입니다.

iTerm2 터미널 색상 변경하기

맥 용 터미널 앱으로 가장 널리 사용되는 iterm2에서 색상을 변경하는 팁을 소개합니다. 특히, ubuntu에서 보여주는 눈이 덜 피로한 은은한 색상을 선호하는 분들께 도움이 될 것 같습니다.

먼저 github의 mbadolato/iTerm2-Color-Schemes 프로젝트에서 색상 파일들을 내려 받아야 합니다.

링크: https://github.com/mbadolato/iTerm2-Color-Schemes

페이지의 우하단의 Download ZIP을 누르면 이 프로젝트 파일들을 압축 파일 하나로 묶어 내려 받을 수 있습니다. 물론, 프로젝트 파일들을 git으로 상시 업데이트 하고 싶다면 cloning 시켜두는 게 좋겠죠. 하지만, 반드시 그럴 필요는 없을 것 같네요.

받아서 압축을 풀면 내부에 schemes라는 디렉토리가 있고 그 안에 매우 많은 예쁜 색상 파일들이 있습니다.

이제 iTerm2를 실행하고 import를 시켜보겠습니다.

  1. Preferences…/Profiles로 이동합니다. 
  2. 특정 프로필을 선택한 후 Colors 탭으로 이동합니다. 
  3. 하단의 Load Presets…를 클릭한 후, 아랫쪽의 Import…를 선택합니다. 
  4. 아까 보았던 schemes 디렉토리로 이동 후, 원하는 파일들을 체크하여 선택합니다. 전체를 선택 할수도 있습니다. 
  5. 엄청나게 늘어난 목록 중에 자신이 원하는 색상을 고를 수 있습니다.

제 경우에는 ‘Desert’ 색상이 가장 편안한 느낌입니다.

어찌 되었건, 취향에 맞게 선택하시면 되겠습니다!
여러분의 눈은 소중하니까요.


아래는 기본으로 제공되는 설정 들과이 비교 스샷입니다.


(기본) Dark Background

 











(기본) Tango Dark

Desert










리눅스 bash shell에서 git 상태 정보 보기

리눅스 쉘에서 git로 관리되는 프로젝트들을 작업하다보면 각 프로젝트들의 git 상황이 궁금 할 때가 많습니다. 일반적인 해결책이라면 해당 디렉토리로 이동해서 git status 명령을 입력하는 것입니다. 어떤 파일들이 아직 commit 되지 않았는지, 혹은 push 되지 않았는지, stash된 파일들은 없는지 등은 매번 이렇게 까다롭게 각 디렉토리로 이동하여 체크해보아야 합니다.

윈도우에서 svn을 이용할 때를 돌아보면 TortoiseSVN처럼 탐색기에서 아이콘 오버레이로 각 디렉토리의 상황을 수월하게 보여주는 도구들이 있어서 무척 편리했습니다. 그렇다면 리눅스 쉘에서 이를 빠르고 손쉽게 체크 할 수 있는 방법은 없을까 하여 찾아보다가 매우 유용한 방법이 있어서 공유합니다.

bash 쉘에서 프롬프트에 git의 정보를 보여주는 도구입니다. 현재의 브랜치 이름, 원격 저장소와의 차이, 수정된 파일의 개수, 스테이지 된 파일의 개수 등을 보여줍니다.

링크: https://github.com/magicmonty/bash-git-prompt



간단한 설치 방법입니다:
  1. 프로젝트 git repository를 home 디렉토리에서 clone 합니다.
    git clone
    https://github.com/magicmonty/bash-git-prompt.git .bash-git-prompt 
  2. 해당 스크립트를 수행합니다.
    source ~/.bash-git-prompt/gitprompt.sh
     
  3. 다음 로그인 시에 자동 적용을 위해 ~/.bashrc 파일에서 gitprompt.sh를 source 시키는 코드를 추가합니다.
    source ~/.bash-git-prompt/gitprompt.sh

프롬프트에는 다음과 같은 방식으로 정보를 표현합니다:

기본 프롬프트 구조:
  • (<브랜치 이름> <브랜치 상태>|<로컬 상태>)

저장소 정보 심볼:
  •  : 저장소가 깨끗한 상태
  • ●n  :  n개의 파일들이 stage된 상태 (add)
  • ✖n  :  n개의 파일들이 충돌(conflict)이 발생하여 병합(merge)되지 못한 상태 
  • ✚n  :  n개의 파일들이 수정되었으나 stage되지 않은 상태
  • …n  :  n개의 파일들이 track되지 않는 상태 (필요하다면 ignore 시켜야겠죠?)
  • ⚑n  :  n개의 파일들이 stash로 저장 된 상태
  • ↑n  :  n개의 커밋이 존재하고 push를 기다리는 상태
  • ↓n  :  원격 저장소에 n개의 커밋이 푸쉬되었으며, 내 로컬 저장소로 pull을 기다리는 상태


node.js 애플리케이션을 쉽고 빠르게 실행/종료하기

보통 node를 이용해 스크립트를 실행하는 방법은 node 명령어 뒤에 javascript 파일을 적어주는 것입니다.
node sample.js
이런 식으로 node를 사용하다보면 불편한 점이 한 둘이 아니죠. 소스코드가 수정되면 프로세스를 죽였다 살려줘야 하고, 죽일 때에도 node 프로세스를 죽이기 위해 프로세스 id를 찾는 수고로움을 치루어야 합니다. 이에 손쉽게 수정된 소스 코드를 반영하여 재실행하는 방법과 프로세스가 문제가 발생하여 죽더라도 자동으로 재시작 되는 방법, 그리고 스크립트를 빠르게 시작하고 종료하는 방법에 대해 알아봅시다.

  1. nodemon
    nodemon은 node 스크립트가 수정된 것을 감지하여 자동으로 재시작시켜주는 애플리케이션입니다. 한참 개발을 진행 중일때 없어서는 안될 유용한 프로그램이죠.
    • 설치:
      npm install nodemon -g
      -g 옵션을 주어 전역적으로 설치 할 수 있습니다. 이 경우 단일 프로젝트로 제한하지 않고 어느 프로젝트에서나 사용 할 수 있겠죠. sudo로 관리자 권한이 필요 할 수 있습니다.
    • 실행:
      nodemon sample.js
    • 공식 사이트:
      https://github.com/remy/nodemon

  2. forever
    forever는 nodemon에 비해 더욱 다양한 기능을 가지고 있습니다. 노드를 쉽게 실행, 종료 시키고 기본으로 로그 출력을 지원하며, 애플리케이션이 종료될 때에도 자동으로 재시작시켜줍니다.
    • 설치:
      npm install forever -g
    • 사용:
      forever start sample.js
      forever stop sample.js
      forever restart sample.js
      forever list

      이외에도 다양한 명령어가 있습니다만, 이 정도만 알아도 사용하는데 무리가 없을거에요. 이 명령어 조합은 자주 사용하는 것 위주로 쉘 스크립트를 만들어 사용하면 더욱 편리합니다.
    • 공식 사이트:
      https://github.com/nodejitsu/forever

번거롭게 프로세스 kill 시키지 마시고 위 유틸리티들을 적극적으로 사용해보세요!
Powered by Blogger.

Popular Posts