JavaScript로 정의되기 전에 왜 함수를 사용할 수 있습니까?


168

이 코드는 다른 브라우저에서도 항상 작동합니다.

function fooCheck() {
  alert(internalFoo()); // We are using internalFoo() here...

  return internalFoo(); // And here, even though it has not been defined...

  function internalFoo() { return true; } //...until here!
}

fooCheck();

그래도 왜 작동 해야하는지에 대한 단일 참조를 찾을 수 없었습니다. 나는 John Resig의 발표 노트에서 이것을 처음 보았다. 그러나 그것은 단지 언급되었다. 그 문제에 대한 설명이 없습니다.

누군가 제발 깨달을 수 있을까요?


3
최신 버전의 파이어 폭스에서는 코드가 try / catch에 있으면 작동하지 않습니다. 이 바이올린을보십시오 : jsfiddle.net/qzzc1evt
Joshua Smith

답변:


217

function선언은 마법과 그 식별자가 * 실행되는 해당 코드 블록에서 아무것도하기 전에 구속됩니다.

이는 function일반적인 하향식 순서로 평가되는 표현식 을 사용한 할당과 다릅니다 .

예제를 다음과 같이 변경 한 경우 :

var internalFoo = function() { return true; };

작동을 멈출 것입니다.

함수 선언은 거의 동일하게 보이고 일부 경우 모호 할 수 있지만 구문 적으로 함수 표현식과는 상당히 분리되어 있습니다.

이것은 ECMAScript 표준 , 10.1.3 장에 설명되어 있습니다. 불행히도 ECMA-262는 표준 표준에서도 읽을 수있는 문서가 아닙니다!

* : 포함 함수, 블록, 모듈 또는 스크립트.


나는 그것이 실제로 읽을 수없는 것 같아요. 나는 당신이 10.1.3을 지적한 부분을 읽었으며 거기에있는 조항들이 왜 이런 행동을 야기하는지 이해하지 못했다. 정보 주셔서 감사합니다.
Edu Felipe

2
@bobince 좋아, 나는이 페이지에서“게양”이라는 용어에 대한 언급을 찾을 수 없을 때 스스로 의심하기 시작했다. 희망이 코멘트 : 바로 설정 것을 충분히 구글 주스를 ™이
마티아스 Bynens

2
인기있는 질문 / 답변 콤보입니다. ES5 주석 사양에 대한 링크 / 발췌로 업데이트하는 것을 고려하십시오. (좀 더 접근하기

1
이 기사에는 몇 가지 예가 있습니다. JavaScript 범위 지정 및
게양

정의하기 전에 함수를 사용하는 라이브러리가 상당히 많았습니다. 일부 언어조차도 공식적으로 허용합니다. 하스켈. 솔직히 말해서 이것은 나쁜 표현이 아닐 수도 있습니다. 어떤 경우에는 좀 더 표현할 수 있기 때문입니다.
windmaomao

28

이를 HOISTING-정의하기 전에 함수 호출 (호출)이라고합니다.

내가 쓰고 싶은 두 가지 다른 유형의 함수는 다음과 같습니다.

식 함수 및 선언 함수

  1. 표현 함수 :

    함수 표현식은 변수에 저장 될 수 있으므로 함수 이름이 필요하지 않습니다. 또한 익명 함수 (이름이없는 함수)로 이름이 지정됩니다.

    이러한 함수를 호출 (호출)하려면 항상 변수 이름이 필요합니다 . 이러한 종류의 기능은 정의되기 전에 호출되면 작동하지 않습니다. 즉, 여기에서 호이 스팅이 발생하지 않음을 의미합니다. 항상 표현식 함수를 먼저 정의한 다음 호출해야합니다.

    let lastName = function (family) {
     console.log("My last name is " + family);
    };
    let x = lastName("Lopez");

    이것이 ECMAScript 6에서 작성하는 방법입니다.

    lastName = (family) => console.log("My last name is " + family);
    
    x = lastName("Lopez");
  2. 선언 함수 :

    다음 구문으로 선언 된 함수는 즉시 실행되지 않습니다. 그것들은 "나중에 사용하기 위해 저장"되며, 호출 될 때 나중에 실행될 것입니다. 이 유형의 함수는 정의 된 위치 이전 또는 이후에 호출하면 작동합니다. 정의되기 전에 선언 함수를 호출하면 게양이 제대로 작동합니다.

    function Name(name) {
      console.log("My cat's name is " + name);
    }
    Name("Chloe");

    게양 예 :

    Name("Chloe");
    function Name(name) {
       console.log("My cat's name is " + name);
    }

let fun = theFunction; fun(); function theFunction() {}작동 할 것입니다 (노드 및 브라우저)
Fider

14

브라우저는 HTML을 처음부터 끝까지 읽고 실행 가능한 청크 (변수 선언, 함수 정의 등)로 읽고 구문 분석 할 때 HTML을 실행할 수 있습니다. 그러나 어느 시점에서나 그 시점 이전에 스크립트에 정의 된 내용 만 사용할 수 있습니다.

이것은 모든 소스 코드를 처리 (컴파일)하는 다른 프로그래밍 컨텍스트와 다릅니다. 아마도 참조를 해결하는 데 필요한 라이브러리와 함께 링크하고 실행이 시작되는 실행 모듈을 구성하십시오.

코드는 추가로 정의 된 명명 된 객체 (변수, 기타 함수 등)를 참조 할 수 있지만 모든 부분을 사용할 수있을 때까지 참조 코드를 실행할 수 없습니다.

JavaScript에 익숙해지면서 올바른 순서로 물건을 작성해야한다는 사실을 친숙하게 알게됩니다.

수정 : 위의 답변을 확인하려면 Firebug를 사용하여 웹 페이지의 스크립트 섹션을 단계별로 진행하십시오. 실제로 코드를 실행하기 전에 첫 번째 줄만 방문하여 함수에서 함수로 건너 뜁니다.


3

일부 언어의 경우 사용하기 전에 식별자를 정의해야합니다. 그 이유는 컴파일러가 소스 코드에서 단일 패스를 사용하기 때문입니다.

그러나 여러 패스가 있거나 일부 수표가 연기 된 경우 해당 요구 사항 없이도 완벽하게 살 수 있습니다. 이 경우 코드를 먼저 읽고 해석 한 다음 링크를 설정합니다.


2

JavaScript 만 조금 사용했습니다. 이것이 도움이 될지 확실하지 않지만, 그것은 당신이 말하고있는 것과 매우 유사하며 통찰력을 줄 수 있습니다.

http://www.dustindiaz.com/javascript-function-declaration-ambiguity/


링크가 더 이상 죽지 않았습니다.
mwclarke

1
연결이 끊어졌습니다.
Jerome Indefenzo

다음 은 archive.org 의 스냅 샷 입니다. 이 블로그 게시물이 해당 범주에 속하지 않고 저자 오래된 콘텐츠를 가지고 전체 웹 사이트를 중단 한 것처럼 보입니다 .
jkmartindale

1

함수 "internalFoo"의 본문은 구문 분석시 어딘가로 이동해야하므로 JS 인터프리터가 코드를 읽을 때 (일명 구문 분석) 함수의 데이터 구조가 작성되고 이름이 지정됩니다.

나중에 코드가 실행 된 후에야 JavaScript는 실제로 "internalFoo"가 존재하는지와 그것이 무엇인지, 그리고 호출 될 수 있는지 여부를 알아냅니다.


-4

같은 이유로 다음은 항상 foo전역 네임 스페이스에 배치 됩니다.

if (test condition) {
    var foo;
}

8
사실, 그것은 매우 다른 이유입니다. if얼마 블록은 범위를 만들지 않습니다 function()블록은 항상 하나를 만듭니다. 실제 이유는 전역 자바 스크립트 이름의 정의가 컴파일 단계에서 발생하므로 코드가 실행되지 않더라도 이름이 정의 되었기 때문입니다. (죄송하기까지 시간이 오래 걸렸습니다)
Edu Felipe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.