유효범위(Scope)

mandoo·2022년 10월 28일
0

JavaScript

목록 보기
4/7

1. 스코프(Scope, 유효범위)란?

스코프는 참조 대상의 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이다. 식별자는 자신이 어디에서 선언되었는지에 따라 자신이 유효한 범위, 즉 스코프를 갖는다. 여기서 "유효하다"란 "참조(접근)할 수 있다"는 의미이다.

2. 스코프의 구분

JavaScript에서 스코프는 2가지로 나눌 수 있다.

  • 전역 스코프(Global Scope): 코드 어디에서든지 참조할 수 있다.
  • 지역 스코프(Local Scope, Function-level scope): 함수 자신과 하위 함수에서만 참조할 수 있다.

모든 변수는 스코프를 가지는데 변수의 관점에서 스코프를 구분하면 2가지로 나눌 수 있다.

  • 전역 변수(Global Variance): 전역에서 선언된 변수로 어디에든 참조할 수 있다.
  • 지역 변수(Local Variance): 함수 내에서 선언된 변수이며 함수와 하위 함수에서만 참조할 수 있다.

변수는 선언 위치(전역 또는 지역)에 의해 스코프를 갖는다. 즉, 전역에서 선언된 변수는 전역 스코프를 갖는 전역 변수이고, 지역(자바스크립트의 경우 함수 내부)에서 선언된 변수는 지역 스코프를 갖는 지역 변수가 된다.

3. JavaScript 스코프의 특징

대부분의 프로그래밍 언어는 블록 레벨 스코프(Block-level scope)를 따른다. 블록 레벨 스코프란 코드 블록({...}) 내부에서 유효한 스코프를 말한다.
이에 반해 JavaScript는 함수 레벨 스코프(Function-level scope)를 따른다. 함수 레벨 스코프란 함수 내부에서 선언된 변수는 함수 내부에서만 유효하고 함부 외부에서는 유효하지 않다는 것이다.
단, EMCAScript 6에서 도입된 let keyword를 사용하면 JavaScript에서도 블록 레벨 스코프를 사용할 수 있다.

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

4. 전역 스코프(Global scope)

전역에 변수를 선언하면 이 변수는 어디서든지 참조할 수 있는 전역 스코프를 갖는 전역 변수가 된다. var 키워드로 선언한 전역 변수는 전역 객체(Global Object) window의 프로퍼티이다.

var global = 'global';

function func() {
  var local = 'local';
  console.log(global);
  console.log(local);
}
func(); //global local

console.log(global); // global
console.log(local); // Uncaught ReferenceError: local is not defined

JavaScript는 타 프로그래밍 언어와는 달리 특별한 시작점(Entry point)이 없어서 위 코드처럼 전역에 변수나 함수를 선언하기 쉽다. 전역 변수는 변수 이름이 중복될 수 있고, 의도치 않은 재할당으로 코드를 예측하기 어렵게 만드므로 사용을 절제해야한다.

5. 함수 레벨 스코프(Function-level Scope)

if (true) {
  var x = "global";
}

function func() {
  var y = "local";
}

console.log(x); // global
console.log(y); // Uncaught ReferenceError: local is not defined

변수가 코드 블록 내부에서 선언되었다 하더라도 JavaScript는 함수 레벨 스코프를 따르기 때문에 함수 밖에서 선언된 변수는 모두 전역 변수이다. 따라서 위 코드에서 변수 x은 전역 스코프를 갖는 전역 변수이다.
JavaScript는 함수 레벨 스코프를 따르기 때문에 함수 내부에서 선언된 매개변수와 변수는 함수 외부에서는 유효하지 않다. 따라서 변수 y은 지역 변수이다.

1) 변수명이 중복 선언된 경우

var x = 'global';

function func() {
  var x = 'local';
  console.log(x);
}

func(); // local
console.log(x); // global 

위 코드에서 전역 변수 x와 지역 변수 x는 중복 선언되었다. 전역 영역에서는 전역 변수만 참조 가능하고 함수 내부에서는 전역과 지역 변수 모두 참조 가능하나 위 코드와 같이 변수명이 중복된 경우 인접한 지역 변수를 우선하여 참조한다.

2) 내부 함수의 경우

var x = 'global';

function outer() {
  var x = 'local';
  console.log(x); // local

  function inner() {
    console.log(x); // local
  }
  inner();
}
outer();
console.log(x); // global

내부 함수는 자신을 포함하고 있는 외부 함수의 변수에 접근할 수 있다. 함수 inner에서 변수 x는 함수 outer에서 선언된 지역 변수이다. 이는 실행 컨텍스트의 스코프 체인에 의해 전역 변수 x의 참조 순위가 뒤로 밀렸기 때문이다.

3) 변수의 변경

var x = 10;

function func() {
  x = 100;
  console.log(x); // 100
}
func();
console.log(x); // 100

함수 영역에서 전역 변수를 참조할 수 있다는 말은 전역 변수의 값을 변경할 수도 있다는 의미이다. 내부 함수의 경우, 전역 변수는 물론 상위 함수에서 선언한 변수도 접근 혹은 변경할 수 있다.

var x = 10;

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

  function inner(){
    x = 1000;
    console.log(x); // 1000
  }

  bar();
}
foo();
console.log(x); // 10

중첩 스코프의 경우 가장 인접한 지역을 우선하여 참조(접근)한다.
위 코드에서 내부 함수 inner는 더 인접한 지역인 외부 함수 outer의 내부에서 선언된 변수 x에 접근하여 값을 변경하였다.

6. 렉시컬 스코프

var x = 1;

function func1() {
  var x = 10;
  func2();
}

function func2() {
  console.log(x);
}

func1(); // 1
func2(); // 1

위 코드의 실행 결과는 함수 func2의 상위 스코프가 무엇인지에 따라 결정된다.
어디서 함수를 호출하였는지에 따라 상위 스코프를 결정한다면 func2의 상위 스코프는 func1이 되고 어디서 함수를 선언하였는지에 따라 상위 스코프를 결정한다면 func2의 상위 스코프는 전역이 될 것이다.
전자를 동적 스코프(Dynamic scope)라 하고 후자를 렉시컬 스코프(Lexical scope) 또는 정적 스코프(Static scope)라고 한다. JavaScript를 비롯한 대부분의 프로그래밍 언어는 렉시컬 스코프를 따른다.

렉시컬 스코프는 함수를 어디서 호출하는지가 아니라 어디에 선언하였는지에 따라 결정된다. 위 코드에서 함수 func2는 전역에서 선언되었으므로 함수 func2의 상위 스코프는 전역 스코프가 된다.

7. 참고 문서

poiemaweb: JavaScript 스코프

profile
매일 조금씩이라도 꾸준히

0개의 댓글