전역 변수가 JavaScript에서 정의되지 않은 값을 가지고 있다는 사실에 놀랐습니다.


87

오늘 저는 전역 변수가 undefined어떤 경우에 가치 가 있다는 것을보고 완전히 놀랐습니다 .

예:

var value = 10;
function test() {
    //A
    console.log(value);
    var value = 20;

    //B
    console.log(value);
}
test();

출력을 다음과 같이 제공합니다.

undefined
20

여기에서 JavaScript 엔진이 글로벌 가치를 undefined. JavaScript가 해석 언어라는 것을 알고 있습니다. 함수에서 변수를 어떻게 고려할 수 있습니까?

이것이 JavaScript 엔진의 함정입니까?

답변:


175

이 현상을 JavaScript Variable Hoisting이라고 합니다.

어떤 시점에서도 함수의 전역 변수에 액세스하지 않습니다. 당신은 지역 value변수 에만 접근하고 있습니다.

코드는 다음과 같습니다.

var value = 10;

function test() {
    var value;
    console.log(value);

    value = 20;
    console.log(value);
}

test();

아직도 당신이 받고 있다는 게 놀랐 undefined나요?


설명:

이것은 모든 JavaScript 프로그래머가 조만간 부딪히는 것입니다. 간단히 말해, 선언하는 변수는 항상 로컬 클로저의 맨 위에 올려 집니다. 따라서 첫 번째 console.log호출 후 변수를 선언 했더라도 그 전에 선언 한 것처럼 간주됩니다.
그러나 선언 부분 만 게양됩니다. 반면에 할당은 그렇지 않습니다.

따라서 처음을 호출 할 때 console.log(value)아직 할당되지 않은 로컬로 선언 된 변수를 참조하고있었습니다. 따라서 undefined.

여기 또 다른 예는 :

var test = 'start';

function end() {
    test = 'end';
    var test = 'local';
}

end();
alert(test);

이것이 무엇을 경고 할 것이라고 생각하십니까? 아뇨, 그냥 읽지 말고 생각 해보세요. 의 가치는 test무엇입니까?

이외의 다른 말을했다면 start틀린 것입니다. 위의 코드는 다음과 같습니다.

var test = 'start';

function end() {
    var test;
    test = 'end';
    test = 'local';
}

end();
alert(test);

전역 변수가 영향을받지 않도록합니다.

보시다시피, 변수 선언을 어디에 두든 상관없이 항상 로컬 클로저의 맨 위에 올려 집니다.


참고 :

이것은 기능에도 적용됩니다.

다음 코드를 고려하십시오 .

test("Won't work!");

test = function(text) { alert(text); }

참조 오류가 발생합니다.

포착되지 않은 ReferenceError : 테스트가 정의되지 않았습니다.

코드 는 잘 작동하기 때문에 많은 개발자를 방해합니다.

test("Works!");

function test(text) { alert(text); }

그 이유는 명시된 바와 같이 할당 부분이 들어 올려 지지 않았기 때문 입니다. 따라서 첫 번째 예제에서 test("Won't work!")실행 되었을 때 test변수는 이미 선언되었지만 아직 함수가 할당되지 않았습니다.

두 번째 예에서는 변수 할당을 사용하지 않습니다. 오히려, 우리는 적절한 함수 선언 구문, 사용하고있는 않는 완전히 빠진 기능을 얻을 수 있습니다.


Ben Cherry 는 이에 대해 JavaScript Scoping and Hoisting 이라는 제목의 훌륭한 기사를 작성했습니다 .
읽어. 전체 그림을 자세하게 보여줍니다.


27
이것은 좋은 설명입니다. 그러나 함수 내에서 전역 변수에 액세스 할 수있는 솔루션이 그립습니다.
DuKes0mE

1
@ DuKes0mE-항상 함수 내 전역 변수에 액세스 할 수 있습니다.
Joseph Silber 2014

3
예, 왜 시작 게시물의 사례 A가 작동하지 않고 정의되지 않았습니까? 나는 그것이 글로벌 대신 로컬 var로 해석된다는 것을 이해하지만 어떻게 글로벌이 될까요?
DuKes0mE 2014

4
액세스 글로벌 가변적이고 사용 window.value에
벤 카트 레디

1
이 스타일의 가변 호이 스팅은 언제 구현 되었습니까? 이것이 항상 자바 스크립트의 표준 이었습니까?
Dieskim

54

나는 여기에 문제가 설명되어 다소 실망했지만 아무도 해결책을 제안하지 않았습니다. 정의되지 않은 로컬 var를 먼저 만드는 함수없이 함수 범위의 전역 변수에 액세스하려면 var를 다음과 같이 참조하십시오.window.varName


8
예, 이것이 Google 결과의 첫 번째 결과이기 때문에 다른 사람들이 해결책을 제안하지 않았다는 것은 유감입니다. 그들은 거의 실제 질문은 .... JS 엔진의 함정 인에 대한 질문에 대답 않았다 한숨 -> 당신의 대답을 주셔서 감사합니다
user1567453

2
그것이 이론적 지식과 성공의 차이입니다. 답변 해 주셔서 감사합니다!
hansTheFranz

나에게는 어떤 함수에서나 전역 이름을 'var'로 지정하는 것이 실수입니다. 적어도 혼란을 야기합니다. 최악의 경우 Google 검색이 필요합니다. 감사합니다
dcromley

Javascript는 매일 나를 놀라게합니다. 감사합니다. 답변이 도움이되었습니다.
Raf

솔루션에 감사드립니다. 전역 변수가 정의되지 않았지만 Safari에서만 발견되었습니다. 다른 'include'파일과 'google'과 같은 전역 변수가 표시되었으므로 Google에서 사용한 접근 방식을 복사했습니다. window.globalVarFromJS = window.globalVarFromJS || {}; 그런 다음 귀하의 솔루션을 찾았으므로 추가 할 것이라고 생각했습니다.
Ralph Hinkley

10

JavaScript의 변수는 항상 함수 전체 범위를 갖습니다. 함수 중간에 정의되어 있어도 이전에 볼 수 있습니다. 기능 호이 스팅에서도 유사한 현상이 관찰 될 수 있습니다.

즉, 첫 번째 console.log(value)value변수 (외부를 가리는 내부 변수 value)를 보지만 아직 초기화되지 않았습니다. 모든 변수 선언 암시 적 기능 (의 시작 부분으로 이동하는 것처럼 당신은 생각할 수 없는 정의가 같은 장소에 남아있는 동안, 가장 안쪽 코드 블록).

또한보십시오


나는 항상 간단한 단어를 하나 :) 사랑
Jashwant

3

전역 변수 value가 있지만 제어가 test함수에 들어가면 다른 value변수가 선언되어 전역 변수를 숨 깁니다. JavaScript의 변수 선언 ( 할당이 아님)은 선언 된 범위의 맨 위로 올립니다.

//value == undefined (global)
var value = 10;
//value == 10 (global)

function test() {
    //value == undefined (local)
    var value = 20;
    //value == 20 (local)
}
//value == 10 (global)

함수 선언도 마찬가지입니다. 즉, 코드에 정의 된 것처럼 보이기 전에 함수를 호출 할 수 있습니다.

test(); //Call the function before it appears in the source
function test() {
    //Do stuff
}

두 가지를 함수 표현식으로 결합 할 때 변수는 undefined할당이 발생할 때까지 유지되므로 그 때까지 함수를 호출 할 수 없다는 점도 주목할 가치가 있습니다 .

var test = function() {
    //Do stuff
};
test(); //Have to call the function after the assignment

0
  1. 물론 전역 범위뿐만 아니라 외부 변수에 대한 액세스를 유지하는 가장 간단한 방법은 함수에서 동일한 이름으로 다시 선언하지 않는 것입니다. 거기에서 var를 사용하지 마십시오 . 의 사용은 적절한 설명 명명 규칙이 좋습니다. 그것들을 사용하면 과 같은 이름의 변수로 끝나기 어려울 것입니다 (이 측면은 단순성을 위해이 변수 이름이 주어 졌을 수 있으므로 질문의 예제와 반드시 관련이있는 것은 아닙니다).

  2. 함수가 다른 곳에서 재사용 될 수 있으므로 외부 변수가 실제로 해당 새 컨텍스트에서 정의된다는 보장이없는 경우 Eval 함수를 사용할 수 있습니다. 이 작업은 느리므로 성능이 필요한 기능에는 권장되지 않습니다.

    if (typeof variable === "undefined")
    {
        eval("var variable = 'Some value';");
    }
    
  3. 액세스하려는 외부 범위 변수가 명명 된 함수에 정의되어있는 경우 처음에는 함수 자체에 연결된 다음 코드의 어느 곳에서나 액세스 할 수 있습니다 (깊이 중첩 된 함수 또는 외부의 이벤트 처리기에서). 다른 모든 것. 속성에 액세스하는 것이 훨씬 느리고 프로그래밍 방식을 변경해야하므로 실제로 필요한 경우가 아니면 권장하지 않습니다. Variables as properties of functions (JSFiddle) :

    // (the wrapper-binder is only necessary for using variables-properties
    // via "this"instead of the function's name)
    var functionAsImplicitObjectBody = function()
    {
        function someNestedFunction()
        {
            var redefinableVariable = "redefinableVariable's value from someNestedFunction";
            console.log('--> functionAsImplicitObjectBody.variableAsProperty: ', functionAsImplicitObjectBody.variableAsProperty);
            console.log('--> redefinableVariable: ', redefinableVariable);
        }
        var redefinableVariable = "redefinableVariable's value from someFunctionBody";
        console.log('this.variableAsProperty: ', this.variableAsProperty);
        console.log('functionAsImplicitObjectBody.variableAsProperty: ', functionAsImplicitObjectBody.variableAsProperty);
        console.log('redefinableVariable: ', redefinableVariable);
        someNestedFunction();
    },
    functionAsImplicitObject = functionAsImplicitObjectBody.bind(functionAsImplicitObjectBody);
    functionAsImplicitObjectBody.variableAsProperty = "variableAsProperty's value, set at time stamp: " + (new Date()).getTime();
    functionAsImplicitObject();
    
    // (spread-like operator "..." provides passing of any number of arguments to
    // the target internal "func" function in as many steps as necessary)
    var functionAsExplicitObject = function(...arguments)
    {
        var functionAsExplicitObjectBody = {
            variableAsProperty: "variableAsProperty's value",
            func: function(argument1, argument2)
            {
                function someNestedFunction()
                {
                    console.log('--> functionAsExplicitObjectBody.variableAsProperty: ',
                        functionAsExplicitObjectBody.variableAsProperty);
                }
                console.log("argument1: ", argument1);
                console.log("argument2: ", argument2);
                console.log("this.variableAsProperty: ", this.variableAsProperty);
                someNestedFunction();
            }    
        };
        return functionAsExplicitObjectBody.func(...arguments);
    };
    functionAsExplicitObject("argument1's value", "argument2's value");
    

0

전역 변수에서도 동일한 문제가 발생했습니다. 내 문제는 전역 변수가 html 파일 사이에 지속되지 않는다는 것입니다.

<script>
    window.myVar = 'foo';
    window.myVarTwo = 'bar';
</script>
<object type="text/html" data="/myDataSource.html"></object>

로드 된 HTML 파일에서 myVar 및 myVarTwo를 참조하려고했지만 정의되지 않은 오류가 발생했습니다. 긴 이야기 / 하루 짧은, 나는 다음을 사용하여 변수를 참조 할 수 있음을 발견했습니다.

<!DOCTYPE html>
<html lang="en">
    <!! other stuff here !!>
    <script>

        var myHTMLVar = this.parent.myVar

        /* other stuff here */
    </script>
</html>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.