공부 정리/You Don't Know Js

[YDKJ] Scope & Closures - Around the Global Scope

경적필패. 2023. 5. 18. 23:57
반응형

요약

Chapter 4: Around the Global Scope

  • 챕터3 에서는 전역 스코프를 주로 언급했으나, 왜 전역 스코프를 사용하면 안되는지, 언제 유용한지에 대해 언급하지 않았음
  • 챕터4에서는 이를 중점으로 볼 것.

Why Global Scope?

대부분의 애플리케이션은 여러개의 개별 js파일로 구성되는 것이 일반적임

=> 그렇다면 js엔진은 어떻게 이러한 분리된 파일을 하나의 런타임 컨텍스트로 관리할까?

 

브라우저에서 실행되는 어플리케이션의 경우 크게 3가지가 있음.

 

1. es모듈을 직접 사용한다면, JS환경에서 각 모듈이 개별적으로 로드 됨. 그 후, 각 모듈이 필요한 모듈이 있을 때, 참조로 가져옴.(공유된 스코프 없이 import를 통해 협력)

 

2. 빌드 프로세스에서 번들러를 사용한다면, 애플리케이션의 모든 구성요소가 단일 파일에 함께 있는 경우에도 각 구성요소가 다른 구송 요소에 참조할 수 있도록 매커니즘 필요함.

 

3. 파일이 브라우저에서 개별적으로 로드되는 경우.

 

Where Exactly is this Global Scope?

전역범위는 파일의 가장 바깥쪽 부분에 위치하는 것처럼 보일 수 있음..

그러나 그렇게 간단하지 않다!

여러 js환경은 전역범위를 다르게 처리함

 

Browser "Window"

브라우저에서는 일반적으로 window가 전역객체임.

var studentName = "Kyle";

function hello() {
    console.log(`Hello, ${ window.studentName }!`);
}

window.hello();
// Hello, Kyle!

가장 일반적인 동작.

 

window.something = 42;

let something = "Kyle";

console.log(something);
// Kyle

console.log(window.something);
// 42

let은 전역변수를 추가하지만, 전역 개체 속성을 추가하진 않음.

=> 전역개체와의 차이점을 만드는건 bad idea임.

=>이 함정을 피하기 위해서는 항상 var을 전역변수로 사용하고 let과 const를 블록범위에 사용할 것.

 

DOM Globals

id 속성이 있는 DOM 요소가 자동으로 참조하는 전역 변수를 생성함.

<ul id="my-todo-list">
   <li id="first">Write a book</li>
   ..
</ul>

가 있을 때,

first;
// <li id="first">..</li>

window["my-todo-list"];
// <ul id="my-todo-list">..</ul>

처럼 생성됨.

=> 모든 ID를  가진 DOM 요소를 자동으로 전역 변수로 등록하는 것은 오래된 레거시 브라우저 동작임.

=> 그러나 여전히 많은 사이트가 이에 의존함.

 

What's in a (Window) Name?

var name = 42;

console.log(name, typeof name);
// "42" string

var asdf = 42;
console.log(asdf, typeof asdf);
// 42 number

위 예시에서 name이 string으로 나온이유는 이미 window.name이라는 전역객체가 있었기 때문임.

따라서 이미 존재하는 전역객체 때문에(getter/setter) 떄문에 문자열이 나온 것.

 

Web Workers

  • 웹 워커는 웹 플랫폼 확장으로, 브라우저-js기반에서 동작함.
  • 메인 스레드와 별개의 스레드에서 실행할 수 있게 해줌.=> 그러나 통신은 제한됨.(ex 웹워커는 DOM에 접근 불가)
  • 마찬가지로 스코프를 공유하지도 않음. => 그래서 window대신 self를 사용함
var studentName = "Kyle";
let studentID = 42;

function hello() {
    console.log(`Hello, ${ self.studentName }!`);
}

self.hello();
// Hello, Kyle!

self.studentID;
// undefined

var및 함수 선언은 글로벌 객체에 속성을 생성하지만, let은 아님

 

Developer Tools Console/REPL

  • Developer Tools은 완전한 js환경을 생성하는 건 아니므로 주의할 것.
  • 콘솔/REPL을 사용할 때 바깥쪽 범위에서 입력된 문장이 실제 전역 범위에서 처리되는 것처럼 보일 수 있지만 정확하진 않음. => 모방일뿐

 

ES Modules (ESM)

ESM의 가장 눈에 띄는 영향 중 하나는 파일에서 최상위 스코프의 범위 동작을 변경하는 것.

=> 왜냐하면 모듈방식을 사용하면 전역범위를 쓰는대신 모듈 범위를 사용하여 전역 사용을 최대한 줄일 수 있다 !

=> 의존도를 최소화 하는 것이지, 전역 범위를 아예 안쓸 수 는 없음.

 

Node

  • Node는 모든 js파일을 모듈로 취급함.=>브라우저처럼 최상위 수준이 전역 범위가 아님.
  • Node에서 전역변수를 사용하는 법은 global을 사용하는 것. 브라우저의 window와 비슷함.

Global This

es2020부터 JS는 전역범위 객체에 접근하기 위한 표준을 제시했음

그게 globalThis임.

이제 global인지 window인지 걱정하지 않고 globalThis를 이용하면 된다.

 

 

 

느낀 점

전역변수에 대해서 좀 더 깊게 생각해볼 수 있는 챕터였다.

노드 js와 브라우저 js의 전역객체 차이점, 그리고 globalThis의 존재.

이미 존재하는 전역객체에 접근할 때, let이 전역객체에 속성을 추가하지 않는다는 것을 배울 수 있는 챕터였다.

 

반응형