JavaScript

스코프

코구리 2022. 10. 18. 23:59

1. 스코프란?

스코프(scope)는 식별자의 유효범위라고 할 수 있다. 모든 식별자는 사실 어디서나 참조할 수 있는 것이 아니다. 호출할 수 있는 범위가 따로 있다. 이렇게만 말하면 감이 잘 안올테니 예시코드를 살펴보도록 하겠다. 

var data=10;


function my_Data(){

var data=1;

console.log(data); //1

}

my_Data();
console.log(data); //10

위 코드에서는 함수없이 그냥 선언한 변수 data는 1로 출력되고 함수 안에서 선언한 변수 data는 10으로 출력이 되는 것을 확인할 수 있다. 함수 내의 변수는 함수 안에서만 사용이 가능하기 때문이다.

하지만 함수 밖에서 쓰인 변수는 어디서든지 사용이 가능하다. 함수 안에 같은이름의 변수가 선언되어있지 않다면 함수안에서도 사용할 수 있다. 함수 밖에서 쓰인 var data=10 과 함수 내에서 쓰인 var data=1 은 동일한 식별자를 가졌지만 다른 스코프에서 쓰인 다른 변수이다.

 

한마디로 같은 스코프 내에서는 같은 식별자를 사용할 수 없다. 그 말은 다른 스코프에서는 같은 식별자를 사용해도 된다는 말이기도 하다.<모던 자바스크립트 딥다이브>에 와닿는 비유가 있었다. 우리가 pc에서 파일을 생성할 때 같은 파일명을 사용할 수 없지만 폴더를 생성하고 다른 폴더끼리는 파일명이 겹쳐도 상관없다. 제일 상위 디렉토리를 전역스코프로, 폴더는 지역스코프로 생각하면 편할 것 같다. 실제로 스코프는 네임스페이스라는 공간이다. 전역, 지역 스코프에 대해서는 지금부터 자세히 다루도록 하겠다.

2. 전역 스코프

전역은 함수 밖에 해당되는 공간이다. 전역 스코프는 코드 전체에서 유효하다. 이 전역에서 선언된 변수를 전역변수라고 하며 코드 내에서 어디든지 유효한 변수이다.

var data=10;

function my_Data(){
    console.log(data);
}

my_Data(); //10
console.log(data); //10

이렇게 작성을 해도 아무런 에러 없이 출력이 된다. 전역변수는 함수 내에서도 사용이 가능하기 때문이다.

 

3. 지역 스코프

지역은 함수 내에 해당되는 공간이다. 지역 스코프는 함수 내에서만 유효하다. 지역에서 선언된 변수를 지역변수라고 하며 함수내에서만 유효한 변수이다.

스코프는 계층적으로 연결되어있다. 전역 스코프 안에 지역스코프가 들어간다. 하나의 함수 안에 또 함수가 중첩되어 있다면 또 그 안에 새로운 지역 스코프가 생성된다. 식별자가 호출되면 해당 식별자가 호출된 스코프부터 계층적으로 검색해나간다. 이것을 스코프체인이라고 한다.

이런 특징 때문에 상위 스코프에서 유효한 변수를 하위 스코프에서 참조하는 것은 가능하지만 , 하위 스코프에서 유효한 변수를 상위 스코프를 참조하는 것은 당연히 불가하다.

3.1. 함수레벨 스코프

var 키워드를 사용한 변수는 함수 안에서만 지역스코프를 갖고 그외에 다른 코드블럭(for, while, if문 등)에서 전역스코프를 따른다.

var num=70;

for (var i=0;i<5;i++){
console.log(i);
var num=100;
}

console.log(num); //100

여기서 마지막줄은 100이 출력된다. for문이 전역스코프를 따르고 있기 때문에 for문 안에서 선언된 num 변수는 전역변수이다. 따라서 num값이 100으로 재할당된 것이다.

참고로 var은 변수의 중복선언을 허용한다. 따라서 이미 선언된 변수에 대해서 초기화문으로 재선언하면 var 키워드가 없는 것처럼 작동하여 값이 재할당되고 그냥 선언만 하면 무시된다.

다른 키워드(let, const)의 경우 중복선언을 허용하지 않기 때문에 위 코드와 같이 작성하면 에러가 발생한다.

이렇게 값이 예기치 못하게 변경될 우려가 있으므로 var키워드는 사용하지 않는 것이 좋다. 자세한 내용은 키워드 간의 차이 게시물을 보면 된다.

3.2. 블록 레벨 스코프

let, const 키워드는 블록레벨 스코프를 지원한다. 이 말은 함수가 아닌 다른 코드블럭(for,while,if 문 등)에서도 지역스코프가 적용된다는 의미이다.

let num=70;

for (var i=0;i<5;i++){
console.log(i);
let num=100;
}

console.log(num); //70

같은 코드를 변수키워드만 let으로 변경해서 작성하면 맨 아랫줄 코드 결과는 100이 아니라 70이다. 이것은 for문이 블록레벨스코프로, 지역스코프가 적용이 되어서 전역 변수 num과는 다른 변수로 선언된 것이다. 그래서 마지막줄에서는 전역에서 변수를 검색하게 되므로 전역변수인 70을 출력하는 것이다.

 

4. 렉시컬 스코프

렉시컬 스코프란 함수의 호출이 아닌 정의하는 시점에서 스코프가 결정되는 것을 말한다.

var num=10;

function foo(){
var num=20;
bob();
}

function bob(){
console.log(num);
}

foo(); //10
bob(); //10

위 코드를 보면 foo 함수 내에서 bob함수를 호출하고 있다. foo 함수를 실행했을 때 bob이 함수 내에 있기 때문에 지역스코프를 따르는 것 아닌가? 라고 생각할 수 있다. 하지만 렉시컬 스코프를 따르기 때문에 함수가 어디서 선언되었는지가 중요하다. bob함수는 전역에서 선언되었다. 따라서 전역스코프를 따르며 foo() 와 bob() 실행결과는 모두 전역변수 num의 값 10을 출력하게 된다.