전역 변수가 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.