골때리는 자바스크립트의 세계 5탄

음.. 슬럼프 상태라서 그런지 머리에서 맴맴거리는군요. 이제 슬슬 매미 올때가 된 것을 알리는 신호인 듯 합니다..응???????????

프로그래머 되면 이렇게됩니다.

어쨌든, 오늘의 골때리는 자바스크립트는 변덕쟁이 장난꾸러기 this 키워드에 대해 알아보겠습니다.

예전에 문제를 하나 냈었죠.

a=0;

function p(){

  (function(){this.a=’b’;a=’c’;})();

  var a=’d’;

  this.a=’e’;

  (function(){var a=this;(function(){a=’f’})();})();

}

p();

음.. 너무나도 미칠것같아서 직접 돌려본 분도 계시겠죠.

아니면 머리로 한번 디버깅을 시도해보신 분도 있겠죠.

결과는 뭐가 나왔죠? a는 ‘e’가 나왔죠.

자 여기서 의문점이 있습니다.

‘e’는 this 키워드 소속인데. 그렇다면 그 키워드는 함수 안에 포함되있을텐데

어째서 상위 a 변수를 건드릴 수 있는건가?

음.. 이런 의문점을 남긴 분도 계실겁니다. 일단 함수를 호출한 부분을 보시면

p();

이겁니다. 최상위 상태에서 p 함수를 호출한 거죠.

그렇다면 최상위 객체는? 당연히 window죠.

이번엔 인라인으로 선언시키고 실행해볼까요?

a=0;

var p=function(){

  (function(){this.a=’b’;a=’c’;})();

  var a=’d’;

  this.a=’e’;

  (function(){var a=this;(function(){a=’f’})();})();

}

p();

이래도 this는 window 객체를 참조하기 때문에 e가 나오는군요.

대체 뭐가 문제입니까? p에게 참조하게 할 수 없습니까?

원인은 바로 호출 문제인 겁니다.

맨 아래 코드를 보시면 p();가 있죠. p를 호출할 때 객체는 참조를 안했습니다. 그러니 자연히 window 객체 아래서 호출하는 것이죠.

즉, 쉽게 말해 이런 환경에서 자스 코딩을 한다고 보시면 무방하겠군요.

with(window){

 //님의 자스코드 주르르르르르르…

}

난 다른 객체를 참조할래 하시면? p에게 객체 소속을 부여시키면 됩니다.

그렇다면 new p(); 이러면 어떨까요?

그렇게 되면은 p의 최상위 객체는 자기 자신으로 할당시키게 됩니다.

그렇게 되면 this가 가리키는건 p가 되겠죠.

그렇게 되면 결과값은? 어이없게도 b가 나옵니다………헐?

그렇다면 첫번째 람다함수에 있는 this가 설마????

this 키워드. 이렇게 변덕이 심합니다. 답이 없어요..ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

하지만 중요한 것은 this 키워드가 어디를 가리키는 건지는 정확히 알아야 한다는 점이죠.

처음부터 어려운 예제를 접해보니 골때리죠? 골 때려도 유분수지..

하지만 이런 골때리는 this 키워드를 손쉽게 접해볼 수 있는 방법이 있습니다.

바로 자신만의 객체를 만드는 연습을 하면 됩니다.

function myobj(){

  this.food=’닭’;

  this.girlfriend=’김태희’;

}

myobj.prototype.gesori=function(){

  alert(this.girlfriend);

}

var a=new myobj();

a.gesori();

a.ge=’baby’;

a.girlfreind=’전지현’;

a.gesori();

프로토타입을 만들다보면 가끔 어이없는일에 부딪히기도 합니다.

동적 객체를 사용할때 setTimeout을 사용해야 할 때도 있고, DOM 객체를 건드려야 할 때도 있습니다. 왜 이 2가지를 대표로 뽑았는지 지금부터 들어갑니다.

function myobj(){

  this.food=’닭’;

  this.girlfriend=’김태희’;

}

myobj.prototype.gesori=function(){

  setTimeout(“alert(this.girlfriend);”,1000);

}

자, 개소리 메서드(..)에 1초 후에 경고창을 뿌리게 해놨습니다.

그리고 종전처럼 실행해봅시다. 에러납니다. girlfriend 변수가 없다는 이유로요.

왜그럴까요?

setTimeout에 첫번째 인자가 들어갈 건 문자열도 있고 함수도 있습니다.

하지만 문자열 따로처리 함수 따로처리 이렇게 하는 건 아닙니다.

setTimeout의 첫번째 인자 처리는 다음과 같습니다.

window.setTimeout=function(func,msec){

    func=new Function(func);

    …그 외에는 네이티브 객체이기 때문에 패스

}

여기서 Function 인스턴스에 들어갈 인자에서 문자열이 들어가도 그 문자열을 파싱해 함수로 만든다는 사실. 물론 function(){어쩌구}도 되고 파싱할 문자열을 넣어도 되고..

그렇다면 어째 eval과 비슷한 역할을 하겠네요? 당연히 다르죠.

eval은 식 자체를 평가하고, function의 문자열은 실행할 코드를 집합시키는 역할을 수행할 뿐이니까요.

근데 문제는 이게 아니죠. this가 가리킨게 대체 뭘 뜻하는건지 원..

그러면 개소리 메서드를 바꿔봅시다.

myobj.prototype.gesori=function(){

  setTimeout(“alert(this.alert(‘?’));”,1000);

}

alert은 window 객체에 있죠? 그래서 실행이 됩니다. 그것도 경고창이 4번씩이나 나오면서요. 물론 alert 메서드는 리턴값이 없기 때문에 첨엔 undefined가 나옵니다.

결국은 이 메소드는 최상위 객체에서 실행하는 꼴이 되는거죠. setTimeout은 숫자가 리턴됩니다. 그게 그냥 숫자는
아니죠. 그 코드를 실행시킬 메모리 주소를 알려주는 역할을 합니다. 그래야 clearTimeout에서 주소를 참조한 다음 그
주소에 있는 네이트브 함수를 삭제해주는 역할을 하죠.

얘기가 왜 자꾸 삼천포로 흘러가는겨?

어쨌든, setTimeout 실행시에 this를 참조하는 곳은 최상위 객체임을 알아주세요.

그래야 메모리 잡고 또다른 방에서 1초후에 경고창이 뜨죠. 근데 해당 객체에 뜨면 안되나 왜이리 불편하게 하는지 이런분도 계실까봐.. 하시는데. 직접 구현해보셈.

그렇다면 해결방안은? 당연히 인터넷에 널리고 널렸으니 직접 찾아보시구요.

DOM 객체를 불러올때. 특히 이벤트를 작성할때 this는 변덕쟁이가 됩니다.

myobj.prototype.gesori=function(){

  domobj.onclick=function(){alert(this.girlfreind);}

}

여기서 DOM 잡아주고 클릭 실행하면? 당연히 안뜹니다.

하아.. 얘 또 어디가나.. 여기서 this는 기본적으로 해당 DOM을 참조하게 됩니다. 그래야 해당 이벤트를 열었을때 자신을 어떻게 할건지 쉽게 구성할 수 있으니까요. 언제 없어지는 변수를 DOM으로 참조하는것보다 낫죠.

이거 해결하는것도 숙제로 남겨두겠습니다.

자, 그렇다면 이제, 함수 안에 있는 this를 최상위객체가 아닌, 원하는 객체에 참조하고 싶다면, this를 길들이고 싶다면 어떻게 하면될까요?

해답은 Function.prototype.call에 있습니다. 뭥미?

그냥 myfunc.call(); 이렇게 쓰는겁니다..

call 메소드의 첫번째 인자는 참조할 컨텍스트라고 하는데 대체 컨텍스트가 뭐냐? 그냥 객체입니다.

사용법은 간단합니다.

a=0;

function p(){

  (function(){this.a=’b’;a=’c’;})();

  var a=’d’;

  this.a=’e’;

  (function(){var a=this;(function(){a=’f’})();})();

}

p.call(p);

new p();대신 p.call(p);를 사용했습니다. 결과는 new p();와 똑같죠.

new는 새로운 인스턴스. 새로운 집을 하나 장만하는 키워드로 this는 p 안이 되겠구요.

p.call(p);는 그냥 p 함수를 실행시키는건데 참조할 객체를 강제로 p로 맞추었기 때문에 this는 p가 되겠습니다.

여기서 a가 왜 b가 되나면 첫번째 람다함수에 참조할 대상이 없기 때문이죠. 물론 참조할 대상이 생기면 좋겠지만 함수란
개념을 이해한다면 빠를겁니다. 구급가방에 반창고 찾는거라 생각하면 쉽겠죠. 일반인이 구급가방에서 반창고 꺼내는거와 의사가
구급가방에서 반창고 꺼내는 개념을 생각하면 되겠습니다.

여기까지 this의 변덕스러움과 그 변덕스러운 this를 길들이는 방법을 간단하게 늘어놓았습니다. 이번에 골때리는 팁은 어려워서 골때리는 팁같군요.

저도 어지럽습니다.

다음 이시간에는 더욱더 골때려서 돌아가시게 만들어드리겠습니다.

License:Public Domain

composite / 2010년 12월 13일 / 미분류

답글 남기기

Your email address will not be published / Required fields are marked *