4 분 소요

Scope 란?

  • 스코프(Scope, 유효범위)는 참조 대상 식별자를 찾아내기 위한 규칙이다. 자바스크립트는 이 규칙대로 식별자를 찾는다.
  • 변수는 전역 또는 코드 블록(if, for, while, try/catch 등)이나 함수 내에 선언하며 코드 블록이나 함수는 중첩 될 수 있다.
  • 식별자는 어디에서 선언됐는지에 의해 자신이 유효한(다른 코드가 자신을 참조할 수 있는) 범위를 갖는다.
let x = "global";

function foo() {
  let x = "function scope";
  console.log(x); // function scope
}

foo();
console.log(x); // global
  • 위의 예제를 보면 x는 어떠한 코드 블럭에 들어가지 않은 변수 이다. 이를 우린 전역 변수(global variable)라 부른다.
  • 반면 foo 함수 코드 블럭 안에 있는 x는 코드 블럭 안에 있는 변수이다. 이를 우린 지역 변수(local variable) 이라 부른다.
  • 위에 예제 코드는 x를 프린트 하는 코드이다. 실행 하면 어떻게 될까?
  • 전역 변수로 x는 ‘global’로 할당 하였다. foo 함수 내에서는 x를 또 다시 ‘function scope’라 할당 하였다. 그렇다면 변수 x는 달라 질까?
  • 답은 아니다. 전역 변수는 코드 블럭 밖에서 선언함으로 전체 코드 블럭에서 유효하다. 하지만 foo 함수 내에 있는 x는 foo 함수 코드 블럭 내에서만 유효하다. 따라서 x의 할당한 값이 변하지 않는 것이다. 이러한 규칙을 스코프라 부른다.
  • 만약 스코프 규칙이 없다면 같은 변수명을 가진 변수를 하나 밖에 선언을 하지 못할 것이다.

scope의 구분

  1. 전역 스코프(Global scope) 코드 어디에서든지 참조할 수 있다.

  2. 지역 스코프(Local scope) 함수 코드 블록이 만든 스코프로 함수 자신과 하위 함수에서만 참조할 수 있다.

  • 모든 변수는 스코프를 갖는다. 변수의 관점에서 스코프를 구분하면 다음과 같이 2가지로 나눌 수 있다.
  1. 전역 변수(Global variable) 전역에서 선언된 변수이며 어디에든 참조할 수 있다.

  2. 지역 변수(Local variable) 지역(함수) 내에서 선언된 변수이며 그 지역과 그 지역의 하부 지역에서만 참조할 수 있다.

  • 변수는 선언 위치(전역 또는 지역)에 의해 스코프를 가지게 된다. 즉, 전역에서 선언된 변수는 전역 스코프를 갖는 전역 변수이고, 지역(함수 내부)에서 선언된 변수는 지역 스코프를 갖는 지역 변수가 된다.
  • 전역 스코프를 갖는 전역 변수는 전역(코드 어디서든지)에서 참조할 수 있다. 지역(함수 내부)에서 선언된 지역 변수는 그 지역과 그 지역의 하부 지역에서만 참조할 수 있다.

자바스크립트 스코프의 특징

  • 자바스크립트의 스코프는 타 언어와는 다른 특징을 가지고 있다.
  • 대부분의 C-family language는 블록 레벨 스코프(block-level scope)를 따른다.
  • 블록 레벨 스코프란 코드 블록({…})내에서 유효한 스코프를 의미한다.
  • 하지만 자바스크립트는 함수 레벨 스코프(function-level scope)를 따른다.
  • 함수 레벨 스코프란 함수 코드 블록 내에서 선언된 변수는 함수 코드 블록 내에서만 유효하고 함수 외부에서는 유효하지 않다.(참조 할 수 없다)
  • let keyword를 사용하면 블록 라벨 스코프를 사용할 수 있다.
var x = 0;
{
  var x = 1;
  console.log(x); // 1
}
console.log(x); // 1

let y = 0;
{
  let y = 1;
  console.log(y); // 1
}
console.log(y); // 0
  • 위의 예제를 봤을 때, var keyword를 사용하여 x를 전역 변수 선언을 했을 때, 블록 밖에서 0을 선언을 하고, 블록 내에서 1을 지역 변수 선언을 또 다시 하였다. 블록 내에서 console.log를 찍어보면 1이 나올 것이다. 블록 밖에서도 물론 1이 찍힌다.
  • 왜냐하면 블록 내에서 x를 1로 할당 했다. 이 블록은 함수의 블록이 아닌 그냥 블록이다. 자바스크립트는 함수 레벨 스코프를 따르기 때문에 블록 외부에서도 1로 나오는 것이다.

  • 밑의 let keyword를 사용하는 경우는 블록 안에서는 1이 찍히고, 외부에서는 0이 찍힌다. 왜냐하면 let keyword는 블록 레벨 스코프를 따르기 때문이다.

스코프의 종류

전역 스코프

  • 전역에 변수를 선언하면 이 변수는 어디서든지 참조할 수 있는 전역 스코프를 갖는 전역 변수가 된다.
  • var keyword로 선언한 전역 변수는 전역 객체 window의 프로퍼티 이다.
var global = "global";

function foo() {
  var local = "local";
  console.log(global); // global
  console.log(local); // local
}
foo();

console.log(global); // global
console.log(local); // Uncaught ReferenceError: local is not defined
  • 변수 global는 함수 영역 밖의 전역에서 선언되었다. 자바스크립트는 타 언어와는 달리 특별한 시작점이 없어서 위 코드와 같이 전역에 변수나 함수를 선언하기 쉽다.
  • 이것은 전역 변수를 남발하게 하는 문제를 야기 시킨다.
  • 전역 변수의 사용은 변수 이름이 중복될수 있고, 의도치 않는 재할당에 의한 상태 변화로 코드를 예측하기 어렵게 만드므로 사용을 억제하여야 한다.

비 블록 레벨 스코프

if (true) {
  var x = 5;
}
console.log(x);
  • 변수 x는 코드 블록 내에서 사용되었다. 하지만 자바스크립트는 블록 레벨 스코프를 사용하지 않으므로 함수 밖에서 선언된 변수는 코드 블록 내에서 선언되었다할지라도 모두 전역 스코프를 갖게 된다. 따라서 변수 x는 전역 변수이다.

함수 레벨 스코프

var a = 10; // 전역변수

(function () {
  var b = 20; // 지역변수
})();

console.log(a); // 10
console.log(b); // "b" is not defined
  • 자바스크립트는 함수 레벨 스코프를 사용함으로, 함수 내에서 선언된 매개변수와 변수는 함수 외부에서 유효하지 않다. 따라서 b는 지역 변수이다.
var x = "global";

function foo() {
  var x = "local";
  console.log(x);
}

foo(); // local
console.log(x); // global
  • 전역변수 x와 지역변수 x가 중복 선언되었다. 전역 영역에서는 전역 변수만이 참조 가능하고 함수 내 지역영역에서는 전역과 지역 변수 모두 참조 가능하나, 위 예제와 같이 변수명이 중복된 경우, 지역변수를 우선하여 참조한다.
var x = "global";

function foo() {
  var x = "local";
  console.log(x); // local

  function bar() {
    // 내부함수
    console.log(x); // local
  }

  bar();
}
foo();
console.log(x); // global
  • 내부함수는 자신을 포함하고 있는 외부함수의 변수에 접근할 수 있다.
  • 함수 bar에서 참조하는 변수 x는 함수 foo에서 선언된 지역변수이다. 이는 실행 컨텍스트의 스코프 체인에 의해 참조 순위에서 전역변수 x가 뒤로 밀렸기 때문이다.
var x = 10;

function foo() {
  x = 100;
  console.log(x);
}
foo();
console.log(x); // 100
  • 함수(지역) 영역에서 전역변수를 참조할 수 있으므로 전역변수의 값도 변경할 수 있다. 내부 함수의 경우, 전역변수는 물론 상위 함수에서 선언한 변수에 접근/변경이 가능하다.
var x = 10;

function foo() {
  var x = 100;
  console.log(x); // 100

  function bar() {
    // 내부함수
    x = 1000;
    console.log(x); // 1000
  }

  bar();
}
foo();
console.log(x); // 10
  • 중첩 스코프는 가장 인접한 지역을 우선하여 참조한다.

keyword var, let, const

  • var : 함수 레벨 스코프 범위(화살표 함수의 블록 스코프는 무시x), 재할당 가능, 재선언 가능
  • let : 블록 레벨 스코프 및 함수 스코프 범위, 재할당 가능 하지만 재선언 방지
  • const : 블록 레벨 스코프 및 함수 스코프 범위, 재할당 불가

댓글남기기