가치투자자

[JS/기술면접] 스코프(scope)란? 본문

Programming/JavaScript

[JS/기술면접] 스코프(scope)란?

미주민 2023. 4. 4. 21:39
728x90
반응형

 스코프 (scope) 

변수와 더불어 모든 프로그래밍 언어에서 가장 기본적인 개념 중 하나가 스코프(scope)이다.

그만큼 중요하기에 완벽하게 자신의 것으로 만들 필요가 있다.

 

* 기술면접 질문은 맨 아래에 적혀 있습니다

 

728x90

1. 스코프란?

공식 문서를 살펴보면, 스코프는 '변수와 표현식을 식별하거나 참조할 수 있는 현재 실행 컨텍스트'를 의미한다고 나와있다.

좀 더 쉽게 설명해보자면,  스코프 (scope) 식별자(identifier, 변수, 함수, 클래스의 이름)가 유효한 범위를 말한다.

서울에 A라는 사람이 살고 있을 때, 서울이라는 범위 내에선 A의 존재를 찾을 수 있고, 서울 밖에서는 A를 찾을 수 없다. 이때 서울이 스코프인 것이다. 만약 서울 외 지역에서 A를 찾게되면, A를 찾을 수 없다며 참조에러(ReferenceError)가 발생할 것이다.

아래의 예시를 보면, 함수 '서울()' 내에서는 A를 찾을 수 있지만, 함수 밖에서는 A를 찾을 수 없다.

const B = 1;

function 서울() {
  const A = 2;
  console.log(A);  // 2
}
서울();

console.log(B);  // 1
console.log(A);  // ReferenceError: A is not defined

1) 스코프가 필요한 이유

만약 스코프가 없다면, 같은 이름을 가진 식별자들끼리 충돌이 일어날 것이다.

만약 스코프가 없다면, 함수 내에서만 활동하는 A와 함수 밖에 있는 A가 중복 선언으로 간주되어 에러가 발생할 것이다.

아래처럼 스코프가 있기에 서로 다른 값이 출력될 수 있는 것이다.

(* 함수 내 A와 함수 밖 A는 서로 다른 변수 A인 것이다)

const A = 1;

function 서울() {
  const A = 2;
  console.log(A);  // 2
}
서울();

console.log(A);  // 1

 


2. 스코프의 종류

이러한 스코프에는 2가지 종류가 있다.

2-1. 전역 스코프 (global scope)

 전역 스코프 코드의 가장 바깥 영역을 말한다. 함수나 블록(if문, for문, while문 등)에서 가장 바깥에 있는 영역을 말한다.

이러한 전역 스코프에 선언된 변수를  전역 변수 (global variable) 라고 하며, 어디서든 이 변수를 참조(사용)할 수 있다.

const A = 1;

function 서울() {
  const B = 2;
  console.log(A);  // 1, 전역변수를 함수 내에서 참조할 수 있다
}
서울();

console.log(A);  // 1, 전역 스코프에서 전역변수를 참조할 수 있다

 


2-2. 지역 스코프 (local scope)

 지역 스코프 블록이나 함수 내부 등 특정 영역을 말하며, 지역 스코프 내에 선언된 변수를  지역 스코프 (local variable) 라고 하며, 자신의 지역 스코프와 하위 지역 스코프에서만 참조 가능하다.

이러한 지역 스코프에는 함수 스코프블록 스코프가 존재한다.

function 서울() {
  const B = 2;
  console.log(B);  // 2, 지역변수를 지역 스코프에서 참조 가능
}
서울();

console.log(B);  // ReferenceError: B is not defined

 

1) 함수 레벨 스코프 (function-level scope)

 함수 레벨 스코프 는 함수 블록만 지역 스코프로 인정해주는 특징을 말한다.

따라서 함수 내에 선언된 변수는 함수 내에서만 참조할 수 있고, 함수 외의 블록(if문, for문, while문, try/catch 등)은 지역 스코프로 인정하지 않기에 전역에서도 스코프의 경계를 무시하고 지역 변수를 참조할 수 있다.

 

CASE 1

 var 키워드 함수 레벨 스코프를 따른다. 따라서 if문이 var x 변수를 감싸고 있어도 저 if문 블록은 없는 것과 마찬가지다.

따라서 var x = 1에 var x = 10로 중복 선언해줘서 값을 바꿔버린다.

var x = 1;

if (true) {
  var x = 10;
}
console.log(x); // 10

------------------------

// if문의 블록 스코프를 인정하지 않기에 아래와 같은 상황인 것이다.
var x = 1;
var x = 10;
console.log(x); // 10

 

2) 블록 레벨 스코프 (block-level scope)

자바스크립트는 다른 언어와 달리 함수 레벨 스코프를 따르는 언어이다. 하지만 ES6부터 let 키워드가 도입되면서 블록 레벨 스코프를 사용할 수 있게 되었다.

 블록 레벨 스코프 는 블록{}, if문, for문, while문, try/catch 등 블록을 지역 스코프로 인정해주는 특징을 말한다. 따라서 블록 내부에 선언된 지역 변수는 블록 내부에서만 접근이 가능하다.

 

CASE 2

그렇지만 var 키워드는 함수 레벨 스코프를 따르기에 블록 바깥에서도 블록 내 var 변수를 참조할 수 있다.

if (true) {
  var x = 10;
  let y = 20;
}
console.log(x);  // 10
console.log(y);  // ReferenceError: y is not defined

 


3. 스코프 체인 (scope chain)

이러한 스코프들은 서로 따로따로 존재하지 않는다. 함수 내에 또 다른 함수가 존재할 수 있고, 이런 경우 스코프가 겹친다.

아래의 사진을 살펴보면, 함수 foo() 내에 함수 bar()가 선언되어 있다. 이렇게 함수가 중첩될 때 함수 내부에 정의된 함수를  중첩함수 (nested function) 이라 하고, 그 중첩 함수를 포함하고 있는 함수를  외부 함수 (outer function) 라고 한다.

 

이때 bar() 함수가 실핼될 때, bar() 함수 내에는 변수 barColor가 있어 출력할 수 있지만, fooColor는 없다.

그럼 자바스크립트 엔진은 bar()의 외부함수인 foo() 함수에 가서 fooColor를 찾게 된다.

 

이렇게 상위 스코프와 하위 스코프가 계층적으로 연결된 것을  스코프 체인 (scope chain) 이라고 한다.

이때 자바스크립트 엔진은 오직 상위 스코프 방향(단방향)으로만 이동하면서 변수를 검색한다. 즉, 하위 스코프에 있는 변수를 상위 스코프에서 참조할 수 없다. 앞서 전역 스코프에서 지역 스코프 내의 변수를 참조할 수 없었던 것도 상위 스코프(전역)에서 하위 스코프(지역)의 변수를 참조하려 했기 때문이다.

 

 


4. 렉시컬 스코프 (lexical scope)

이처럼 변수를 탐색하고 참조하기 위해서 어느 스코프가 상위 스코프인지 중요하다. 그럼 상위 스코프는 어떻게 결정되는걸까?

먼저 아래 코드를 살펴보자.

let x = 1;

function foo() {
  let x = 10;
  bar();
}

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

foo(); // ?
bar(); // ?

 

위 코드가 어떻게 실행될까? 두 가지 결과를 예상할 수 있다.

 

1번째는  호출한 위치 로 상위 스코프를 결정할 수 있을 것이다. bar() 함수가 foo() 함수 내에서 호출되었기에 bar() 함수의 상위 스코프를 foo() 함수로 생각할 수 있다. 그럼 foo() 함수 내에서 x를 찾아야 하니 x의 값으로 10이 출력될 것이다.

이런 결정 방식을 "동적 스코프(Dynamic scope)"라고 한다.

 

2번째는  선언된 위치 로 상위 스코프를 결정하는 방식이다. bar() 함수가 foo() 함수 내에서 호출되긴 했지만, 선언된 곳은 전역 스코프이기에 전역 스코프를 상위 스코프로 볼 수 있다. 그럼 전역에서 x를 찾아야 하니 x의 값으로 1이 출력될 것이다.

이런 결정 방식을 "정적 스코프(Static scope)" 또는 "렉시컬 스코프(Lexical scope)"라고 한다.

 

자바스크립트는 함수가 어디에 선언되었는지에 따라 상위 스코프를 결정된다.

만약 함수를 호출한 위치를 통해 상위 스코프를 결정한다면, 그 과정을 하나하나 다 확인해야하고 그 과정은 매우 복잡을 것이다.

즉, 코드를 위에서 아래로 적힌 순으로 실행이 되지 않기에 코드의 가독성도 많이 떨어질 것이며, 이로 인해 어떤 에러가 발생할 수 있는지 생각하기 어렵다. 따라서 2번 방식으로 코드가 실행된다.

 

그리고 함수가 호출될 때마다 함수의 상위 스코프와 그 내의 변수들을 참조할 필요가 있기 때문에, 함수가 선언된 때(함수 선언문, 함수 표현식) 생성된 함수 객체가 상위 스코프를 기억하고 있어 참조가 가능하다.

 

🎯  렉시컬 환경 (lexical Environment)

  • 특정 코드가 선언(작성)된 환경(장소)를 의미한다

 

반응형

 


🌟 자바스크립트 기술면접 질문

1. 스코프가 뭔가요? 🔥🔥

 

  • 식별자(변수, 함수, 클래스의 이름)가 유효한 범위

 

2. 스코프에는 어떤 종류가 있죠? 🔥

 

  1. 전역 스코프
    - 코드의 가장 바깥 영역
    - 전역 스코프 내에 선언된 전역 변수는 어디서든 참조가 가능하다


  1. 지역 스코프
    - 블록이나 함수 내부 등 특정 영역
    - 지역 스코프 내에 선언된 지역 변수는 자신의 지역 스코프와 하위 지역 스코프에서만 참조 가능하다

3. 스코프 체인은 무엇인가요? 🔥

 

  • 상위 스코프와 하위 스코프가 계층적으로 연결된 것을 말하며, 자바스크립트 엔진은 오직 하위 스코프에서 상위 스코프 방향으로만 이동하면서 변수를 탐색한다

 

4. 렉시컬 스코프는 무엇을 의미하나요? 🔥

 

  • 함수가 어디에 선언되었는지에 따라 상위 스코프를 결정하는 방식을 말한다. 만약 렉시컬 스코프가 아니라 동적 스코프로 상위 스코프를 결정하게 되면, 코드 작성 순으로 코드가 실행되는 것이 아니므로, 코드의 가독성이 매우 떨어지고 이로 인해 에러가 발생할 가능성도 생긴다.

 


</> 끊임없이 성장하기 위해 공부한 내용을 글로 작성하고 있습니다. 틀린 부분이나 추가해야 할 부분이 있다면 언제든 댓글로 남겨주세요❗️

 


References

 

728x90
반응형