인터넷정보

자바스크립트 :: 객체 prototype에서 setInterval 문제점

알 수 없는 사용자 2007. 10. 17. 18:07

사용자 삽입 이미지

요즘 prototype이 유행하고 있어서 잠깐 갖고 놀다가 문제점이 발생했습니다.

function KALSOME(id, str) {
    var num = 0;
    var str = str;
    var int = null;
    var obj = document.getElementById(id);

    this.start = function() {
        int = setInterval(this.foo, 500);
    };
    this.end = function() {
        if(int) clearInterval(int);
    };
    this.foo = function() {
        num++;
        obj.value = str + " = " + num;
    };
}

var kalsome_1 = new KALSOME("timer_1","성유리");

-----------------------------------------------------------------------------------------------------------

위에 소스는 잘됩니다. 그래서 prototype으로 확장성을 위해서 다음과 같이
바꿔보았습니다.

KALSOME = function(id, str) {
    this.num = 0;
    this.str = str;
    this.int = null;
    this.obj = document.getElementById(id);
}
KALSOME.prototype.start = function() {
    this.int = setInterval(this.foo,500);
}
KALSOME.prototype.end = function() {
    if(this.int) clearInterval(this.int);
}
KALSOME.prototype.foo = function() {
    this.num++;
    this.obj.value = this.str + " = " + this.num;
}

var kalsome_1 = new KALSOME("timer_1","성유리");

-----------------------------------------------------------------------------------------------------------

이렇게 하니까 foo() 함수가 실행이 안되는것이었습니다.
this.num = NaN 이 되고 this.str = undefined가 되고
this.obj는 개체가 없다고 댕댕거리더군요.

아무래도 수상해서 보니까 setInterval()로 호출된 함수는
KALSOME이 아니고 window 였습니다. ㅡㅡ;
그러니까 setInterval에서 호출될때 foo()죠.. 이것의 instance가
window로 둔갑한다는 겁니다. ㅡㅡ;

그러면 어떻게 하냐.. 무식이 짜장으로 var kalsome_1의 이름을 주냐?..

KALSOME.prototype.start = function() {
    this.int = setInterval("kalsome_1.foo()",500);
}

이렇게 하니까 되기는 되는데, 너무 무식한것 같았습니다. ㅡㅡa
변수의 이름도 넘겨야 하니까요..

그래서 할 수 없이 구글링을 통해서 도움을 받았는데 이 문제 때문에
애 먹는 분이 계실까봐 포스팅 합니다.

먼저 해결방법은 다음과 같습니다.

KALSOME.prototype.start = function() {
    var oInstance = this;
    this.int = setInterval(function(){oInstance.foo()}, 500);
}

현재의 인스턴스가 window로 바뀌는것을 방지하기 위해서 인스턴스를
ANONYMOUS FUNCTION으로 만들어서 넘기는 방법입니다.

하여튼 양키들 대단합니다. ㅡㅡ;;

위에 예제 링크 보시면 쉽게 아실 수 있을겁니다.

양키 사이트 참고하실분은 아래 링크 클릭하세요. ^^

http://www.thescripts.com/forum/thread152277.html

ps. 예제 사이트를 올릴 수 있게 서버를 협찬해 주신 '우하루'님께 감사드립니다.



리플글.......

  공대여자   07-09-20 19:09  
예전에 저거 머리싸고 고민했지만
그냥 함수 하나 만들어서 넘기면 간단하죠.

window.setInterval 이라서
이 안에서 this를 하면 window가 되버리죠.

전에 저거 어떤분이 물어보신것 같은데.... 
 
예전에 저거 머리싸고 고민했지만
그냥 함수 하나 만들어서 넘기면 간단하죠.

window.setInterval 이라서
이 안에서 this를 하면 window가 되버리죠.

전에 저거 어떤분이 물어보신것 같은데....
       
    L   07-09-21 00:37  
아마 제가 물어봤을지도;;
자바스크립트 기본 개념이 없는지라.. 저 문제로 며칠 고민했네요 
 
아마 제가 물어봤을지도;;
자바스크립트 기본 개념이 없는지라.. 저 문제로 며칠 고민했네요
 
   칼솜   07-09-20 19:20  
공대여자님 // 이렇게 하는것 말씀하는건가요?

KALSOME = function() {
    this.index = KALSOME.instances.length;
    KALSOME.instances[this.index] = this;
    ...
}

KALSOME.instances = [];

KALSOME.prototype.start = function() {
    this.int = setInterval('KALSOME.instances['+this.index+'].foo()', 500);

 
공대여자님 // 이렇게 하는것 말씀하는건가요?

KALSOME = function() {
 this.index = KALSOME.instances.length;
 KALSOME.instances[this.index] = this;
 ...
}

KALSOME.instances = [];

KALSOME.prototype.start = function() {
 this.int = setInterval('KALSOME.instances['+this.index+'].foo()', 500);
}
       
   공대여자   07-09-20 20:25  
아뇨 그냥 위 적힌 글과 같은방법을 사용했습니다.
뭐, 이것도 똑같군요. 
 
아뇨 그냥 위 적힌 글과 같은방법을 사용했습니다.
뭐, 이것도 똑같군요.
 
   거친마루   07-09-20 20:27  
함수가 실행될 당시 스코프가 변해버려서 생기는 문제인데..
이럴때를 대비해서 Function.apply 라는게 있군요 : )

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Function:apply

You can assign a different this object when calling an existing function. this refers to the current object, the calling object. With apply, you can write a method once and then inherit it in another object, without having to rewrite the method for the new object.

즉,
this.int = setInterval(this.foo.apply(this),500);
라고 하면 원하는 결과가 되겠네요

아...그나저나, 안녕하세요
오랜만에 로그인 =3=3 
 
함수가 실행될 당시 스코프가 변해버려서 생기는 문제인데..
이럴때를 대비해서 Function.apply 라는게 있군요 : )

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Function:apply

You can assign a different this object when calling an existing function. this refers to the current object, the calling object. With apply, you can write a method once and then inherit it in another object, without having to rewrite the method for the new object.

즉,
this.int = setInterval(this.foo.apply(this),500);
라고 하면 원하는 결과가 되겠네요

아...그나저나, 안녕하세요
오랜만에 로그인 =3=3
 
   칼솜   07-09-20 20:47  
공대여자님, 거친마루님 // 감사합니다. ^^
워... 별 방법이 다 있군요 ㅡㅡ;

ps. 에구.. 거친마루님 // Function.apply 하니까 한번만 실행되고 에러나네요 ㅡㅡ; 
 
공대여자님, 거친마루님 // 감사합니다. ^^
워... 별 방법이 다 있군요 ㅡㅡ;

ps. 에구.. 거친마루님 // Function.apply 하니까 한번만 실행되고 에러나네요 ㅡㅡ;
 
   거친마루   07-09-20 22:28  
앗.. 그런식으로 만든게 있었는데 어딨는지 기억 안나요..
일단 도망 =3 
 
앗.. 그런식으로 만든게 있었는데 어딨는지 기억 안나요..
일단 도망 =3
       
   칼솜   07-09-20 23:06  
그래도 한번이라도 실행되는것이 어딥니까? ^^
도망가지 마셈 ^^ 
 
그래도 한번이라도 실행되는것이 어딥니까? ^^
도망가지 마셈 ^^
 
   Andrew.Ahn   07-09-21 02:25  
http://jibbering.com/faq/faq_notes/closures.html#clSto
참고하시면 도움되실 듯 싶습니다. 
 
http://jibbering.com/faq/faq_notes/closures.html#clSto
참고하시면 도움되실 듯 싶습니다.
       
   칼솜   07-09-21 09:14  
Andrew.Ahn님 // 감사합니다 ^^
일단 ANONYMOUS에서 잘되서 만족합니다만, 좋은 자료네요.
꼭 참고하겠습니다. ^^ 
 
Andrew.Ahn님 // 감사합니다 ^^
일단 ANONYMOUS에서 잘되서 만족합니다만, 좋은 자료네요.
꼭 참고하겠습니다. ^^
 
   찌질찌질   07-09-21 11:46  
전 뭐 복잡한건 모르고 저역시 무식이 짜장으로 만든 소스가있습니다.
<script>
KALSOME = function(id, str) {
    me = this;
    this.num = 0;
    this.str = str;
    this.int = null;
    this.obj = document.getElementById(id);

}
KALSOME.prototype.start = function() {
    this.int = setInterval(this.foo,500);
}
KALSOME.prototype.end = function() {
    if(this.int) clearInterval(this.int);
}
KALSOME.prototype.foo = function() {

    me.num++;
    me.obj.value = me.str + " = " + me.num;

}

var kalsome_1 = new KALSOME("timer_1","성유리");
kalsome_1.start();
</script>


저도 이벤트를 통해 객체?내 함수가 실행되면 this가 변해버리더라구요
그래서 me = this; 하면 해결이 되더라구요 전 이런식으로 해결합니다 
 
전 뭐 복잡한건 모르고 저역시 무식이 짜장으로 만든 소스가있습니다.
<script>
KALSOME = function(id, str) {
    me = this;
    this.num = 0;
    this.str = str;
    this.int = null;
    this.obj = document.getElementById(id);

}
KALSOME.prototype.start = function() {
    this.int = setInterval(this.foo,500);
}
KALSOME.prototype.end = function() {
    if(this.int) clearInterval(this.int);
}
KALSOME.prototype.foo = function() {

    me.num++;
    me.obj.value = me.str + " = " + me.num;

}

var kalsome_1 = new KALSOME("timer_1","성유리");
kalsome_1.start();
</script>


저도 이벤트를 통해 객체?내 함수가 실행되면 this가 변해버리더라구요
그래서 me = this; 하면 해결이 되더라구요 전 이런식으로 해결합니다
       
   칼솜   07-09-21 11:48  
찌질찌질님 // 감사합니다. ^^
me라는 변수를 넣는 독특한 방식이군요. ^^

ps. 점심 먹고 테스트해 보았는데 new로 객체를 2개 받았더니
    무조건 2번째 함수만 실행이 되더군요. me = window.me 변수로
    동작하기 때문이라고 생각됩니다. 멀티로 돌릴 경우 배열로 처리해야
    할것 같습니다. 
 
찌질찌질님 // 감사합니다. ^^
me라는 변수를 넣는 독특한 방식이군요. ^^

ps. 점심 먹고 테스트해 보았는데 new로 객체를 2개 받았더니
     무조건 2번째 함수만 실행이 되더군요. me = window.me 변수로
     동작하기 때문이라고 생각됩니다. 멀티로 돌릴 경우 배열로 처리해야
     할것 같습니다.
            
   찌질찌질   07-09-21 13:34  
헉. 그렇군요. me변수가 칼솜님말씀처럼 window.me변수로 되나보군요. 크응.. 
 
헉. 그렇군요. me변수가 칼솜님말씀처럼 window.me변수로 되나보군요. 크응..
 
   공대여자   07-09-21 13:40  
var this_c = this;

var fn =function(){this_c.xxxx();}

setInterval(fn,1000);

개인적으로 위처럼 사용합니다.

그냥
this_c = this
해버리면
this_c는 전역변수가 되버립니다.
밖에서 this_c = 'x'
해버리면 오류나겠죠. 
 
var this_c = this;

var fn =function(){this_c.xxxx();}

setInterval(fn,1000);

개인적으로 위처럼 사용합니다.

그냥
this_c = this
해버리면
this_c는 전역변수가 되버립니다.
밖에서 this_c = 'x'
해버리면 오류나겠죠.
       
   칼솜   07-09-21 14:53  
공대여자님 // this_c에 this 넣고 function을 미리 함수 만들고
그것을 호출한것이군요. 역시 공대여자님입니다. ^^ (양키보다 우수하십니다)
그렇죠, this_c 하면 window.this_c가 되죠. ^^ 
 
펌:PHPSCHOOL

반응형