2011-08-06 3 views
1

나는 최근에 자바 스크립트를 배웠다. 나는 그것으로 실험하고 있었다. 이제 간단한 타이머를 만들려고했습니다. <p></p>타이머가 숫자를 증가시키지 않는 이유는 무엇입니까?

<html> 
<head> 
<script type="text/javascript"> 
    function start(obj) 
    { 
     var t = setTimeout("increment(obj)", 1000); 
    } 

    function increment(obj) 
    { 
     obj.innerHTML = parseInt(obj.innerHTML) + 1; 
     start(obj); 
    } 
</script> 
</head> 

<body> 

<p onclick="start(this)">0</p> 

</body> 
</html> 

내용이 매초 1 씩 증가되어야한다 : 다음의 코드이다. 왜 이것이 작동하지 않는지 아는 사람이 있습니까?

+0

'setTimeout'이 아니라'setInterval'이 필요합니다. – FK82

+0

@ fk82 그는 다시 start를 호출하므로 setTimeout은이 시나리오에서는 문제가 없습니다. –

+0

@Gaby : 모호합니다. 코드는 그렇게 할 것입니다. 하지만 실제로는 의도가 "(...)

의 내용이 매초마다 1 씩 증가되어야한다고 생각합니다."':-) 사용자가 매초마다 정확하게 클릭하지 않으면 발생하지 않는 오류가 있습니다. – FK82

답변

2

문제는 (적어도 내가 본 첫 번째) 문자열 "증분 (obj)"을 setTimeout() 메서드로 전달하지만 objstart() 메서드 내에서만 정의됩니다. 전달한 문자열은 시간 제한 트리거가 발생할 때까지 실제로 평가되지 않습니다.이 시점에서 변수는 범위에 없습니다. obj 변수가 범위 내에 있습니다.

이 문제를 해결하는 데는 몇 가지 방법이 있습니다. 하나는 같은 대신 자바 스크립트 문자열의 setTimeout()에 클로저를 전달하는 것입니다 :

function start(obj) { 
    var nextIncrement = function() { 
     increment(obj); 
    }; 
    var t = setTimeout(nextIncrement, 1000); 
} 

또 다른 (덜 바람직하지만) 옵션이 같이 전역에 obj을 촉진하는 것입니다 일반적으로

function start(obj) { 
    window.obj = obj; 
    var t = setTimeout("increment(obj)", 1000); 
} 

그러나 문자열을 setTimeout으로 전달하지 않아야합니다. 또한 불필요하게 전역 범위에 배치하지 않아야합니다. 앞서 보았 듯이 범위 분석에 문제가 발생할 수 있으며 중요한 작업이 아니라면 코드를 훨씬 쉽게 유지 관리 할 수 ​​없게됩니다. 가능한 경우 항상 함수 클로저를 전달하는 것을 선호합니다.

또한, 다음 코드 줄을 probably not doing exactly what you expect입니다 :

parseInt(obj.innerHTML) 

당신은 항상 parseInt에 기수 인수를 제공해야한다, 9입니다 같은 011 같은 값 (보다는 11 오류를 방지 할 때문에 선도자가 0이기 때문에 8 진수로 평가됩니다.

parseInt(obj.innerHTML, 10) 

... 기본 -10 구문 분석을 강제 실행하면 이러한 단점을 피할 수 있습니다. 당신의 obj 객체를 참조하지 않습니다 그래서 당신은 setTimeout에 전달하는 문자열, 글로벌 범위에서 함수 내되지 범위를 평가 http://jsfiddle.net/dSLZG/1

5

때문에, 그리고 :

어쨌든, 여기에 예를 들어 작업.

문자열을 setTimeout으로 전달해서는 안됩니다.

function start(obj) 
{ 
    var t = setTimeout(function() { 
       increment(obj); 
      }, 1000); 
} 

function increment(obj) 
{ 
    obj.innerHTML = parseInt(obj.innerHTML) + 1; 
    start(obj); 
} 

우리가 setTimeout에 전달하는 기능은 그것이 정의되어 범위의 항목에 대한 지속적인 참조가 의미 폐쇄입니다 대신, 그것을 함수 참조를 전달합니다. 잠시 후에 타이머 메카니즘이 그것을 호출 할 때 start 함수가 오랫동안 반환 된 후에도 start 함수의 obj 인수에 여전히 액세스 할 수 있습니다.더 여기서는 Closures are not complicated

1

문제는 코드의 라인이다

var t = setTimeout("increment(obj)", 1000); 

obj는 함수 범위 식별자이다 - 그것은 start 함수 내에서만 접근 할 수있다. 문자열을 setTimeout에 전달하면 전역 범위에서 문자열이 평가됩니다. 즉, obj 변수를 사용할 수 없으므로 아무 것도 증가하지 않습니다. 이것은 폐쇄를 만듭니다로

당신은 대신에 함수 객체를 통과해야하고 변수에 액세스 할 수 있습니다 :

당신은 아무것도 안하고 있기 때문에 나는, 불필요한 var t =을 제거한
function start(obj) 
{ 
    setTimeout(function() { 
     increment(obj); 
    }, 1000); 
} 

주 타이머 식별자.

0

코드를 jsFidle로 복사하고 실제 예제를 추가했습니다. sample code을 참조하십시오. 원래 버전의 문제는 변수 obj가 전역 컨텍스트에 정의되어 있지 않다는 것입니다. 문자열을 setTimeout으로 전달할 때마다 전역 컨텍스트 (obj은 변수가 아님)에서 평가 된 문자열을 갖게됩니다.

대신해야 할 일은 문자열을 setTimeout이 아니라 함수 객체로 전달하는 것입니다. 이 함수 객체는 함수 객체가 정의 된 곳에서 설정된 모든 변수에 대한 참조를 보유합니다.
start2setTimeout에 전달 된 함수 객체가 start2에 정의되어 있기 때문에 모든 변수와 매개 변수 start2에 액세스 할 수 있습니다. 변수 obj은 그 중 하나이므로 setTimeout에 의해 실행되는 즉시 함수 객체 내에서 액세스 할 수 있습니다.

관련 문제