[JavaScript] 스코프

Sjin·2021년 1월 21일
0

스코프란?

모든 식별자는 자신이 선언된 위치에 의해 다른 코드가 식별자를 참조할 수 있는 유효범위가 결정되고, 이를 스코프라한다. 즉, 식별자가 유효한 범위이다.

스코프의 종류

  1. 전역 스코프
  2. 지역 스코프

전역 스코프

코드의 가장 바깥쪽으로, 전역 변수는 어디서든 참조할 수 있다.

지역 스코프

함수 몸체 내부를 말한다. 자신의 지역 스코프와 하위 지역 스코프에서 유효하다. 따라서, 상위 스코프에서는 하위 지역에서 선언된 스코프를 참조할 수 없다.

스코프 체인

모든 스코프는 하나의 계층 구조로 이루어져있다. 하위 스코프는 상위 스코프를 가리키고, 상위 스코프는 다시 상위 스코프를 가리킨다. 이를 스코프 체인이라한다.

스코프 체인에 의한 함수 검색

변수를 참조할 때, 먼저 자신의 스코프 내에 변수가 선언됐는지 확인한다. 있으면 그 변수를 참조하고 검색을 종료한다. 없으면 상위 스코프로 이동하면서 변수가 선언됐는지 확인한다. 다른 스코프에 같은 변수명이 선언됐을 때, 어느 스코프의 변수를 참조할지는 스코프 체인을 통해 결정한다.

함수 레벨 스코프

개념

코드 블록이 아닌 함수에 의해서만 지역 스코프가 생성된다.

var

const와 let은 블록 레벨 스코프이지만, var은 함수 레벨 스코프이다. 따라서, var로 선언할 당시의 함수로 스코프의 범위가 정해진다.

var num = 10;

if (true) {
  num = 100;
}

console.log(num); // 100
// num이 선언될 당시 함수 범위가 전역으로 되있다. 따라서 num은 전역 변수이고, if 문 안에서의 num은 전역변수 num을 가리키고 있으므로 전역변수의 값이 변경된다.
var i = 5;
for (var i = 0; i<2; i++) {
  console.log(i); // 0 1
}
console.log(i); // 2
// i가 for 문 안에서 재선언됐으나, 범위는 전역이다. 전역 변수에 i가 이미 있으므로 전역 변수 i값이 바뀐다.

렉시컬 스코프

상위 스코프는 다음 두가지 경우에 의해 결정된다.

  1. 함수가 어디서 호출됐는지에 따라 상위 스코프가 결정된다.
  2. 함수가 어디서 정의됐는지에 따라 상위 스코프가 결정된다.

렉시컬 스코프는 2번 (함수가 어디서 정의됐는지)에 따라 상위 스코프가 결정된다. 따라서, 함수의 호출 위치는 전혀 상관없으면 선언될 당시에 상위 스코프가 어디었냐를 판단하면 된다.

예제

var fruit = 'banana';

function getFruit() {
  fruit = 'apple';
  log();
}

function log() {
  console.log(fruit);
}

getFruit();
log();
// apple
// apple

fruit을 전역 변수로 선언했다. 이후, getFruit을 호출하여 실행한다. 함수 내부에서 fruit을 apple로 바꿨다. 이때, fruit은 스코프 체인에 의해 상위 스코프인 전역 변수의 fruit을 가리키고 있으므로 값이 바뀐다. log가 선언될 당시 상위스코프는 전역 스코프로 정해졌다. log의 지역변수에 fruit이 없으므로 상위 스코프의 fruit을 가리키고, 이미 값이 바꼈으므로 apple을 출력한다. 따라서 apple로 출력된다. log를 호출할 때도 마찬가지다.

var fruit = 'banana';

function getFruit() {
  var fruit = 'apple';
  log();
}

function log() {
  console.log(fruit);
}

getFruit();
log();
// banana
// banana

위 예제와의 차이는 getFruit 내부에서 fruit을 재선언 한 것이다. 하지만 전혀 다른 결과가 나타났다. getFruit 내부에서 fruit은 재선언됐다. var은 선언 당시의 함수 레벨을 스코프로 가지고 있으므로 여기서 fruit은 getFruit 함수 내부의 지역 스코프라는 점이 중요하다. 따라서 전역 변수의 fruit은 아직 바뀌지 않았다. getFruit을 호출하면 내부에서 log를 호출한다. 이때 log가 선언될 당시 상위스코프는 전역 스코프이다. 따라서, 전역 변수 fruit이 가리키는 banana가 출력된다. 밑에 log도 마찬가지다.

처음에는 개념을 이해하기 어려웠으나 var의 특징을 생각하고 나니 이해가 됐다.

profile
프론트엔드 개발에 관심있는 주니어 웹 개발자입니다.

0개의 댓글