전역객체와 globalThis


globalThis?

globalThis는 환경에 관계없이 전역객체를 통일된 방법으로 참조할 수 있는 방법이다.

따라서, 아래와 같이 브라우저에서 globalThis를 참조하면, window객체를 반환하는 것을 확인할 수 있다.

또한, node.js 환경에서는 global객체를 반환한다.


사실 다양한 환경에서 전역객체를 가져와 환경에 맞게쓰는 경우가 얼마나 있겠냐만은,

전역객체 뿐만 아니라 브라우저 또는 플랫폼간에 워낙 통일감이 없는 javaScript의 현실을 봤을 떄,

나는 개인적으로 통일된 방법을 제안했다는 것 자체가 좋다고 생각한다. (사실 이거 개꿀인데?라고 생각했다😇)


globalThis에 대한 오해

근데 여기서 globalThis가 정확히 어떤건지 명확히 짚고 넘어갈 필요가 있다.

일반적인 맥락에서

1
2
3
4
5
// on Browser
globalThis === window; // true

// on node.js
globalThis === global; // true

이렇게 결과가 나오니까,

globalThis! 이거 전역객체구나!”

라고 생각하고 넘어가기 쉬운데, glbalThis는 전역객체인가? 라고 질문을 한다면,

엄밀히 말해 globalThis는 전역객체가 아니다.


globalThis의 실체

그럼 globalThis가 무엇이냐?

정답은 “globalThis전역 스코프this를 반환한다.”이다.

좀 더 자세히 말하면, globalThis 전역 실행컨텍스트의 this에 바인딩된 전역 객체에 대한 참조이다.


globalThis와 전역 실행 컨텍스트

이 부분은 “실행 컨텍스트”가 어떻게 생성되고, 어떻게 구성되어 있는지에 대한 지식이 필요하다.
(실행 컨텍스트에 대해 정리하면 링크 첨부할 생각…)

전역 코드는 실행 컨텍스트를 생성하는 코드로,

애플리케이션이 load되고 javaScript파일이 처음 평가될 때, 전역 실행 컨텍스트를 생성하게 된다.

전역 실행 컨텍스트가 생성되면, 전역 실행 컨텍스트에 전역 렉시컬 환경(Global Lexical Environment)이 생기는데,

이게 바로 전역 스코프의 실체, 변수나 함수가 관리되는 자료구조이다.


이 전역 렉시컬 환경에는 물론 this도 가지는데,

this[[GlobalThisValue]]라는 내부슬롯에 의해 전역객체가 바인딩 되게 된다.

[[GlobalThisValue]]가 바로 globalThis의 실체이다.

아래 ECMAScript 사양서에 나와 있는 전역 렉시컬 환경 생성 과정과, globalThis에 대한 정의를 보면 실제로 그렇다는 것을 알 수 있다.

ECMAScript - NewGlobalEnvironment

ECMAScript - globalThis


globalThis의 사용

그럼 이제 globalThis가 뭔지 제대로 알았으니 사용하기만 하면 된다!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- test.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test</title>
</head>
<body>
Test!
<script>
globalThis.onload = function () {
alert('짜쟌~~');
};
</script>
</body>
</html>

window 대신에 사용하면, 문제없이 잘 동작한다!

하지만, 이대로 문제없이 끝나면 좋으련만… 문제가 하나 있다 🥲


호환성

MDN - browser compatibility

ES11이라는 비교적 진보(?)된 문법이기 때문에, 어김없이 IE는 지원하지 않는다. 🤬


해결책? 킹 갓 Babel?

우리에겐 킹 갓 바벨이 있으니, Babel로 트랜스파일링하면 다 해결될꺼야!!@@

(는 개뿔…) babal env preset에서 지원하지 않는다.

만약 Babel로 globalThis를 트랜스 파일링하려면, 폴리필을 구현한 플러그인을 따로 적용해줘야 한다.


비교적 간단한 폴리필

비교적 간단하게 폴리필을 구현할 수도 있다.

일부 극단적인 환경에서는 사용할 수 없겠지만, MDN에서 제시하는 아래의 코드를 사용하면,

대부분의 환경에서는 문제없이 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
var getGlobal = function () {
if (typeof self !== 'undefined') return self;
if (typeof window !== 'undefined') return window;
if (typeof global !== 'undefined') return global;
throw new Error('unable to locate global object');
};

var globals = getGlobal();

if (typeof globals.setTimeout !== 'function') {
// no setTimeout in this environment!
}
// 출처 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/globalThis


결론

대부분의 최신 javaScript 환경에서는 전역 스코프의 this를 접근할 필요가 별로 없다. (라이브러리 만들 떄는 쓰려나..?)

아무튼, 이유없는 기술은 없다고 생각한다.

통일감이 없는 javaScript가 이런 통일된 움직임을 보이고 있다는 것 자체가 중요한 것 같다.

나중에는 window, global 대신 globalThis를 사용하세요! 라는 시대가 올 수도 있지 않을까도 싶다.

상식으로라도 이런게 있구나하고 알아둬서 나쁠 것은 없을 것 같다. 😇


그리고 왜 globalThis라는 이름의 식별자를 사용했는가에 대한 내용도 ECMAScript github에 있다.

읽다보면 꽤 재밌으니 심심하면 읽어보면 좋을 것 같다. 😊


참고