JavaScript

유효범위

유효범위(Scope)는 변수의 수명을 의미한다. 아래의 예제를 보자. 결과는 global이다.

var vscope = 'global';
function fscope(){
	alert(vscope);
}
fscope();

함수 밖에서 변수를 선언하면 그 변수는 전역변수가 된다. 전역변수는 에플리케이션 전역에서 접근이 가능한 변수다. 다시 말해서 어떤 함수 안에서도 그 변수에 접근 할 수 있다. 그렇기 때문에 함수 fscope 내에서 vscope를 호출 했을 때 함수 밖에서 선언된 vscope의 값 global이 반환된 것이다. 아래 예제를 보자. 결과는 '함수안 local'과 '함수밖 global'이 출력된다.

var vscope = 'global';
function fscope(){
    var vscope = 'local';
	alert('함수안 '+vscope);
}
fscope();
alert('함수밖 '+vscope);

즉 함수 안에서 변수 vscope을 조회(4행) 했을 때 함수 내에서 선언한 지역변수 vscope(3행)의 값인 local이 사용되었다. 하지만 함수 밖에서 vscope를 호출(7행) 했을 때는 전역변수 vscope(1행)의 값인 global이 사용된 것이다. 즉 지역변수의 유효범위는 함수 안이고, 전역변수의 유효범위는 에플리케이션 전역인데, 같은 이름의 지역변수와 전역변수가 동시에 정의되어 있다면 지역변수가 우선한다는 것을 알 수 있다. 아래 예제를 보자. 결과는 모두 local이다.

var vscope = 'global';
function fscope(){
    vscope = 'local';
    alert('함수안'+vscope);
}
fscope();
alert('함수밖'+vscope);

함수밖에서도 vscope의 값이 local인 이유는 무엇일까? 그것은 함수 fscope의 지역변수를 선언할 때 var를 사용하지 않았기 때문이다. var를 사용하지 않은 지역변수는 전역변수가 된다. 따라서 3행은 전역변수의 값을 local로 변경하게 된 것이다. var을 쓰는 것과 쓰지 않는 것의 차이를 이해해야 한다.

전역변수는 사용하지 않는 것이 좋다. 여러가지 이유로 그 값이 변경될 수 있기 때문이다. 함수 안에서 전역변수를 사용하고 있는데, 누군가에 의해서 전역변수의 값이 달라졌다면 어떻게 될까? 함수의 동작도 달라지게 된다. 이것은 버그의 원인이 된다. 또한 함수를 다른 에플리케이션에 이식하는데도 어려움을 초래한다. 함수의 핵심은 로직의 재활용이라는 점을 상기하자. 변수를 선언할 때는 꼭 var을 붙이는 것을 습관화해야 한다. 전역변수를 사용해야 하는 경우라면 그것을 사용하는 이유를 명확히 알고 있을 때 사용하도록 하자.

유효범위의 효용

아래 두개의 예제는 변수 i를 지역변수로 사용했을 때와 전역변수로 사용했을 때의 차이점을 보여준다. 전역변수는 각기 다른 로직에서 사용하는 같은 이름의 변수값을 변경시켜서 의도하지 않은 문제를 발생시킨다.

지역변수의 사용

function a (){
    var i = 0;
}
for(var i = 0; i < 5; i++){
	a();
	document.write(i);
}

 실행결과

01234

전역변수의 사용

본 예제는 무한반복을 발생시킨다. 
function a (){
    i = 0;
}
for(i = 0; i < 5; i++){
	a();
	document.write(i);
}

전역변수의 사용

불가피하게 전역변수를 사용해야 하는 경우는 하나의 객체를 전역변수로 만들고 객체의 속성으로 변수를 관리하는 방법을 사용한다.

MYAPP = {}
MYAPP.calculator = {
    'left' : null,
	'right' : null
}
MYAPP.coordinate = {
	'left' : null,
	'right' : null	
}

MYAPP.calculator.left = 10;
MYAPP.calculator.right = 20;
function sum(){
	return MYAPP.calculator.left + MYAPP.calculator.right;
}
document.write(sum());

전역변수를 사용하고 싶지 않다면 아래와 같이 익명함수를 호출함으로서 이러한 목적을 달성할 수 있다.

(function(){
    var MYAPP = {}
	MYAPP.calculator = {
		'left' : null,
		'right' : null
	}
	MYAPP.coordinate = {
		'left' : null,
		'right' : null	
	}
	MYAPP.calculator.left = 10;
	MYAPP.calculator.right = 20;
	function sum(){
		return MYAPP.calculator.left + MYAPP.calculator.right;
	}
	document.write(sum());
}())

위와 같은 방법은 자바스크립트에서 로직을 모듈화하는 일반적인 방법이다. 

유효범위의 대상 (함수)

자바스크립트는 함수에 대한 유효범위만을 제공한다. 많은 언어들이 블록(대체로 {,})에 대한 유효범위를 제공하는 것과 다른 점이다. 아래 예제의 결과는 coding everybody이다.

for(var i = 0; i < 1; i++){
    var name = 'coding everybody';
}
alert(name);

자바에서는 아래의 코드는 허용되지 않는다. name은 지역변수로 for 문 안에서 선언 되었는데 이를 for문 밖에서 호출하고 있기 때문이다.

for(int i = 0; i < 10; i++){
	String name = "egoing";
}
System.out.println(name);

자바스크립트의 지역변수는 함수에서만 유효하다.

정적 유효범위

자바스크립트는 함수가 선언된 시점에서의 유효범위를 갖는다. 이러한 유효범위의 방식을 정적 유효범위(static scoping), 혹은 렉시컬(lexical scoping)이라고 한다. 

var i = 5;

function a(){
    var i = 10;
	b();
}

function b(){
	document.write(i);
}

a();

실행 결과는 5이다.

댓글

댓글 본문
작성자
비밀번호
  1. 정요한
    퍼갑니다 . ^^
  2. 김명수
    정적 유효범위! 잘 들었습니다. 감사합니다.
  3. 날고기는람쥐
    var i = 5;
    function a(){
    var i = i;
    document.write(i)
    b();
    }

    function b(){
    document.write(i);
    }
    a();

    전역변수로 지정된 i가 5라는 값을 가지고 있으면서 함수 a 에선 자기 자신 i를 지역변수로 가져버리게 되는데
    거기서 undefiend가 나오게됩니다.

    그리고 함수 b에서 i를 호출했기에 5도 출력이 됩니다.

    즉 두번 출력이 되어버리는것이죠
    실제로 함수 b에서 document.write(i); 를 document write(' a ' + i ) 바꾼다면 결과는 undefined a 5 가 됩니다.

    제 생각이 틀린것이라면 수정 답변을 달아주세요. 저두 정확한 답을 알고 싶네요.
    대화보기
    • 완료!
      완료! 감사합니다.
    • 감사합니다. 정리가 잘 됐습니다.
    • 취준생1
      오 사용될 때 정의될 때 이렇게 생각하니까 쉽군요...
    • yihsang
      감사합니다.
    • kmax95@naver.com
      ㅋㅋㅋㅋ
      대화보기
      • Harry S. Hur
        앵귤러를 공부하기 위해 보고있습니다. 감사합니다.
      • fasdgoc
        자바스크립트는 함수에 대한 유효범위만을 제공한다.
        전역변수는 객체로 묶는다 (익명함수 내부)
        자바스크립트는 함수가 선언된 시점에서의 유효범위를 갖는다.
      • interimlife
        이 아이가 누구의 아이인가!!!!
        여러분, 전역변수가 이러케 무섭슴니다.
      • 이주환
        2016. 04. 24
        유효범위는 정말 중요한 내용입니다.
      • JustStudy
        고맙습니다
      • 삼십대학생
        점점 어려워지는군요. 하... 여기서 거의 포기할뻔 했지만, 약 2주만에 다시 돌아왔습니다. 다시 정신차리고 열심히 하겠습니다. ㅠㅠ 화이팅...
      • 공부합시다
        처음에 MYAPP 이라는 이름의 변수이름을 만들었습니다.
        1. 함수 밖에서 만들었기에 MYAPP 는 전역 변수가 됩니다.
        (참조:1/5 영상 처음에 설명되어 있습니다. 함수 밖에서 변수를 선언하면 그 변수는 전역변수가 된다.)
        2. MYAPP 이라는 전역변수도 싫어 다시 함수(익명) 로 만들었기때문에 더 이상 전역변수가 아닌
        지역 변수가 되었습니다.
        3. 다시 myappfn 변수를 만들고 거기에 익명함수를 객체로 만들었으니
        myappfn은 다시 전역 변수가 된것이죠
        이해가 되셨을까요 ?

        저는 양파를 생각 했습니다. 양파를 생각하시면 어떨까요 ? !
        대화보기
        • basicb
          3번째 동영상에서 'myappfn 이라는 함수의 이름도 사실은 변수 안에 함수가 들어가 있는 것이기 때문에 결국에 myappfn이 전역 변수가 된다' 라는 말이 이해가 안가네요. 혹시 설명 해주실분 계신가요?
        • Byeong Koo Kang
          정적 유효범위가 신박하네요!
        • 질문이용!!
          질문 있습니다.
          MYAPP = {} <------------------------세미콜론 원래 뺴는게 맞나요?
          MYAPP.calculator = {
          'left' : null,
          'right' : null
          }<------------------------세미콜론 원래 뺴는게 맞나요?
          MYAPP.coordinate = {
          'left' : null,
          'right' : null
          }<------------------------세미콜론 원래 뺴는게 맞나요?

          MYAPP.calculator.left = 10;
          MYAPP.calculator.right = 20;
          function sum(){
          return MYAPP.calculator.left + MYAPP.calculator.right;
          }
          document.write(sum());
        • 김경민
          이렇게 클로저를 안써도 함수를 바로 실행하도 되는 방법이 있네요!

          <script>
          var arr = [];
          for(var i = 0 ; i < 5; i++)
          {
          arr[i] = (function() {
          return i;
          }());
          }

          for(var index in arr)
          console.log(arr[index]);
          </script>
        • Kyung Jun Jung
          자답입니다.
          호이스팅 때문에 그렇게 됩니다. ^^
          대화보기
          • Kyung Jun Jung
            좋은 강의 잘 듣고 있습니다.
            하기의 내용이 궁금하여 로그인하게 되네요...

            <script>
            function fn1(){
            alert(x);
            }

            fn1();

            var x = 20;
            </script>

            이건 undefined alert 이 뜹니다.

            <script>
            function fn1(){
            alert(x);
            }

            fn1();

            x = 20;
            </script>

            이건 alert 이 안뜹니다.

            차이는 전역변수 x 의 var 가 있고 없고 인데.. 무슨 이유로 이런 현상이 발생하는지요?

            혹시 아시는 분 알려주세요~~
          • 리치
            scoping 강의 감사합니다.
          • 리치
            scoping 강의 감사합니다.
          • Beluga
            더글라스 크로포드의
            "JavaScript 핵심 가이드"
            대화보기
            • 어디선가... 책 이름 언급한거 같은데... 뭐였죠? ㅠ
            • QuiDam
              일단 개념만 갖고 갑니다. ^^
              매번 감사합니다.
            • Simon Lee
              10~12번째 줄의
              -----함수밖에서도 vscope의 값이 local인 이유는 무엇일까? 그것은 함수 fscope의 지역변수를 선언할 때 var를 사용하지 않았기 때문이다. var를 사용하지 않은 지역변수는 전역변수가 된다. 따라서 3행은 전역변수의 값을 local로 변경하게 된 것이다. var을 쓰는 것과 쓰지 않는 것의 차이를 이해해야 한다-----

              라는 부분은, 함수안에서 var 없이 사용한 vscope는 새로 선언한 지역변수가 아니라, (함수밖에서 선언된 같은이름의)전역변수인 vscope가 사용된 것이다. 라고 설명하는 게 더 자연스럽지 않을까요?
            • 준맹
              좋은 강의 감사합니다. 다음에 와서 또 봐야될 것 같습니다. 저는 아직도 모호한 부분이 있네요:(
            • 우후훗
              아 참고로 처음 생각하셧던 대로 지역변수 i에 전역변수 5를 설정해주시려거든
              var i = i 를 var i = this.i로 수정하시면 됩니다. this는 자바와 동일하게 사용되네요
              대화보기
              • 우후훗
                화질구지님의 대한 답변...이라기엔 너무 늦은거 같지만 어쨋든 다른 궁금한 분이 보실수도 있으므로..
                본문의 강의 내용중에 이런 내용이 있었죠.
                '같은 이름의 지역변수와 전역변수가 있을 경우 지역변수가 우선한다'
                위 내용을 생각하고 화질구지님의 소스를 보면,
                var i = 5; // 전역변수 i, 값은 5

                function a(){
                var i = i; // a라는 함수내부에서 선언되었으니 var i는 지역변수를 선언함이고 그값으로 준 i는 우선순위에 따라 전역변수 i가 아닌 지역변수 i가 되는겁니다. 즉 추측하신것처럼 지역변수의 값이 정의되지 않았으므로 undefined가 됩니다
                document.write(i) //그래서 첫번째 출력결과는 undefined가 나옵니다.
                b();
                }

                function b(){
                document.write(i); //함수 b의 내부에는 i라는 지역변수가 존재하지 않습니다. 고로 출력하는 i는 전역변수 i, 즉 5가 됩니다. 그래서 두번째 출력결과는 5가 되겠습니다.
                }

                a();

                결과적으로 a()의 write(i)는 undefined, b()의 write(i)는 5가 되므로

                출력결과로 undefined5가 나오게 됩니다
              • 이원배
                자바스크립트에서 함수를 선언할때
                function statement 방식과 function expression 방식이 있는데
                (Function() 생성자 함수를 사용한 방법도 있습니다)
                function statement 방식은

                흔히 함수를 선언하는
                function a()
                {
                함수식;
                }

                방식이고

                function expression 방식은
                변수를 선언해서 함수를 대입하는 방식입니다.

                var a = function(){};

                이런씩으로 생성이 되는데

                여기서 또 함수의 접근 범위가 달라집니다.


                a();

                function a()
                {
                alert(1);
                }

                이런씩으로 함수 선언보다 앞에서 함수를 호출하면 호출이 됩니다.
                하지만

                a();

                var a = function()
                {
                alert(1);
                }
                이런씩으로 function expression 방식으로 함수를 선언하게 되면
                함수 호출을 막아줍니다.
                그래서 이런씩으로 함수를 선언하라고 권고 하고 있고요

                이런 현상은 함수 호이스팅 이라고 하는데.

                네..

                그냥 아는척 하고 싶어서요... 뎨헷
              • 강집사
                오호 유효범위...
                자바를 먼저 공부해서 그런진 살작 햇갈리네요..ㅜㅜ
                그래도 한번더 들어보고 개념을 잡고 갑니다.

                감사합니다 ^^
              • document.write
                var i=5; 전역변수 i 값은 5
                function a(){
                var i=i; 지역변수 i 값은 할당되지 않았으므로 undefined i에 undefined 대입
                document.write(i); 지역변수 i undefined 출력
                b();
                }
                이럴것 같은 저 개인적인 생각입니다.
                자바스크립트 콘솔창에서 var i=5; 이렇게 해서 엔터치면 number가 아니라 undefined 가 뜨더라구요 i;이렇게해서 엔터치면 5가 뜨고
                우리가 생각하기에는 5하면 데이터가 숫자라고 알지만 컴퓨터인 자바스크립트는 일단은 테이터형이 undefined 정의되지 않은 값이다. 이렇게 인식하도록 설계가 된듯하네요^^
                대화보기
                • Anna Kim
                  네.

                  일단 var i =i 라고 지정해주었지만 i에게 구체적으로 숫자나 스트링같은 정의된것이 없어서 undefined가 된걸테구요,
                  말씀대로 a 함수안에서 스스로를 참고하고나서 document.write(i) 이 디스플레이해달라고 요구했기때문에 undefined라고 뜨고 나서 b함수가 호출되어 5라고 디스플레이 됬어요. egoing님이 주신 예제또한 a 함수안에서 var i가 정의되어 참고가 된 상태이지만 그 변수에 대한 호출메소드가 없어서(document.write 같은...) 콘솔에 뜨지않은것 뿐이에요.

                  만일 화질구지님의 예제에서
                  a 함수안에서 var i = i; 를 var i = 3; 으로 숫자를 지정해 정의해준다면 결과는
                  35로 뜨게 됩니다. 즉, 함수a 를 처리해서 호출한 후 함수 b를 처리해 불러왔다는 뜻이 되겠네요.

                  결론은 호출메소드가 있느냐없느냐 여부이지 궁극적으로는 함수안의 모든 내용은 다 참고되고 있다는 사실입니다.
                  대화보기
                  • 화질구지
                    너무 잘 보고 있습니다~
                    수업을 듣다가개인적으로 궁금한게 생겨서요.

                    var i = 5;
                    function a(){
                    var i = i;
                    document.write(i)
                    b();
                    }

                    function b(){
                    document.write(i);
                    }
                    a();

                    이런식으로 코드를 작성해봤는데, 답은 'undefined5'으로 나오게 되네요.
                    개인적인 생각으로는 a()에서 i 생성시 전역변수인 5값을 가지고 있는 i가 들어오게 될 것 같았는데 정의되지 않음으로 뜨게되네요. 이 경우는 어떻게 처리되는건지 혹시 알 수 있을까요? a()내부에서 var i를 통해 먼저 i가 생성된 상태이기 때문에 뒤에 =i;에서 자기 스스로를 참고하게 되는건가요?
                  • egoing
                    Var가 없으면 전역함수가 됩니당
                    대화보기
                    • brooklyn
                      제가 잘 짚고 넘어갔는지 잘 모르겠지만.. 혹시 그럼 함수 밖 전역변수는 var를 붙이지 않아도 된다는 거로 이해해도 될까요? (물론...var는 무조건 붙이겠지만... 순수한 호기심에 ^^;;;)
                    • YellowBall
                      잘 들었습니다.
                    • finalx
                      3번 동영상의 익명함수 설명하신 것은 익명함수(anonymous function)만을 말씀하신 게 아니라 익명함수 실행방법인 self-executing anonymous function 혹은 self-executing anonymous function을 같이 설명하신거네요(구글링해본 결과).
                      즉 self-executing anonymous function 이란 익명함수를 function (){.....}; 로 정의하고 익명함수 뒤에 ()를 붙여 정의 즉시 실행하는 것이라는 겁니다. 즉 function () {.....} ();
                      3번 동영상 괄호위치 논란은 (function () {.....} ());인 것인데 전체(self-executing anonymous function) 를 괄호로 한번 더 감싼 것 같습니다. 예를 들면 alert(1); 을 (alert(1));으로 하신 것이라 보면 될 것같습니다.

                      이전 함수 수업내용에선 괄호위치가 달랐는데 정의된 익명함수 범위가 헷갈릴 수 있으니 선언된 익명함수 자체를 괄호로 감싸는 것을 권장한다는 것이고요. 즉, (function () {.....})();
                    • 찐똥구리구리
                      함수가 정의되어도 호출을 해야만 사용할 수 있는 거 아닐까요...
                      대화보기
                      • Quan Lee
                        브라우저는 <script>...</script> 태그 속의 내용을 어떤 방식으로 읽나요? 순서대로 위로부터 아래로 읽는것인가요? 아니면 전체를 로드 마친후에 해석을 시작하나요?
                        前者라면 아래 코드는 실행 될수 없고 console에 b() is not defined라는 에러가 떠야하는 것이 아닐까요?

                        var i = 5;

                        function a(){
                        var i = 10;
                        b();
                        }

                        function b(){
                        document.write(i);
                        }

                        a();
                      • Quan Lee
                        세번째 동영상 예제에서 왜서 맨 밖에 괄호를 제거하면 실행결과가 나오지 않지요?
                        맨 밖에 괄호는 무슨 의미로 쓰는것이지요?

                        (function(){
                        var MYAP ... ...



                        (function(){
                        var MYAPP = {}
                        MYAPP.calculator = {
                        'left' : null,
                        'right' : null
                        }
                        MYAPP.coordinate = {
                        'left' : null,
                        'right' : null
                        }
                        MYAPP.calculator.left = 10;
                        MYAPP.calculator.right = 20;
                        function sum(){
                        return MYAPP.calculator.left + MYAPP.calculator.right;
                        }
                        document.write(sum());
                        }())
                      • 조신부리
                        (function(){
                        ......
                        })();

                        (function(){
                        ......
                        }());

                        둘다 되네요?....js는 역시어려워~~
                      • WebCat
                        저도 님처럼 배워서 크롬 콘솔에서 실행해봤는데 둘 다 작동이 되네요
                        대화보기
                        • WebCat
                          정적 유효범위는 기억할만한 부분이네요..! 잘 들었습니다
                        • 익명함수
                          함수 수업의 함수를 정의하는 다른 방법 강의에선 익명함수 표현을
                          (function(){
                          ......
                          })();
                          이렇게 설명해 주셨는데 유효범위 세번째 강의와는 마지막 괄호 부분이 다른데 어떤게 맞는건가요?
                        • 나무마루
                          굉장히 도움이 많이 되는 내용이었습니다.
                        • 미친고양이
                          기존에 자바나 C의 scope 와는 달라서 혼동스러웠는데
                          덕분에 차이점을 이해하게되었네요 감사합니다 ^^
                        • hehypapa
                          (function(){
                          var egoing = "my teacher";
                          alert(egoing);
                          }())
                        • Daniel
                          지나가다 "날씨"님의 글을 보고 혹시나 도움될까 남깁니다.
                          말씀하신 var vscope = 'global';와 vscope = 'global';의 극명한 차이점은 "최창용"님 말씀처럼
                          delete 연산자로 지워지느냐 아니냐 입니다. delete 연산자는 "프로퍼티"를 지우는 연산자예요.
                          var를 표기한 변수는 delete로도 지워지지 않는 반면, vscope = 'global';의 경우는 지워지죠.
                          이것이 말하는 바는 var를 표기하지 않고 초기화한 것은(vscope = 'global';) window객체의 "프로퍼티"란
                          말과 같아요.

                          var vscope = 'global'; // "전역 변수" - delete로 지워지지 않아요.

                          vscope = 'global'; // window 객체의 "프로퍼티" - delete로 지워져요.

                          * var를 선언하지 않으면, "변수"가 아니라, 전역 객체(window)의 "프로퍼티"
                          대화보기
                          버전 관리
                          egoing
                          현재 버전
                          선택 버전
                          graphittie 자세히 보기