자바스크립트, 스코프란?

잭슨·2023년 11월 29일
0

javascriprt

목록 보기
1/11

스코프란?

var a = "Global Scope";
function a_func(){
    var a = "Function Scope";
    console.log(a); // ?
}
a_func(); 
console.log(a); // ?

위 소스 코드의 실행결과는 무엇이 나올까? 직접 코드를 실행시켜보자.



실행 결과로는 "Function Scope", "Global Scope"가 차례대로 출력된다. 분명 식별자 a에 두가지 값이 들어갔는데 a가 선언된 위치에 따라 다른 값을 출력한다. 이것은 각각의 변수의 스코프가 서로 다르기 때문이다.
스코프란 변수의 유효 범위 즉, 변수를 참조할 수 있는 범위를 의미하며 이러한 스코프는 변수가 "선언"된 위치에 따라 크게 두 가지로 나눌 수 있다.


1) 전역 스코프: 코드 어디서든 참조할 수 있다.
2) 지역 스코프: 해당 변수가 선언된 지역과 그 하위 지역에서만 참조할 수 있다.


변수는 자신이 갖는 스코프에 따라 다른 이름으로 불린다. 전역 스코프를 갖는 변수를 '전역 변수', 지역 스코프를 갖는 변수를 '지역 변수' 라고 한다.
따라서 위 소스코드에서 a_func함수의 밖에서 선언된 a는 '전역변수' 고, 함수 안에 선언된 a는 '지역 변수' 로 서로 스코프가 다르기 때문에 값이 충돌하지 않는다.

만약 스코프라는 개념이 없었더라면 같은 이름의 식별자들끼리 충돌을 일으킬 것이기 때문에 프로그램 전체에서 식별자는 모두 서로 다른 이름으로 사용해야했을 것이다. 파일을 디렉토리로 구분할 수 없다고 생각해보면 쉽게 와닿을 것이다.



함수 스코프? 블록 스코프?

대부분의 언어는 '블록 레벨 스코프(block-level scope)' 를 따르지만 자바스크립트는 '함수 레벨 스코프(function-level scope)' 를 따른다. 예를 들어 C언어의 경우 '블록 레벨 스코프(block-level scope)'를 따르기 때문에 아래 코드처럼 스코프가 블록(중괄호)에 따라 구분되어 있어서 해당 블록 밖에서는 블록 안쪽에 있는 변수를 참조할 수 없다.

// C-language
// block-level scope
int main(void) {
  if (1) {
    int a = 5;
    printf("a = %d\n", a); // a = 5
  }

  printf("a = %d\n", a); // use of undeclared identifier 'a'

  return 0;
}

하지만 자바스크립트는 블록이 아닌 함수에 따라 스코프가 구분되기 블록이 다르더라도 참조가 가능하다.
// Javascript
// function-level scope
function a_func(){
    if(1){
        var a = 5;
        console.log("a = ",a); // a = 5
    }
    console.log("a = ",a) // a = 5 (블록이 서로 다르더라도 참조 가능)
}
a_func();




위에서 자바스크립트는 함수 스코프를 갖는다고 얘기했다. 하지만 그건 사실 과거의 얘기다. 2015년에 도입된 ES6 덕분에 우리는 자바스크립트에서도 블록 스코프를 사용할 수 있다.
변수를 선언할 때 var 키워드 대신 let 또는 const 키워드로 변수를 생성하면 해당 변수는 블록 레벨 스코프를 갖는다.

// Javascript
// block-level scope
function a_func(){
    if(1){
        let a = 5;
        console.log("a = ",a); // a = 5
    }
    console.log("a = ",a) // ReferenceError: a is not defined
}
a_func();



렉시컬 스코프?

아래 코드의 실행 결과를 예측해보자.

var a = 10;

function first() {
  var a = 20;
  second();
}

function second() {
  console.log(a);
}

first(); // ?
second(); // ?

만약 실행 결과가 20, 10 으로 출력될 것이라고 생각했으면 스코프가 "호출"에 따라 결정된다고 생각했을 가능성이 높다. 예를 들면 위 코드가 아래처럼 동작했을 거라고 생각했을 것이다.

var a = 10;

function first() {
  var a = 20;
  (function second() {
    console.log(a);
  })();
}

function second() {
  console.log(a);
}

first(); // 20
second(); // 10

하지만 맨 위에서 말했듯 자바스크립트에서 스코프는 호출 위치가 아니라 "선언된 위치" 에 따라 결정된다. 따라서 실행 결과로는 10, 10이 출력된다. second함수가 first함수 안에서 호출되었다고 하더라도 second함수가 선언된 위치는 전역 스코프이므로 전역 변수인 a를 참조하여 10이 출력되는 것이다.

스코프가 '호출 위치'에 따라 정해지는 것을 '동적 스코프(Dynamic Scope)'라고 하고, '선언 위치'에 따라 정해지는 것을 '렉시컬 스코프(Lexical Scope)'혹은 '정적 스코프(Static Scope)'라고 한다.

자바스크립트에선 렉시컬 스코프를 따르기 때문에 선언 위치에 따라 스코프가 결정된다.




참고 자료

poiemaweb.com

profile
지속적인 성장

0개의 댓글