[Javascript] 함수지향 : 함수의 범위(Scope)

SJ·2022년 8월 20일
0

Javascript

목록 보기
1/13

유효범위(Scope)

유효범위(Scope)는 변수의 수명을 의미한다.

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

함수 밖에서 변수를 선언하면 그 변수는 전역변수가 된다. 전역변수는 에플리케이션 전역에서 접근이 가능한 변수다. 그렇기 때문에 함수 fscope 내에서 vscope를 호출 했을 때 함수 밖에서 선언된 vscope의 값 global이 반환된다.

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

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


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

이 예제의 결과는 모두 local이다. var를 사용하지 않은 지역변수는 전역변수가 된다. 함수 fscope 안에서 vscope를 선언할 때 var를 사용하지 않았기 때문에 지역변수를 생성하는 것이 아닌 전역변수의 값을 local로 변경하게 된 것이다.

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

유효범위의 효용

지역변수

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);
}

본 예제는 무한반복을 발생시킨다. function a에서 i앞에 var를 쓰지 않았기 때문에 a는 for문의 i에 접근해 i의 값을 변경한다. 따라서 i는 계속 0이 되고, 결국 무한반복을 발생시킨다.

전역변수의 사용

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

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());
}())

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

(밑의 방법처럼 사용할 순 있지만 이것도 myappfn이라는 전역변수 안에 함수를 담았기에 전역변수를 1개 이상 사용하고 있다.)

function myappfn(){
    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());
}
myappfn();

유효범위의 대상 (함수)

많은 언어들이 블록(대체로 {,}(중괄호))에 대한 유효범위를 제공하는 것과 다르게 var 변수는 함수에 대한 유효범위만을 제공한다. (함수의 중괄호 안에서 선언된 변수만이 지역변수가 된다.) 그러나 ES6에 추가된 let, const는 블록({,})단위 유효범위를 갖는다. let, const와 다르게 var는 for문, if문 등 안에서 선언된 변수는 지역변수의 의미를 갖지 않는다. 따라서 아래 예제의 alert(name)은 name에 접근가능하기 때문에 'coding everybody'를 출력한다.

  • in javascript
for(var i = 0; i < 1; i++){
    var name = 'coding everybody';
}
alert(name); // coding everybody
  • in java
    자바에서는 아래의 코드는 허용되지 않는다. name은 지역변수로 for 문 안에서 선언 되었는데 이를 for문 밖에서 호출하고 있기 때문이다.
for(int i = 0; i < 10; i++){
    String name = "egoing";
}
System.out.println(name); // undefined

정적 유효범위(Static scoping)

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

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

function b가 실행될 때 첫번째로 b 안에서 지역변수 i가 있는지 찾는다. 그리고 없다면 어떻게 될까? function a 안의 i를 찾는 것이 아닌 더 거슬러 올라가 전역변수 i를 찾아 사용한다. 이는 함수를 호출할 때가 아닌 선언된 시점에서 찾는 것이기 때문에 정적 유효범위(static scoping), 또는 어휘적 유효범위(lexical scoping)라고도 한다. 그렇지 않은걸 동적 유효범위라 한다.


출처 : 생활코딩 - Javascript

0개의 댓글