JavaScript 함수 선언 및 평가 순서
이 예제 중 첫 번째 예제는 작동하지 않지만 다른 모든 예제는 작동하는 이유는 무엇입니까?
// 1 - does not work
(function() {
setTimeout(someFunction1, 10);
var someFunction1 = function() { alert('here1'); };
})();
// 2
(function() {
setTimeout(someFunction2, 10);
function someFunction2() { alert('here2'); }
})();
// 3
(function() {
setTimeout(function() { someFunction3(); }, 10);
var someFunction3 = function() { alert('here3'); };
})();
// 4
(function() {
setTimeout(function() { someFunction4(); }, 10);
function someFunction4() { alert('here4'); }
})();
이것은 범위 문제도 종료 문제도 아닙니다. 문제는 선언 과 표현 사이의 이해에 있습니다.
Netscape의 첫 번째 JavaScript 버전과 Microsoft의 첫 번째 사본조차도 JavaScript 코드는 두 단계로 처리됩니다.
1 단계 : 컴파일-이 단계에서는 코드가 구문 트리 (엔진에 따라 바이트 코드 또는 바이너리)로 컴파일됩니다.
2 단계 : 실행-파싱 된 코드가 해석됩니다.
함수 선언 구문 은 다음과 같습니다.
function name (arguments) {code}
인수는 물론 선택 사항입니다 (코드도 선택 사항이지만 그 요점은 무엇입니까?).
그러나 JavaScript를 사용하면 표현식을 사용하여 함수를 만들 수도 있습니다 . 함수 식의 구문은 식 컨텍스트로 작성된다는 점을 제외하면 함수 선언과 유사합니다. 그리고 표현은 다음과 같습니다.
=
기호 (또는:
객체 리터럴) 오른쪽에있는 모든 것 .- 괄호 안의 모든 것
()
. - 함수에 대한 매개 변수 (실제로 이미 2에서 다룹니다).
선언 과 다른 식은 컴파일 단계가 아닌 실행 단계에서 처리됩니다. 그리고이 때문에 표현의 순서가 중요합니다.
그래서 명확히하기 위해 :
// 1
(function() {
setTimeout(someFunction, 10);
var someFunction = function() { alert('here1'); };
})();
1 단계 : 컴파일. 컴파일러는 변수 someFunction
가 정의되어 있음을 확인하여 생성합니다. 기본적으로 생성 된 모든 변수는 undefined 값을 갖습니다. 컴파일러는 아직 값을 할당 할 수 없습니다. 값은 할당 할 값을 반환하기 위해 일부 코드를 실행하기 위해 인터프리터가 필요할 수 있기 때문입니다. 그리고이 단계에서 우리는 아직 코드를 실행하지 않습니다.
2 단계 : 실행. 인터프리터는 변수 someFunction
를 setTimeout 에 전달하려는 것을 확인합니다 . 그리고 그렇습니다. 불행히도의 현재 값 someFunction
은 정의되지 않았습니다.
// 2
(function() {
setTimeout(someFunction, 10);
function someFunction() { alert('here2'); }
})();
1 단계 : 컴파일. 컴파일러는 someFunction이라는 이름으로 함수를 선언하고 있음을 확인하고이를 생성합니다.
2 단계 : 인터프리터는 사용자 someFunction
가 setTimeout 에 전달할 것을 확인합니다. 그리고 그렇습니다. 의 현재 값은 someFunction
컴파일 된 함수 선언입니다.
// 3
(function() {
setTimeout(function() { someFunction(); }, 10);
var someFunction = function() { alert('here3'); };
})();
Phase 1: compilation. The compiler sees you have declared a variable someFunction
and creates it. As before, its value is undefined.
Phase 2: execution. The interpreter passes an anonymous function to setTimeout to be executed later. In this function it sees you're using the variable someFunction
so it creates a closure to the variable. At this point the value of someFunction
is still undefined. Then it sees you assigning a function to someFunction
. At this point the value of someFunction
is no longer undefined. 1/100th of a second later the setTimeout triggers and the someFunction is called. Since its value is no longer undefined it works.
Case 4 is really another version of case 2 with a bit of case 3 thrown in. At the point someFunction
is passed to setTimeout it already exists due to it being declared.
Additional clarification:
You may wonder why setTimeout(someFunction, 10)
doesn't create a closure between the local copy of someFunction and the one passed to setTimeout. The answer to that is that function arguments in JavaScript are always, always passed by value if they are numbers or strings or by reference for everything else. So setTimeout does not actually get the variable someFunction passed to it (which would have meant a closure being created) but rather only gets the object that someFunction refers to (which in this case is a function). This is the most widely used mechanism in JavaScript for breaking closures (for example in loops).
Javascript's scope is function based, not strictly lexical scoping. that means that
Somefunction1 is defined from the start of the enclosing function, but it's content is undefined until assigned.
in the second example, the assignment is part of the declaration, so it 'moves' to the top.
in the third example, the variable exist when the anonymous inner closure is defined, but it's not used until 10 seconds later, by then the value has been assigned.
fourth example has both of the second and third reasons to work
Because someFunction1
has not yet been assigned at the time the call to setTimeout()
is executed.
someFunction3 may look like a similar case, but since you are passing a function wrapping someFunction3()
to setTimeout()
in this case, the call to someFunction3()
is not evaluated until later.
This sounds like a basic case of following good procedure to stay out of trouble. Declare variables and functions before you use them and declare functions like this:
function name (arguments) {code}
Avoid declaring them with var. This is just sloppy and leads to problems. If you get into the habit of declaring everything before using it, most of your problems will disappear in a big hurry. When declaring variables, I would initialize them with a valid value right away to insure that none of them are undefined. I also tend to include code that checks for valid values of global variables before a function uses them. This is an additional safeguard against errors.
The technical details of how all this works is sort of like the physics of how a hand grenade works when you play with it. My simple advice is to not play with hand grenades in the first place.
Some simple declarations at the beginning of the code might solve most most of these kinds of problems, but some cleanup of the code might still be necessary.
Additional Note:
I ran a few experiments and it seems that if you declare all of your functions in the manner described here, it doesn't really matter what order they are in. If function A uses function B, function B does not have to be declared before function A.
So, declare all of your functions first, your global variables next, and then put your other code last. Follow these rules of thumb and you can't go wrong. It might even be best to put your declarations in the head of the web page and your other code in the body to ensure enforcement of these rules.
참고URL : https://stackoverflow.com/questions/3887408/javascript-function-declaration-and-evaluation-order
'development' 카테고리의 다른 글
Eclipse에서 Maven 저장소를 업데이트하는 방법은 무엇입니까? (0) | 2020.10.09 |
---|---|
Bash 백틱을 올바르게 중첩하는 방법 (0) | 2020.10.09 |
C / C ++에서 포인터 변수를 선언하는 올바른 방법 (0) | 2020.10.09 |
Maven 및 시스템 범위에 JAR 추가 (0) | 2020.10.09 |
파이썬에서 numpy 유형을 식별하는 방법은 무엇입니까? (0) | 2020.10.09 |