[JavaScript] 스코프(Scope)

eonisal·2023년 9월 5일
0

JavaScript

목록 보기
1/3
post-thumbnail

🛰️ 자바스크립트 함수가 실행되는 과정

자바스크립트에서 함수가 실행되는 과정을 간략하게 설명하자면, '함수가 실행될 때 각 스코프에 해당하는 실행 컨텍스트가 콜스택에 쌓인다' 라고 표현할 수 있다.

이 문장을 이해하기 위해 알아야 할 개념이 스코프(Scope)와 실행 컨텍스트(Execute Context)인데 우선 스코프에 대해 정리해보자.

🎪 Scope

스코프란 단어의 뜻 그대로 '범위'라는 의미를 가지고있다. 코드에서의 스코프는 '변수에 접근할 수 있는 범위'라고 보면 된다.

자바스크립트의 스코프는 크게 전역 스코프(Global Scope)와 지역 스코프(Local Scope)로 나눌 수 있다.

전역 스코프(Global Scope)
자바스크립트 코드의 최상위 레벨에 해당하는 스코프로 함수 어디에서든 접근이 가능하다.

지역 스코프(Local Scope)
특정 함수에 해당하는 스코프로 해당 함수 자신과 하위 함수에서만 자원에 접근이 가능하다.

여기서 코드의 최상위 레벨, 즉 전역에서 변수를 선언하면 그 변수는 전역 변수이므로 global scope에 속하는 거라고 생각이 들지만 한가지 유의해야 할 점이 있다.

n0='n0';
var v0='v0';
let l0='l0';
const c0 = 'c0';
console.log(v0, n0, l0, c0);
console.log(window.v0, window.n0, window.l0, window.c0);

이 코드를 브라우저에서 실행했을 때 브라우저 개발자도구의 디버거(debugger)의 모습은 다음과 같다.

위 코드를 4번째줄 까지 실행했을 때의 모습인데, 디버거에 나와있는 스코프 정보에는 우리가 알고있는 전역 스코프 외에 스크립트라는 스코프가 있다.

현재 이 코드는 전역 레벨에서의 내용만 있는 코드이다. 그리고 n0, v0, l0, c0 이라는 변수를 선언했는데 이 변수들은 전역 변수일 것이다. 그런데 '스크립트' 라는 스코프가 따로 있고 c0과 l0는 이 스크립트 스코프 안에 있는것을 볼 수 있다.

이 script scope는 뭐고 global scope와는 뭐가 다른것일까?

Global Scope

우리가 흔히 아는 전역 스코프인 Global Scope는 최상위 레벨의 범위로, 브라우저에서 실행되는 js에서는 window 객체가 담당한다.

위의 디버거의 모습을 보면 전역 스코프에는 옆에 window 라고 적혀있는 것을 볼 수 있다. 그리고 이 전역 스코프를 펼쳐보면 alert 함수 등 우리가 알고 있던 window 객체의 수많은 변수와 함수들을 볼 수 있다.

그리고 전역에서 변수를 선언할 때

n0='n0';
var v0='v0';

와 같이 키워드를 사용하지 않고 변수를 선언하거나, var를 사용해 변수를 선언하면 이 변수들은 전역 스코프에 추가된다. 실제로 디버거의 전역 스코프를 열어보면 window 객체의 프로퍼티들과 함께 변수 n0과 v0이 들어가있는 것을 볼 수 있다. 따라서 window.v0, window.n0 으로도 접근이 가능하다.

그리고 키워드를 사용하지 않고 변수를 선언하면 함수 내에서 선언했더라도 그 변수는 전역 변수가 되어 global scope를 가진다.

Script Scope

let l0='l0';
const c0 = 'c0';

이처럼 전역에서 let이나 const를 사용하여 선언한 변수는 global scope가 아닌 script scope에 추가된다. 디버거의 모습으로 보자면 global scope와는 별개의 scope처럼 나와있어서 전역스코프가 아닌 다른 스코프로 보이는데 분명 l0과 c0도 전역 변수인건 맞다.

이 script scope라는 것에 대해 정확히는 모르겠지만 global 환경을 기존의 global scope를 담당하는 window 객체와 script scope로 나눈거라고 보면 될 거 같다.

let과 const는 js의 역사에서 비교적 최근에 추가된 문법인데, 만약 이 문법을 전역 레벨에서 실행했을때 기존과 동일하게 window 객체 내에 추가가 된다면 이미 굉장히 많은 프로퍼티들이 있는 상황에 새로운게 추가가 되는것이다.

그러면 기존에 있던 window 객체의 변수나 함수가 새로 추가되는 사용자 정의 변수의 이름과 동일하여 덮어씌워지는 등 여러 문제가 발생할 수도 있기 때문에 window 객체인 기존의 global scope와는 다른 전역 스코프가 따로 추가된 것이 아닐까 싶다.

아무튼 script scope는 글로벌 환경인건 맞지만 기존의 global scope인 window 객체와는 별개인 또다른 global scope 라고 이해해두면 될 것 같다. 그리고 let과 const로 선언된 전역변수는 script scope에 들어간다는거!

Local Scope (Function-level Scope)

전역이 아닌 함수 내에 선언된 변수들은 지역 스코프(local scope)를 가진다. 이 지역 스코프는 함수 스코프와 블록 스코프로 나뉜다.

Function-level Scope

C언어 등의 언어는 지역 스코프가 블록 레벨 스코프(Block-level Scope)를 따른다. 특정 함수 내에 어떠한 블록이 있다면, 그 블록 내에 있는 변수는 해당 함수 내에서도 접근할 수 없고 오직 그 블록 내에서만 접근이 가능하다.

하지만 자바스크립트는 기본적으로 함수 레벨 스코프(Function-level Scope)를 따른다. 함수 내에서 선언한 변수는 그 함수 내에서만 접근할 수 있고 함수 안의 블록에서 선언된 변수도 해당 함수 내에서 접근할 수 있다.

function f1() {
  var x = 0;
  {
    var x = 1;
    console.log(x);  // 1
  }
  console.log(x);  // 1
}

f1();

Block-level Scope

let과 const 키워드를 사용하여 변수를 선언하면 그 변수는 Block-level Scope를 가진다. let과 const 변수는 선언된 블록 내에서만 유효하다.

function f1() {
  let x = 1;
  const y = 2;
  {
    let x = 3;
    const y = 4;
    console.log(x, y);  // 3, 4
  }
  console.log(x, y);  // 1, 2
}

f1();

Lexical Scope

함수의 위치에따라 함수의 상위 스코프가 정해지는데 이 상위 스코프가 정해지는 시점이 함수의 선언인지, 함수의 실행인지에 따라 함수의 상위 스코프가 달라진다.

함수의 상위 스코프가 함수가 실행되는 시점에서의 상위 스코프로 정해지는 것을 동적 스코프(Dynamic Scope), 함수가 선언되는 시점에서의 상위 스코프로 정해지는 것을 정적 스코프(Static Scope) 또는 렉시컬 스코프(Lexical Scope)라고 한다.

자바스크립트는 렉시컬 스코프 방식을 따른다. 따라서 함수의 선언부에서의 상위 스코프가 해당 함수의 상위 스코프로 결정된다.



참고자료
유튜브 생활코딩
https://poiemaweb.com/js-scope

profile
언제까지_이렇게_살아야돼_

0개의 댓글