Skip to content

Latest commit

 

History

History
156 lines (114 loc) · 5.96 KB

File metadata and controls

156 lines (114 loc) · 5.96 KB

스코프

모든 식별자(변수 이름, 함수 이름, 클래스 이름 등)는 자신이 선언된 위치에 의해 다른 코드가 식별자 자신을 참조할 수 있는 유효 범위를 스코프라고 한다.

모든 식별자는 자신이 선언된 위치에 따라 스코프를 다르게 가진다는 부분에 주의하자.

식별자 중복?

식별자는 유일해야하지만… 이는 같은 스코프 내에서 유일해야하는 것이고 다른 스코프에서는 동일한 이름의 식별자를 사용할 수 있다.

즉, 스코프는 네임스페이스로서의 기능도 담당한다.

❓ 네임스페이스란?

네임스페이스(namespace)는 프로그래밍에서 이름들을 구분하여 관리하는 개념입니다. 코드의 다른 부분에서 동일한 이름을 사용할 수 있도록 해주는 일종의 "이름 공간"이라고 생각하면 됩니다.

네임스페이스의 핵심 개념을 설명하자면:

  1. 이름 충돌 방지: 서로 다른 네임스페이스에 존재하는 동일한 이름의 식별자들은 서로 충돌하지 않습니다. 예를 들어, A 네임스페이스의 counter와 B 네임스페이스의 counter는 완전히 다른 변수입니다.
  2. 구조적 조직화: 큰 프로그램에서 관련된 기능들을 논리적으로 그룹화할 수 있게 해줍니다.
  • 자바스크립트에서는 함수나 객체가 네임스페이스 역할을 할 수 있습니다. 각 함수는 자신만의 스코프를 가지므로, 서로 다른 함수 내에서 동일한 이름의 변수를 선언해도 충돌이 발생하지 않습니다.
  • 파이썬에서는 모듈과 패키지가 네임스페이스 역할을 합니다.
  • *C++**이나 **C#**에서는 명시적인 namespace 키워드가 있습니다.

다른 식별자와 구분되는 var의 동작

이러한 스코프 식별자 원칙 구현이 var와 let,const 와는 다소 다르다.

function foo() {
	var x = 1;
	var x = 2;
	
	console.log(x); // 2
}
foo();

// var는 같은 스코프내에서 중복 선언이 허용된다.
// 이 때 가장 나중에 선언된 변수만 선언으로 허용된다.
function bar() {
	let x = 1;
	let x = 2; // SyntaxError: Identifier 'x' has already been declared
}
bar(); 

// let과 const는 같은 스코프 내 중복선언이 불가능하다.

전역과 지역 스코프

  • 코드는 전역과 지역으로 나뉜다
    • 전역이란 코드의 가장 바깥 영역을 말한다.
    • 지역이란 함수 몸체 내부를 말한다.
    • 보통 블록이 스코프를 만드는 기준임 (블록 레벨 스코프)
    • 그러나 var의 경우는 지역 스코프는 함수본체에 의해서만 생김 (다른 언어랑 차이)
      • 함수 본체가 아닌 if나 for같은 블록스코프 안에 var로 변수 선언하면 전역스코프가됨
      • 이를 함수 레벨 스코프라고 하며, 이 특성은 많은 혼란을 일으킬 수 있다
      • 이런 혼란 때문에 ES6에서 let과 const가 도입됐다고 볼 수 있음
// var의 함수 레벨 스코프 예시
function myFunc() {
   var a = 1; // 함수 스코프

   if (true) {
      var b = 2; // 함수 스코프 (블록 스코프가 아님!)
   }

   console.log(a); // 1
   console.log(b); // 2 (접근 가능)
}

// let과 const의 블록 레벨 스코프 비교
function myFunc2() {
   let c = 3; // 함수 스코프

   if (true) {
      let d = 4; // 블록 스코프
   }

   console.log(c); // 3
   console.log(d); // ReferenceError: d is not defined
}

스코프체인

  • 스코프는 계층 구조를 이룸 → 스코프체인
    • 스코프 체인의 물리적 실체가 렉시컬 환경 (정보를 가지고 있음 그 자체라기보다는)
    • 내부 함수에서 변수를 참조할 때 먼저 자기 자신의 스코프에서 검색하고, 없으면 바깥 스코프를 차례로 검색함
    • 이런 검색 과정을 "식별자 결정(identifier resolution)"이라고 함
    • 스코프 체인은 단방향 연결
      • 하위 스코프에서 상위 스코프 참조 가능
      • 역은 불가능 (상위 스코프에서 하위 스코프의 변수는 참조 불가능)
// 스코프 체인 예시
var global = 'global';

function outer() {
   var outer = 'outer';

   function inner() {
      var inner = 'inner';
      console.log(inner); // inner (자신의 스코프)
      console.log(outer); // outer (outer 함수 스코프)
      console.log(global); // global (전역 스코프)
   }

   inner();

   console.log(inner); // ReferenceError: inner is not defined (역방향 참조 불가)
}

outer();

스코프의 종류

  • 스코프의 종류
    • 함수를 어디서 호출했는지에 따라 상위 스코프 결정 → 동적 스코프
      • 실행 시점에 호출한 위치에 따라 상위 스코프가 결정됨
      • 실행 컨텍스트가 동적으로 변함
      • 예: Perl, Bash 등의 언어가 채택
    • 함수를 어디서 정의했는지에따라 상위 스코프 결정 → 정적 스코프 | 렉시컬 스코프
      • 자바스크립트는 렉시컬 스코프를 따름
      • 코드를 작성하는 시점(코드가 정의될 때)에 이미 스코프가 결정됨
      • 함수가 정의되어 실행될 때 함수는 자신이 정의된 위치의 상위 스코프 정보까지 항상 기억하고있음
      • 이 기억하는 메커니즘이 클로저(closure)의 핵심 개념이기도 함
// 렉시컬 스코프 예시
var value = 1;

function foo() {
   var value = 2;
   bar();
}

function bar() {
   console.log(value); // 1
}

foo(); // 1이 출력됨 (bar 함수가 어디서 호출됐는지가 아니라, 어디서 정의됐는지가 중요)

렉시컬 스코프는 자바스크립트 엔진이 함수를 어디서 호출했는지가 아니라 어디에 정의했는지에 따라 상위 스코프를 결정한다는 것이 핵심이다. 즉, 함수의 상위 스코프는 언제나 자신이 정의된 스코프다.