μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ globalThis의 μ†Œλ¦„λΌμΉ˜λŠ” 폴리필


원문: https://mathiasbynens.be/notes/globalthis

globalThis μ œμ•ˆμ€ λͺ¨λ“  μžλ°”μŠ€ν¬λ¦½νŠΈ ν™˜κ²½μ—μ„œ μ „μ—­ this에 μ ‘κ·Όν•  수 μžˆλŠ” λ©”μ»€λ‹ˆμ¦˜μ„ λ„μž…ν•œλ‹€. globalThis의 폴리필은 맀우 간단할 것 κ°™μ§€λ§Œ, μ •ν™•ν•˜κ²Œ λ§Œλ“€κΈ°λŠ” 맀우 μ–΄λ ΅λ‹€. Toon이 창쑰적인 ν•΄κ²°μ±…μœΌλ‘œ λ‚˜λ₯Ό κΉœμ§λ†€λž˜ν‚€κΈ° μ „κΉŒμ§€ λ‚˜λŠ” 그것이 κ°€λŠ₯ν•˜λ‹€κ³  생각쑰차 λͺ»ν–ˆλ‹€.

이 글은 globalThis의 μ μ ˆν•œ 폴리필 μž‘μ„±μ΄ μ–΄λ ΅λ‹€λŠ” 것을 μ„€λͺ…ν•œλ‹€. 폴리필은 μ•„λž˜μ˜ μš”κ΅¬μ‚¬ν•­μ„ λ”°λΌμ•Όν•œλ‹€.

  • λΈŒλΌμš°μ €, λΈŒλΌμš°μ €μ˜ μ›Œμ»€, λΈŒλΌμš°μ €μ˜ ν™•μž₯ν”„λ‘œκ·Έλž¨, Node.js 그리고 standalone(μ΄ν•˜ λ…λ¦½ν˜•) μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진 λ°”μ΄λ„ˆλ¦¬μ—μ„œ λͺ¨λ‘ λ™μž‘ν•΄μ•Ό ν•œλ‹€.
  • sloppy mode(μ΄ν•˜ λŠμŠ¨ν•œ λͺ¨λ“œ), strict mode(μ΄ν•˜ μ—„κ²©ν•œ λͺ¨λ“œ) 그리고 μžλ°”μŠ€ν¬λ¦½νŠΈ λͺ¨λ“ˆμ„ λͺ¨λ‘ 지원해야 ν•œλ‹€.
  • μ½”λ“œκ°€ μ‹€ν–‰λ˜λŠ” μ»¨ν…μŠ€νŠΈμ— 관계없이 λ™μž‘ν•΄μ•Ό ν•œλ‹€. (즉, λΉŒλ“œν•  λ•Œ 폴리필이 μ—„κ²©ν•œ λͺ¨λ“œμΈ ν•¨μˆ˜λ‘œ λž˜ν•‘ 된 κ²½μš°μ—λ„ μ •ν™•ν•˜κ²Œ λ™μž‘ν•΄μ•Ό ν•œλ‹€.)

μš©μ–΄

λ¨Όμ € μš©μ–΄μ— λŒ€ν•΄μ„œ μ •λ¦¬ν•˜κ² λ‹€. globalThisλŠ” μ „μ—­ μŠ€μ½”ν”„μ˜ this 값을 μ œκ³΅ν•œλ‹€. 이것은 λ³΅μž‘ν•œ 이유둜 λΈŒλΌμš°μ €μ˜ μ „μ—­ κ°μ²΄μ™€λŠ” λ‹€λ₯΄λ‹€.

μžλ°”μŠ€ν¬λ¦½νŠΈ λͺ¨λ“ˆμ—μ„œ λͺ¨λ“ˆ μŠ€μ½”ν”„λŠ” μ „μ—­ μŠ€μ½”ν”„μ™€ λ‹Ήμ‹ μ˜ μ½”λ“œ 사이에 κ°œμž…λ˜μ–΄ μžˆλ‹€λŠ” 점에 μœ μ˜ν•΄μ•Ό ν•œλ‹€. λͺ¨λ“ˆ μŠ€μ½”ν”„λŠ” κΈ€λ‘œλ²Œ μŠ€μ½”ν”„μ˜ thisλ₯Ό 숨기기 λ•Œλ¬Έμ— λͺ¨λ“ˆ μŠ€μ½”ν”„μ˜ μ΅œμƒλ‹¨μ—μ„œ thisλŠ” undefined이닀.

즉, globalThisλŠ” "μ „μ—­ 객체"κ°€ μ•„λ‹ˆλ©°, 단지 μ „μ—­ μŠ€μ½”ν”„μ˜ thisλ₯Ό μ˜λ―Έν•œλ‹€. 이 μ€‘μš”ν•œ λ‰˜μ•™μŠ€λ₯Ό μ΄ν•΄μ‹œμΌœμ€€ Domenicμ—κ²Œ κ°μ‚¬ν•œλ‹€.

globalThis의 λŒ€μ•ˆ

λΈŒλΌμš°μ €μ—μ„œ globalThis와 λ™μΌν•œ 것은 window이닀.

globalThis === window;
// β†’ true

frames도 λ™μΌν•˜κ²Œ λ™μž‘ν•œλ‹€.

globalThis === frames;
// β†’ true

ν•˜μ§€λ§Œ, window와 framesλŠ” (μ›Ή μ›Œμ»€μ™€ μ„œλΉ„μŠ€ μ›Œμ»€μ™€ 같은) μ›Œμ»€ μ»¨ν…μŠ€νŠΈ μ•ˆμ—μ„œ undefined이닀. 운 μ’‹κ²Œλ„ selfλŠ” λͺ¨λ“  λΈŒλΌμš°μ € μ»¨ν…μŠ€νŠΈμ—μ„œ λ™μž‘ν•˜λ―€λ‘œ 더 κ°•λ ₯ν•œ λŒ€μ•ˆμ΄λ‹€.

globalThis === self;
// β†’ true

Node.jsμ—μ„œλŠ” window, frames, self을 μ‚¬μš©ν•  수 μ—†μ§€λ§Œ, global을 μ‚¬μš©ν•  수 μžˆλ‹€.

globalThis === global;
// β†’ true

jsvu으둜 μ„€μΉ˜ν•˜λŠ” 것과 같은 λ…λ¦½ν˜• μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진 μ‰˜μ—μ„œλŠ” μœ„μ—μ„œ μ„€λͺ…ν•œ λͺ¨λ“  것(window, frames, self, global)을 μ‚¬μš©ν•  수 μ—†λ‹€. μ—¬κΈ°μ„œλŠ” μ „μ—­ this에 μ ‘κ·Όν•  수 μžˆλ‹€.

globalThis === this;
// β†’ true

κ²Œλ‹€κ°€ λŠμŠ¨ν•œ λͺ¨λ“œ ν•¨μˆ˜λŠ” κ·Έλ“€μ˜ thisλ₯Ό μ „μ—­ this둜 μ„€μ •ν•  수 있기 λ•Œλ¬Έμ—, μ½”λ“œλ₯Ό μ „μ—­ μŠ€μ½”ν”„μ—μ„œ μ‹€ν–‰ν•  수 없더라도 μ „μ—­ this에 μ ‘κ·Όν•  수 μžˆλ‹€.

globalThis === (function() {
	return this;
})();
// β†’ true

ν•˜μ§€λ§Œ, μžλ°”μŠ€ν¬λ¦½νŠΈ λͺ¨λ“ˆμ—μ„œ μ΅œμƒλ‹¨μ˜ thisλŠ” undefined이고, μ—„κ²©ν•œ λͺ¨λ“œμ˜ ν•¨μˆ˜μ•ˆμ—μ„œ thisλŠ” undefined이닀. κ·Έλž˜μ„œ 이 접근방법은 μ—¬κΈ°μ„œ λ™μž‘ν•˜μ§€ μ•ŠλŠ”λ‹€.

일단 μ—„κ²©ν•œ λͺ¨λ“œμ˜ μ»¨ν…μŠ€νŠΈ μ•ˆμ—μ„œ μž„μ‹œλ‘œ μ—„κ²©ν•œ λͺ¨λ“œλ₯Ό κΉ¨κ³  λ‚˜μ˜¬ 수 μžˆλŠ” 방법은 였직 ν•˜λ‚˜λ‹€. Function μƒμ„±μžλŠ” λŠμŠ¨ν•œ ν•¨μˆ˜λ₯Ό μƒμ„±ν•œλ‹€.

globalThis === Function('return this')();
// β†’ true

음, eval도 같은 효과λ₯Ό λ‚΄κΈ° λ•Œλ¬Έμ— 두 가지 방법이 μžˆλ‹€.

globalThis === (0, eval)('this');
// β†’ true

λΈŒλΌμš°μ €μ—μ„œ Function μƒμ„±μžμ™€ eval을 μ‚¬μš©ν•˜λŠ” 것은 컨텐츠 λ³΄μ•ˆ μ •μ±…(Content Security Policy (CSP))λ•Œλ¬Έμ— μ’…μ’… ν—ˆλ½λ˜μ§€ μ•ŠλŠ”λ‹€. μ›Ήμ‚¬μ΄νŠΈλŠ” μ’…μ’… 이런 정책을 μ˜΅μ…˜μœΌλ‘œ κ°€μ Έκ°€μ§€λ§Œ, 예λ₯Ό λ“€μ–΄ 크둬 ν™•μž₯ν”„λ‘œκ·Έλž¨ μ•ˆμ—μ„œλŠ” μ‹œν–‰ν•˜κ³  μžˆλ‹€. λΆˆν–‰ν•˜κ²Œλ„, 이것은 μ μ ˆν•œ 폴리필이 Function μƒμ„±μžμ™€ eval에 μ˜μ‘΄ν•  수 μ—†λ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€.

주의: setTimeout('globalThis = this', 0)λŠ” 같은 이유둜 μ œμ™Έλ˜μ—ˆλ‹€. κ²Œλ‹€κ°€ 일반적으둜 CSP에 μ˜ν•΄μ„œ λ§‰νžŒλ‹€. λ˜ν•œ setTimeout을 폴리필에 μ‚¬μš©ν•˜λŠ” 것에 λ°˜λŒ€ν•˜λŠ” μ΄μœ κ°€ 두 가지 더 μžˆλ‹€. 첫 λ²ˆμ§ΈλŠ” ECMAScript의 μŠ€νŽ™μ΄ μ•„λ‹ˆκ³  λͺ¨λ“  μžλ°”μŠ€ν¬λ¦½νŠΈ ν™˜κ²½μ—μ„œ μ‚¬μš©ν•  수 μ—†λ‹€. 두 λ²ˆμ§ΈλŠ” λΉ„λ™κΈ°μ μ΄μ–΄μ„œ setTimeout이 λͺ¨λ“ κ³³μ—μ„œ μ§€μ›λœλ‹€κ³  ν•˜λ”λΌλ„, λ‹€λ₯Έ μ½”λ“œμ— μ˜μ‘΄ν•˜λŠ” 폴리필을 μ‚¬μš©ν•˜λŠ” 것은 κ³ ν†΅μŠ€λŸ¬μšΈ 것이닀.

κ°„λ‹¨ν•œ 폴리필

μœ„μ˜ 기법듀을 κ²°ν•©ν•˜μ—¬ μ•„λž˜μ™€ 같이 ν•˜λ‚˜μ˜ 폴리필을 λ§Œλ“€ 수 μžˆλ‹€.

// λ„€μ΄ν‹°λΈŒ 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;
	if (typeof this !== 'undefined') return this;
	throw new Error('μ „μ—­ 객체λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€');
};
// 주의: μ „μ—­ μŠ€μ½”ν”„μ—μ„œ 싀행될 λ•Œ `globalThis`λ₯Ό μ „μ—­ 객체둜 λ§Œλ“€κΈ° μœ„ν•΄ 
// (μ–΄νœ˜μ (lexical) λ²”μœ„μ˜ μ΅œμƒλ‹¨ λ³€μˆ˜μ™€λŠ” λŒ€μ‘°μ μœΌλ‘œ)
// `const` λŒ€μ‹ μ— `var`λ₯Ό μ‚¬μš©ν–ˆλ‹€.
var globalThis = getGlobal();

ν•˜μ§€λ§Œ 이 μ½”λ“œλŠ” μ—„κ²©ν•œ λͺ¨λ“œμ˜ ν•¨μˆ˜λ‚˜ λΈŒλΌμš°μ €κ°€ μ•„λ‹Œ ν™˜κ²½μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ λͺ¨λ“ˆ μ•ˆμ—μ„œλŠ” λ™μž‘ν•˜μ§€ μ•ŠλŠ”λ‹€. (globalThisλ₯Ό μ§€μ›ν•˜λŠ” κ²½μš°λŠ” μ œμ™Έ). κ²Œλ‹€κ°€ getGlobal은 잘λͺ»λœ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•  수 μžˆλ‹€. μ™œλƒν•˜λ©΄ this에 μ˜μ§€ν•˜λŠ”λ°, thisλŠ” μ»¨ν…μŠ€νŠΈμ— 의쑴적이고 λ²ˆλ“€λŸ¬μ— μ˜ν•΄μ„œ 변경될 수 있기 λ•Œλ¬Έμ΄λ‹€.

κ°•λ ₯ν•œ 폴리필

globalThis의 κ°•λ ₯ν•œ 폴리필을 μž‘μ„±ν•  수 μžˆμ„κΉŒ? λ‹€μŒκ³Ό 같은 ν™˜κ²½μ΄ μžˆλ‹€κ³  κ°€μ •ν•΄λ³΄μž.

  • globalThis, window, self, global, this에 μ˜μ‘΄ν•  수 μ—†λ‹€.
  • Function μƒμ„±μžμ™€ eval을 μ‚¬μš©ν•  수 μ—†λ‹€.
  • ν•˜μ§€λ§Œ λ‹€λ₯Έ μžλ°”μŠ€ν¬λ¦½νŠΈ λ‚΄μž₯ κΈ°λŠ₯의 무결성에 μ˜μ‘΄ν•  μžˆλ‹€.

해결책은 μ°Ύμ•˜μ§€λ§Œ 방식이 μ•„λ¦„λ‹΅μ§€λŠ” μ•Šλ‹€. 이것에 λŒ€ν•΄μ„œ μž μ‹œ μƒκ°ν•΄λ³΄μž.

μ „μ—­ this에 직접 μ ‘κ·Όν•˜λŠ” 방법을 λͺ¨λ₯Έμ±„ μ „μ—­ this에 μ–΄λ–»κ²Œ μ ‘κ·Όν•  수 μžˆμ„κΉŒ? λ§Œμ•½ globalThis에 ν•¨μˆ˜ ν”„λ‘œνΌν‹°λ₯Ό μ–΄λ–»κ²Œλ“  μ§€μ •ν•˜κ³ , 그것을 globalThis의 ν•¨μˆ˜λ‘œμ¨ ν˜ΈμΆœν•œλ‹€λ©΄, κ·Έ ν•¨μˆ˜ μ•ˆμ—μ„œ thisλ₯Ό μ ‘κ·Όν•  수 μžˆλ‹€.

globalThis.foo = function() {
	return this;
};
var globalThisPolyfilled = globalThis.foo();

globalThisλ‚˜ globalThisλ₯Ό μ°Έμ‘°ν•˜λŠ” 바인딩 없이 μ–΄λ–»κ²Œ 그것이 κ°€λŠ₯ν•œκ°€? λ‹€μŒ μ½”λ“œλŠ” μ‹€ν–‰ ν•  수 μ—†λ‹€.

function foo() {
	return this;
}
var globalThisPolyfilled = foo();

foo()λŠ” 더 이상 ν•¨μˆ˜λ‘œ ν˜ΈμΆœλ˜μ–΄μ§ˆ 수 μ—†κ³ , λ˜ν•œ μœ„μ—μ„œ μ–ΈκΈ‰ν–ˆλ“―μ΄ μ—„κ²©ν•œ λͺ¨λ“œλ‚˜ μžλ°”μŠ€ν¬λ¦½νŠΈ λͺ¨λ“ˆμ—μ„œ 이 ν•¨μˆ˜ μ•ˆμ˜ thisλŠ” undefined이닀. μ—„κ²©ν•œ λͺ¨λ“œμ˜ ν•¨μˆ˜λŠ” κ·Έλ“€μ˜ thisλ₯Ό undefined둜 μ„€μ •ν•œλ‹€. ν•˜μ§€λ§Œ getter와 setter의 κ²½μš°λŠ” μ•„λ‹ˆλ‹€.

Object.defineProperty(globalThis, '__magic__', {
	get: function() {
		return this;
	},
	configurable: true // 이것은 λ‚˜μ€‘μ— getterλ₯Ό `delete` κ°€λŠ₯ν•˜κ²Œ ν•œλ‹€.
});
// 주의: μ „μ—­ μŠ€μ½”ν”„μ—μ„œ 싀행될 λ•Œ `globalThis`λ₯Ό μ „μ—­ 객체둜 λ§Œλ“€κΈ° μœ„ν•΄ 
// (μ–΄νœ˜μ (lexical) λ²”μœ„μ˜ μ΅œμƒλ‹¨ λ³€μˆ˜μ™€ λŒ€μ‘°μ μœΌλ‘œ)
// `const` λŒ€μ‹ μ— `var`κ°€ μ‚¬μš©λ˜μ–΄μ§„λ‹€.
var globalThisPolyfilled = __magic__;
delete globalThis.__magic__;

μœ„μ˜ μ½”λ“œμ—μ„œ globalThis에 getterλ₯Ό μ„€μ •ν•˜κ³  getterλ₯Ό ν†΅ν•΄μ„œ globalThis의 μ°Έμ‘°λ₯Ό κ°€μ €μ˜¨ λ‹€μŒ, 더이상 ν•„μš”μ—†λŠ” getterλŠ” μ‚­μ œν•œλ‹€. 이 기법은 μ›ν•˜λŠ” λͺ¨λ“  μƒν™©μ—μ„œ globalThis에 μ ‘κ·Όν•  수 μžˆμ§€λ§Œ, 첫 번째 λΌμΈμ—μ„œ μ—¬μ „νžˆ (μ—¬κΈ°μ„œλŠ” globalThis라고 λΆ€λ₯΄λŠ”) μ „μ—­ this 참쑰에 μ˜μ‘΄ν•˜κ³  μžˆλ‹€. 이 μ˜μ‘΄μ„±μ„ ν”Όν•  수 μžˆμ„ 까? globalThis에 직접 μ ‘κ·Όν•˜μ§€ μ•Šκ³  getterλ₯Ό μ „μ—­μ μœΌλ‘œ μ„€μ • ν•  수 μžˆμ„ 까?

globalThis에 getterλ₯Ό μ„€μ •ν•˜λŠ” 것 λŒ€μ‹ μ—, μ „μ—­ this 객체λ₯Ό Object.prototype으둜 μƒμ†λ°›μ•„μ„œ getterλ₯Ό μ„€μ •ν•  수 μžˆλ‹€.

Object.defineProperty(Object.prototype, '__magic__', {
	get: function() {
		return this;
	},
	configurable: true // 이것은 λ‚˜μ€‘μ— getterλ₯Ό `delete` κ°€λŠ₯ν•˜κ²Œ ν•œλ‹€.
});
// 주의: μ „μ—­ μŠ€μ½”ν”„μ—μ„œ 싀행될 λ•Œ `globalThis`λ₯Ό μ „μ—­ 객체둜 λ§Œλ“€κΈ° μœ„ν•΄ 
// (μ–΄νœ˜μ (lexical) λ²”μœ„μ˜ μ΅œμƒλ‹¨ λ³€μˆ˜μ™€ λŒ€μ‘°μ μœΌλ‘œ)
// `const` λŒ€μ‹ μ— `var`κ°€ μ‚¬μš©λ˜μ–΄μ§„λ‹€.
var globalThis = __magic__;
delete Object.prototype.__magic__;

주의: 사싀 ECMAScript μŠ€νŽ™μ— μ „μ—­ thisκ°€ Object.prototype을 상속 λ°›λŠ”λ‹€λŠ” λ‚΄μš©μ€ μ—†κ³ , 단지 객체여야 ν•œλ‹€κ³  λͺ…μ‹œλ˜μ–΄ μžˆλ‹€. Object.create(null)은 Object.prototype을 상속 받지 μ•Šμ€ 객체λ₯Ό λ§Œλ“ λ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진은 Object.prototypeλ₯Ό 상속받지 μ•ŠλŠ” 객체λ₯Ό this둜 μ‚¬μš©ν•˜λ”λΌλ„ μŠ€νŽ™μ— μœ„λ°°λ˜μ§€ μ•ŠμœΌλ©°, 이 경우 μœ„μ™€ 같은 μ½”λ“œλŠ” μ—¬μ „νžˆ λ™μž‘ν•˜μ§€ μ•Šμ„ 것이닀. (μ‹€μ œλ‘œ IE 7은 κ·Έλ ‡κ²Œ ν•œλ‹€.) 운 μ’‹κ²Œ, μ’€ 더 μ΅œμ‹ μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진은 μ „μ—­ thisκ°€ Object.prototype을 prototype 체인으둜 κ°€μ Έμ•Όλ§Œ ν•œλ‹€κ³  λ™μ˜ν•œ κ²ƒμœΌλ‘œ 보인닀.

globalThisλ₯Ό 이미 μ‚¬μš©ν•  수 μžˆλŠ” μ΅œμ‹ μ˜ ν™˜κ²½μ—μ„œλŠ” Object.prototypeκ°€ λ³€ν™”(mutating)ν•˜λŠ” 것을 막기 μœ„ν•΄μ„œ 폴리필을 μ•„λž˜μ™€ 같이 μˆ˜μ •ν•  수 μžˆλ‹€.

(function() {
	if (typeof globalThis === 'object') return;
	Object.defineProperty(Object.prototype, '__magic__', {
		get: function() {
			return this;
		},
		configurable: true // 이것은 λ‚˜μ€‘μ— getterλ₯Ό `delete` κ°€λŠ₯ν•˜κ²Œ ν•œλ‹€.
	});
	__magic__.globalThis = __magic__; // lolwat
	delete Object.prototype.__magic__;
}());

// 이제 μ½”λ“œμ—μ„œ `globalThis`λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.
console.log(globalThis);

ν˜Ήμ€ __defineGetter__λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

function() {
	if (typeof globalThis === 'object') return;
	Object.prototype.__defineGetter__('__magic__', function() {
		return this;
	});
	__magic__.globalThis = __magic__; // lolwat
	delete Object.prototype.__magic__;
}());

// 이제 μ½”λ“œμ—μ„œ `globalThis`λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.
console.log(globalThis);

이것은 μ§€κΈˆκΉŒμ§€ λ³Έ 폴리필 쀑 κ°€μž₯ λ”μ°ν•œ 것이닀. μ†Œμœ ν•˜μ§€ μ•Šμ€ 객체(object)λŠ” λ³€κ²½ν•˜μ§€ μ•ŠλŠ” 것이 관행인데, 이 폴리필은 이런 관행을 μ™„μ „νžˆ λ¬΄μ‹œν•œλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„μ˜ κΈ°λ³Έ 원리인 ν”„λ‘œν† νƒ€μž… μ΅œμ ν™”μ—μ„œ μ„€λͺ…ν•˜λ“―이 λ‚΄μž₯된 ν”„λ‘œν† νƒ€μž…μ„ λ³€κ²½ν•˜λŠ” 것은 일반적으둜 λ‚˜μœ 생각이닀.

λ°˜λ©΄μ— 이 폴리필을 깨뜨릴 μœ μΌν•œ 방법은 폴리필이 μ‹€ν–‰λ˜κΈ° 전에 λˆ„κ΅°κ°€κ°€ Object λ˜λŠ” Object.defineProperty (λ˜λŠ” Object.prototype.__defineGetter__)λ₯Ό λ³€κ²½ν•˜λŠ” 것이닀. λ‚˜λŠ” 이보닀 더 κ°•λ ₯ν•œ 폴리필을 생각해낼 수 μ—†λ‹€. μ—¬λŸ¬λΆ„μ€ μ–΄λ– ν•œκ°€?

폴리필 ν…ŒμŠ€νŠΈ

이 폴리필은 λ²”μš©μ μΈ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ ν₯미둜운 μ˜ˆμ΄λ‹€. 폴리필은 μˆœμˆ˜ν•œ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ‘œ 호슀트 빌트인 κΈ°λŠ₯에 μ˜μ‘΄ν•˜μ§€ μ•Šκ³  ECMAScriptκ°€ κ΅¬ν˜„λœ μ–΄λŠ ν™˜κ²½μ—μ„œλ‚˜ 싀행될 수 μžˆλ‹€. 이것은 μ• μ΄ˆμ— ν΄λ¦¬ν•„μ˜ λͺ©ν‘œ 쀑 ν•˜λ‚˜μ˜€λ‹€. μ‹€μ œλ‘œ 이것이 λ™μž‘ν•˜λŠ”μ§€ ν™•μΈν•΄λ³΄μž.

여기에 이 폴리필을 μœ„ν•œ HTML 데λͺ¨ νŽ˜μ΄μ§€κ°€ μžˆλ‹€. 이 데λͺ¨μ—μ„œλŠ” 고전적인 슀크립트인 globalthis.js와 λ™μΌν•œ μ½”λ“œλ‘œ λͺ¨λ“ˆλ°©μ‹μΈ globalthis.mjsλ₯Ό μ‚¬μš©ν•˜μ—¬ globalThisλ₯Ό 좜λ ₯ν•œλ‹€. 이 데λͺ¨λŠ” 폴리필이 λΈŒλΌμš°μ €μ—μ„œ λ™μž‘ν•˜λŠ”μ§€ ν™•μΈν•˜λŠ” 데 μ‚¬μš©λ  수 μžˆλ‹€. globalThisλŠ” 기본적으둜 Chrome 71 / V8 v7.1, Firefox 65, Safari 12.1, iOS Safari 12.2μ—μ„œ μ§€μ›ν•œλ‹€. ν΄λ¦¬ν•„μ˜ ν₯미둜운 뢀뢄을 ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄μ„œλŠ” 이전 λ²„μ „μ˜ λΈŒλΌμš°μ €μ—μ„œ 데λͺ¨νŽ˜μ΄μ§€λ₯Ό μ—΄μ–΄μ•Όν•œλ‹€.

주의: 이 폴리필은 인터넷 μ΅μŠ€ν”Œλ‘œλŸ¬ 10 μ΄ν•˜μ˜ λ²„μ „μ—μ„œλŠ” λ™μž‘ν•˜μ§€ μ•ŠλŠ”λ‹€. 이 λΈŒλΌμš°μ €λ“€μ—μ„œλŠ” __magic__이 μ „μ—­ this의 참쑰둜 λ™μž‘ν•¨μ—λ„ λΆˆκ΅¬ν•˜κ³ , __magic__.globalThis = __magic__으둜 μ–΄λ–»κ²Œλ“ μ§€ globalThisκ°€ μ „μ—­μœΌλ‘œ μ‚¬μš© κ°€λŠ₯ν•˜κ²Œ λ§Œλ“€μ–΄μ£Όμ§€ μ•ŠλŠ”λ‹€. 즉 __magic__κ³Ό windowκ°€ λͺ¨λ‘ [object Window]μ΄μ§€λ§Œ __magic__ !== window λΌλŠ” 사싀이닀. 이것은 이 λΈŒλΌμš°μ €λ“€μ΄ μ „μ—­ 객체와 μ „μ—­ this μ‚¬μ΄μ˜ 차이에 λŒ€ν•΄ 혼돈될 수 μžˆμŒμ„ λ‚˜νƒ€λ‚Έλ‹€. μ΄μ „μ˜ λŒ€μ•ˆλ“€ 쀑 ν•˜λ‚˜λ‘œ 폴리필을 μˆ˜μ •ν•˜λ©΄ IE10κ³Ό IE 9μ—μ„œ λ™μž‘ν•œλ‹€. IE 8을 μ§€μ›ν•˜κΈ° μœ„ν•΄μ„œλŠ” Object.defineProperty ν˜ΈμΆœν•˜λŠ” 뢀뢄을 try-catch문으둜 감싸고 catch λΈ”λ‘μ—μ„œ μ΄μ „μ˜ λŒ€μ•ˆλ“€ 쀑 ν•˜λ‚˜λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€. (μ΄λ ‡κ²Œ ν•˜λŠ” 것은 μ „μ—­ thisκ°€ Object.prototype을 상속 받지 μ•ŠλŠ” IE 7 이슈 λ˜ν•œ ν”Όν•  수 μžˆλ‹€. IE의 μ΄μ „λ²„μ „μ—μ„œ 이 데λͺ¨λ₯Ό μ‹€ν–‰μ‹œμΌœ 보아라)

Node.js와 λ…λ¦½ν˜• μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„μ—μ„œ ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄μ„œλŠ” λ™μΌν•œ μžλ°”μŠ€ν¬λ¦½νŠΈ νŒŒμΌμ„ λ‹€μš΄λ‘œλ“œ ν•œλ‹€.

# 폴리필과 데λͺ¨ μ½”λ“œλ₯Ό λͺ¨λ“ˆλ‘œ λ‹€μš΄λ‘œλ“œ 해라
curl https://mathiasbynens.be/demo/globalthis.mjs > globalthis.mjs
# 이 νŒŒμΌμ„ 고전적인 μžλ°”μŠ€ν¬λ¦½νŠΈ 파일둜 μ‚¬μš©ν•  수 μžˆλ„λ‘ 볡사(즉, symlink) 해라
ln -s globalthis.mjs globalthis.js

이제 nodeμ—μ„œ ν…ŒμŠ€νŠΈν•  수 μžˆλ‹€.

$ node --experimental-modules --no-warnings globalthis.mjs
Testing the polyfill in a module
[object global]

$ node globalthis.js
Testing the polyfill in a classic script
[object global]

λ…λ¦½ν˜• μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진 μ‰˜μ—μ„œ ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄μ„œλŠ” jsvuλ₯Ό μ‚¬μš©ν•΄μ„œ μ›ν•˜λŠ” 엔진을 μ„€μΉ˜ν•˜κ³  슀크립트λ₯Ό λ°”λ‘œ μ‹€ν–‰ν•  수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄ (globalThisλ₯Ό μ§€μ›ν•˜μ§€ μ•ŠλŠ”) V8의 7.0버전과 (globalThisλ₯Ό μ§€μ›ν•˜λŠ”) 7.1λ²„μ „μ—μ„œ ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄μ„œλŠ” μ•„λž˜μ™€ 같이 ν•˜λ©΄λœλ‹€.

$ jsvu v8@7.0 # Install the `v8-7.0.276` binary.

$ v8-7.0.276 globalthis.mjs
Testing the polyfill in a module
[object global]

$ v8-7.0.276 globalthis.js
Testing the polyfill in a classic script
[object global]

$ jsvu v8@7.1 # Install the `v8-7.1.302` binary.

$ v8-7.1.302 globalthis.js
Testing the polyfill in a classic script
[object global]

$ v8-7.1.302 globalthis.mjs
Testing the polyfill in a module
[object global]

이와 같은 기술둜 JavaScriptCore, SpiderMonkey, Chakra 그리고 XS와 같은 λ‹€λ₯Έ μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„μ—μ„œ ν…ŒμŠ€νŠΈν•  수 μžˆλ‹€. μ—¬κΈ° JavaScriptCoreλ₯Ό μ‚¬μš©ν•œ μ˜ˆμ œκ°€ μžˆλ‹€.

$ jsvu # Install the `javascriptcore` binary.

$ javascriptcore globalthis.mjs
Testing the polyfill in a module
[object global]

$ javascriptcore globalthis.js
Testing the polyfill in a classic script
[object global]

κ²°λ‘ 

μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•˜λŠ” 것은 κΉŒλ‹€λ‘­κ³ , μ’…μ’… 독창적인 방법을 μš”κ΅¬ν•œλ‹€. globalThisλŠ” μ „μ—­ this에 μ‰½κ²Œ μ ‘κ·Όν•  수 있게 ν•΄μ€€λ‹€. μ •ν™•ν•˜κ²Œ λ™μž‘ν•˜λŠ” globalThis 폴리필은 보기보단 μ’€ 더 λ„μ „μ μ΄μ§€λ§Œ, λ™μž‘ν•˜λŠ” 해결책이 μžˆλ‹€.

μ •λ§λ‘œ ν•„μš”ν•  λ•Œλ§Œ 이 폴리필을 μ‚¬μš©ν•΄λΌ. μžλ°”μŠ€ν¬λ¦½νŠΈ λͺ¨λ“ˆμ€ μ „μ—­ μƒνƒœλ₯Ό λ³€κ²½ν•˜μ§€ μ•Šκ³  κΈ°λŠ₯을 μ‰½κ²Œ κ°€μ Έμ˜€κ±°λ‚˜ 내보낼 수 μžˆλ‹€. λŒ€λΆ€λΆ„μ˜ μ΅œμ‹  μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλŠ” μ „μ—­ this에 접근을 ν•„μš”λ‘œ ν•˜μ§€ μ•ŠλŠ”λ‹€. globalThisλŠ” λΌμ΄λΈŒλŸ¬λ¦¬μ™€ ν΄λ¦¬ν•„μ—μ„œλ§Œ μœ μš©ν•˜λ‹€.

npm에 μžˆλŠ” globalThis 폴리필

이 글을 κ²Œμ‹œν•œ 이후에 λ‹€μŒκ³Ό 같은 npm νŒ¨ν‚€μ§€κ°€ 이 κΈ°μˆ μ„ μ΄μš©ν•΄μ„œ globalThis 폴리필을 μ œκ³΅ν•˜κΈ° μ‹œμž‘ν–ˆλ‹€.

μ°Έκ³ : λ‚˜λŠ” 이 νŒ¨ν‚€μ§€λ“€ 쀑 μ–΄λ– ν•œ κ²ƒμ˜ μ €μžλ„ κ΄€λ¦¬μžλ„ μ•„λ‹ˆλ‹€.

μ΄μ†Œν¬2019.05.03
Back to list