globalThis 폴리필로 보는 자바스크립트 모든 환경에서 this 접근

각 환경마다 전역 객체에 접근하는 방식이 달라 개발자들을 괴롭혔는데요. 이런 문제를 해결하기 위해 es2020에 등장한 것이 바로 globalThis입니다.

기존 환경의 복잡성

아래 환경들을 고려해야하는 모든 환경을 지원하기 위해서는 생각보다 까다로운데요.

실행 환경

  • 브라우저

  • 브라우저 워커(Web Worker, Service Worker)

  • 브라우저 확장 프로그램

  • Node.js

  • 자바스크립트 엔진(V8, Webkit)

실행 모드

  • sloppy mode

  • strict mode

  • 자바스크립트 모듈

globalThis의 등장

globalThis는 전역 스코프의 this 값을 일관되게 제공합니다.

실행 환경별 globalThis의 동작

브라우저

globalThis === window    // true
globalThis === frames    // true
globalThis === self      // true

웹 워커

// window, frames는 워커에서 사용 불가
globalThis === self      // true

Node.js

globalThis === global    // true

자바스크립트 엔진

// window, frames, self, global 사용 불가
globalThis === this      // true

실행 모드별 globalThis의 동작

모듈 스코프는 글로벌 스코프의 this를 숨기기 때문에 최상단에서 thisundefined가 됩니다

console.log(this);        // undefined
console.log(globalThis);  // 전역 객체

strict mode에서도 마찬가지로 함수 내부의 thisundefined가 됩니다.

globalThis이전 솔루션

// Function 생성자 활용
globalThis === Function('return this')();

// eval 사용
var global = eval('this');

브라우저의 CSP(Content Security Policy)와 같이 eval()을 비활성화하는 환경에서는 사용할 수 없었습니다.

globalThis 폴리필

직접 구현

const getGlobal = () => {
    if (typeof globalThis !== 'undefined') return globalThis;
    if (typeof self !== 'undefined') return self;
    if (typeof window !== 'undefined') return window;
    if (typeof global !== 'undefined') return global;
    throw new Error('전역 객체를 찾을 수 없습니다');
};

라이브러리 속 구현

// core-js (https://github.com/zloirock/core-js)
'use strict';
var check = function (it) {
  return it && it.Math === Math && it;
};

// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
module.exports =
  // eslint-disable-next-line es/no-global-this -- safe
  check(typeof globalThis == 'object' && globalThis) ||
  check(typeof window == 'object' && window) ||
  // eslint-disable-next-line no-restricted-globals -- safe
  check(typeof self == 'object' && self) ||
  check(typeof global == 'object' && global) ||
  check(typeof this == 'object' && this) ||
  // eslint-disable-next-line no-new-func -- fallback
  (function () { return this; })() || Function('return this')();


// @ungap/global-this (https://github.com/ungap/global-this)
(function (Object) {
  typeof globalThis !== 'object' && (
    this ?
      get() :
      (Object.defineProperty(Object.prototype, '_T_', {
        configurable: true,
        get: get
      }), _T_)
  );
  function get() {
    var global = this || self;
    global.globalThis = global;
    delete Object.prototype._T_;
  }
}(Object));

마무리

globalThis는 자바스크립트의 복잡한 환경 차이를 해결하는 최적의 솔루션이라고 생각합니다. 만약 레거시 환경을 지원해야 한다면 폴리필을 사용해야겠지만, 가능하다면 globalThis를 사용하는 것이 가장 안전할 것 같습니다.

참고

Last updated