πŸ“© μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ this

thumb_hyeokΒ·2022λ…„ 3μ›” 2일
0

🟑 JavaScript

λͺ©λ‘ 보기
4/15
post-thumbnail

πŸ€” thisλŠ” 뭘까?

thisλŠ” μžμ‹ μ΄ μ†ν•œ 객체 λ˜λŠ” μžμ‹ μ΄ 생성할 μΈμŠ€ν„΄μŠ€λ₯Ό κ°€λ¦¬ν‚€λŠ” 자기 μ°Έμ‘° λ³€μˆ˜(self-referencing variable)λ‹€. λ‹€λ₯Έ μ–Έμ–΄μ˜ thisμ™€λŠ” 달리 μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ thisλŠ” μ–΄λ””μ„œλ“  μ‚¬μš©ν•  수 μžˆλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ thisλŠ” μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλ₯Ό 생성할 λ•Œ ν•¨κ»˜ κ²°μ •λœλ‹€. μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•Œ μƒμ„±λ˜λ―€λ‘œ, thisλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•Œ κ²°μ •λœλ‹€κ³  ν•  수 μžˆλ‹€. ν•¨μˆ˜λ₯Ό μ–΄λ–€ λ°©μ‹μœΌλ‘œ ν˜ΈμΆœν•˜λŠλƒμ— 따라 값이 달라진닀. μ•„λž˜μ—μ„œ μžμ„Ένžˆ μ‚΄νŽ΄λ³΄μž.


πŸ“ž ν˜ΈμΆœλ°©μ‹μ— 따라 λ‹¬λΌμ§€λŠ” this 바인딩

μ „μ—­μ—μ„œμ˜ this

λ‹€λ₯Έ 언어와 달리 μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ thisλŠ” μ–΄λ””μ„œλ“  μ‚¬μš©ν•  수 μžˆλ‹€κ³  ν–ˆλ‹€. μ „μ—­μ—μ„œλ„ thisλ₯Ό μ°Έμ‘°ν•  수 μžˆλŠ”λ° μ „μ—­μ—μ„œ thisλ₯Ό ν˜ΈμΆœν•˜λ©΄ thisμ—λŠ” μ „μ—­ 객체가 λ°”μΈλ”©λœλ‹€.

μ—¬κΈ°μ„œ λ°”μΈλ”©μ˜ 의미λ₯Ό μž μ‹œ μ„€λͺ…ν•˜κ³  κ°€κ² λ‹€.

λ°”μΈλ”©μ΄λž€ μ‹λ³„μžμ™€ 값을 μ—°κ²°ν•˜λŠ” 과정을 μ˜λ―Έν•œλ‹€. 예λ₯Ό λ“€μ–΄, λ³€μˆ˜ 선언은 λ³€μˆ˜ 이름(μ‹λ³„μž)κ³Ό ν™•λ³΄λœ λ©”λͺ¨λ¦¬ κ³΅κ°„μ˜ μ£Όμ†Œλ₯Ό λ°”μΈλ”©ν•˜λŠ” 것이닀.

this 바인딩은 this와 thisκ°€ 가리킬 객체λ₯Ό λ°”μΈλ”©ν•˜λŠ” 것이닀. (thisλŠ” ν‚€μ›Œλ“œλ‘œ λΆ„λ₯˜λ˜μ§€λ§Œ μ‹λ³„μž 역할을 ν•œλ‹€)

this에 μ „μ—­ 객체가 λ°”μΈλ”©λœλ‹€ === thisκ°€ μ „μ—­ 객체λ₯Ό 가리킨닀.

console.log(this); //undefined

thisλŠ” 객체의 ν”„λ‘œνΌν‹°λ‚˜ λ©”μ„œλ“œλ₯Ό μ°Έμ‘°ν•˜κΈ° μœ„ν•œ 자기 μ°Έμ‘° λ³€μˆ˜μ΄λ―€λ‘œ 일반적으둜 객체의 λ©”μ„œλ“œ, μƒμ„±μž ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œλ§Œ μ˜λ―Έκ°€ μžˆλ‹€. μ „μ—­κ³΅κ°„μ΄λ‚˜ 일반 ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ thisλ₯Ό μ°Έμ‘°ν•˜λ©΄ 엄격 λͺ¨λ“œ(strict mode)μ—μ„œλŠ” undefinedκ°€ λ°”μΈλ”©λœλ‹€. μ΄λŠ” ESLint 등을 μ‚¬μš©ν•΄λ„ λ§ˆμ°¬κ°€μ§€λ‹€. μ „μ—­κ³΅κ°„μ΄λ‚˜, 일반 ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ thisλ₯Ό μ‚¬μš©ν•  ν•„μš”κ°€ μ—†κΈ° λ•Œλ¬Έμ΄λ‹€.


일반 ν•¨μˆ˜λ‘œ 호좜될 λ•Œ ν•¨μˆ˜ λ‚΄μ—μ„œμ˜ this

thisλŠ” ν˜ΈμΆœν•œ 주체의 정보λ₯Ό λ‹΄λŠ”λ‹€. μ–΄λ–€ ν•¨μˆ˜λ₯Ό ν•¨μˆ˜λ‘œμ¨ ν˜ΈμΆœν•  κ²½μš°μ—” thisκ°€ μ§€μ •λ˜μ§€ μ•ŠλŠ”λ‹€. 그런데 ν•¨μˆ˜λ‘œμ¨ ν˜ΈμΆœν•˜λŠ” 것은 호좜 주체λ₯Ό λͺ…μ‹œν•˜μ§€ μ•Šκ³  κ°œλ°œμžκ°€ μ½”λ“œμ— 직접 κ΄€μ—¬ν•΄μ„œ μ‹€ν–‰ν•œ 것이기 λ•Œλ¬Έμ— 호좜 주체의 정보λ₯Ό μ•Œ 수 μ—†λŠ” 것이닀. μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ˜ ν™œμ„±ν™” λ‹Ήμ‹œμ— thisκ°€ μ§€μ •λ˜μ§€ μ•Šμ€ 경우 thisμ—λŠ” μ „μ—­ 객체가 λ°”μΈλ”©λœλ‹€. λ”°λΌμ„œ ν•¨μˆ˜μ—μ„œμ˜ thisλŠ” μ „μ—­ 객체λ₯Ό 가리킨닀.

ν•˜μ§€λ§Œ μœ„μ—μ„œ λ§ν–ˆλ“―μ΄ 엄격 λͺ¨λ“œλ‚˜ ESLint 등을 μ‚¬μš©ν•  경우 μ „μ—­ κ°μ²΄μ—λŠ” undefinedκ°€ λ°”μΈλ”©λœλ‹€.

function foo() {
  console.log(this); //undefined
}
foo();

일반 ν•¨μˆ˜λ‘œ 호좜된 λͺ¨λ“  ν•¨μˆ˜(μ€‘μ²©ν•¨μˆ˜λ‚˜ 콜백 ν•¨μˆ˜ 포함) λ‚΄λΆ€μ˜ thisμ—λŠ” μ „μ—­ 객체가 λ°”μΈλ”©λœλ‹€. 참고둜 λΈŒλΌμš°μ € ν™˜κ²½μ—μ„œ μ „μ—­ κ°μ²΄λŠ” window, Node.JS ν™˜κ²½μ—μ„œλŠ” global이닀.


λ©”μ„œλ“œλ‘œ 호좜될 λ•Œ λ©”μ„œλ“œ λ‚΄μ—μ„œμ˜ this

λ©”μ„œλ“œλ‘œ 호좜될 λ•Œ, λ©”μ„œλ“œ λ‚΄λΆ€ thisμ—λŠ” λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ 객체가 λ°”μΈλ”©λœλ‹€. 점 ν‘œκΈ°λ²•μ˜ 경우 λ§ˆμ§€λ§‰ 점 μ•žμ— λͺ…μ‹œλœ 객체가 곧 thisκ°€ λ˜λŠ” 것이닀. 여기에 μ£Όμ˜ν•΄μ•Όν•  점이 ν•˜λ‚˜ μžˆλŠ”λ°, thisλŠ” λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•œ 객체가 μ•„λ‹Œ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ 객체에 λ°”μΈλ”©λœλ‹€λŠ” 점이닀.

λ©”μ„œλ“œλŠ” ν”„λ‘œνΌν‹°μ— λ°”μΈλ”©λœ ν•¨μˆ˜λ‹€.
λ§Œμ•½ Person 객체의 λ©”μ„œλ“œλ‘œ getNameμ΄λΌλŠ” λ©”μ„œλ“œκ°€ μžˆλ‹€κ³  ν–ˆμ„ λ•Œ, getName ν”„λ‘œνΌν‹°κ°€ κ°€λ¦¬ν‚€λŠ” ν•¨μˆ˜ κ°μ²΄λŠ” Person 객체에 ν¬ν•¨λœ 것이 μ•„λ‹ˆλΌ λ…λ¦½μ μœΌλ‘œ μ‘΄μž¬ν•˜λŠ” λ³„λ„μ˜ 객체이닀. κ·Έμ € getName ν”„λ‘œνΌν‹°κ°€ ν•¨μˆ˜ 객체λ₯Ό 가리킀고 μžˆμ„ 뿐이닀.

λ”°λΌμ„œ getName ν”„λ‘œνΌν‹°κ°€ κ°€λ¦¬ν‚€λŠ” ν•¨μˆ˜ 객체, getName λ©”μ„œλ“œλŠ” λ‹€λ₯Έ 객체의 ν”„λ‘œνΌν‹°μ— ν• λ‹Ήν•˜λŠ” κ²ƒμœΌλ‘œ λ‹€λ₯Έ 객체의 λ©”μ„œλ“œκ°€ 될 μˆ˜λ„ 있고 일반 λ³€μˆ˜μ— ν• λ‹Ήν•˜μ—¬ 일반 ν•¨μˆ˜λ‘œ 호좜될 μˆ˜λ„ μžˆλ‹€.


μ½œλ°±ν•¨μˆ˜λ‘œ 호좜될 λ•Œ μ½œλ°±ν•¨μˆ˜ λ‚΄μ—μ„œμ˜ this

μ½œλ°±ν•¨μˆ˜λ‘œ ν•¨μˆ˜κ°€ 호좜될 λ•ŒλŠ” μ½œλ°±ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œ ν•¨μˆ˜μ˜ λ‚΄λΆ€ λ‘œμ§μ—μ„œ μ •ν•œ κ·œμΉ™μ— 따라 값이 κ²°μ •λœλ‹€. μ½œλ°±ν•¨μˆ˜λ„ ν•¨μˆ˜μ΄κΈ° λ•Œλ¬Έμ— 기본적으둜 this에 μ „μ—­ 객체가 λ°”μΈλ”©λ˜μ§€λ§Œ, μ½œλ°±ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œ ν•¨μˆ˜κ°€ λ³„λ„λ‘œ μ½œλ°±ν•¨μˆ˜μ— thisκ°€ 될 λŒ€μƒμ„ μ§€μ •ν•œ κ²½μš°μ—λŠ” κ·Έ λŒ€μƒμ΄ λ°”μΈλ”©λœλ‹€.
μ˜ˆμ‹œ μ½”λ“œλ₯Ό 톡해 ν•œ 번 μ‚΄νŽ΄λ³΄μž.

setTimeOut(function () {
  console.log(this); //window
}, 300);

const $ = (selector) => document.querySelector(selector);
$('#app').addEventListener('click', function (e) {
  console.log(this); //app
});

setTimeOut ν•¨μˆ˜λŠ” thisκ°€ 될 λŒ€μƒμ„ λ”°λ‘œ μ§€μ •ν•˜μ§€ μ•ŠλŠ”λ‹€. thisμ—λŠ” 전역객체가 λ°”μΈλ”©λœλ‹€.
addEventListner λ©”μ„œλ“œλŠ” μžμ‹ μ˜ thisλ₯Ό μƒμ†ν•˜λ„λ‘ μ •μ˜λΌ μžˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ, λ©”μ„œλ“œ λͺ…μ˜ (.) μ•žλΆ€λΆ„μ΄ this에 λ°”μΈλ”©λ˜λŠ” 것이닀.


μƒμ„±μž ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œμ˜ this

μƒμ„±μž ν•¨μˆ˜ λ‚΄λΆ€μ˜ thisμ—λŠ” μƒμ„±μž ν•¨μˆ˜κ°€ 생성할 μΈμŠ€ν„΄μŠ€κ°€ λ°”μΈλ”©λœλ‹€.

const Crew = function (name, age) {
  this.name = name;
  this.age = age;
}

const harry = new Crew('Harry', 23);

console.log(harry); //Crew { name: 'Harry', age: 23 }

κ·ΈλŸ¬ν•˜λ‹€.


ν™”μ‚΄ν‘œ ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œμ˜ this

ES6λΆ€ν„° ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ thisκ°€ 전역객체λ₯Ό κ°€λ¦¬ν‚€λŠ” 문제λ₯Ό λ³΄μ™„ν•˜κ³ μž, ν™”μ‚΄ν‘œ ν•¨μˆ˜κ°€ μΆ”κ°€λ˜μ—ˆλ‹€. ν™”μ‚΄ν‘œ ν•¨μˆ˜λŠ” μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλ₯Ό 생성할 λ•Œ this 바인딩 κ³Όμ • μžμ²΄κ°€ λΉ μ§€κ²Œ λ˜μ–΄, μƒμœ„ μŠ€μ½”ν”„μ˜ thisλ₯Ό κ·ΈλŒ€λ‘œ ν™œμš©ν•  수 μžˆλ‹€. μ•„λž˜μ—μ„œ λ‚˜μ˜¬ call, apply, bind λ“±μ˜ λ°©λ²•μœΌλ‘œλ„ ν™”μ‚΄ν‘œ ν•¨μˆ˜μ˜ thisλ₯Ό μ˜€λ²„λΌμ΄λ”©ν•  수 μ—†λ‹€.

즉, ν™”μ‚΄ν‘œ ν•¨μˆ˜ λ‚΄λΆ€μ˜ thisλŠ” 무쑰건 μƒμœ„ μŠ€μ½”ν”„μ˜ this와 κ°™λ‹€.


🏷️ λͺ…μ‹œμ  this 바인딩

call λ©”μ„œλ“œ

Function.prototype.call(thisArg[, arg1[, arg2[, ...]]])

call λ©”μ„œλ“œλŠ” λ©”μ„œλ“œμ˜ 호좜 주체인 ν•¨μˆ˜λ₯Ό μ¦‰μ‹œ μ‹€ν–‰ν•˜λ„λ‘ ν•˜λŠ” λ©”μ„œλ“œμ΄λ‹€. μ΄λ•Œ call λ©”μ„œλ“œμ˜ 첫 번째 인자λ₯Ό this둜 λ°”μΈλ”©ν•˜κ³  μ΄ν›„μ˜ μΈμžλ“€μ„ ν˜ΈμΆœν•  ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ‘œ ν•œλ‹€.

const func = function (a, b, c) {
  console.log(this, a, b, c); 
}

console.log(func(1, 2, 3)); // window{ ... } 1 2 3
console.log(func.call({ x: 1 }, 4, 5, 6}; // { x: 1} 4 5 6

apply λ©”μ„œλ“œ

Function.prototype.apply(thisArg[, argsArray])

applyλ©”μ„œλ“œλŠ” callλ©”μ„œλ“œμ™€ κΈ°λŠ₯μ μœΌλ‘œλŠ” μ™„μ „νžˆ λ™μΌν•˜λ‹€. κ·ΈλŸ¬λ‚˜ applyλ©”μ„œλ“œλŠ” 두 번째 인자λ₯Ό λ°°μ—΄λ‘œ λ°›μ•„ κ·Έ λ°°μ—΄μ˜ μš”μ†Œλ“€μ„ ν˜ΈμΆœν•  ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ‘œ μ§€μ •ν•œλ‹€λŠ” μ μ—μ„œλ§Œ 차이가 μžˆλ‹€.

const func = function (a, b, c) {
  console.log(this, a, b, c); 
}

console.log(func(1, 2, 3)); // window{ ... } 1 2 3
console.log(func.apply({ x: 1 }, [4, 5, 6]}; // { x: 1} 4 5 6

bind λ©”μ„œλ“œ

Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]])

bind λ©”μ„œλ“œλŠ” ES5에 μΆ”κ°€λœ λ©”μ„œλ“œλ‘œ, call λ©”μ„œλ“œμ™€ μœ μ‚¬ν•˜κΈ΄ ν•˜μ§€λ§Œ, ν•¨μˆ˜λ₯Ό μ¦‰μ‹œ ν˜ΈμΆœν•˜μ§€ μ•Šκ³ , λ„˜κ²¨ 받은 this 및 μΈμˆ˜λ“€μ„ λ°”νƒ•μœΌλ‘œ μƒˆλ‘œμš΄ ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•˜κΈ°λ§Œ ν•˜λŠ” λ©”μ„œλ“œμ΄λ‹€.

νŠΉμ΄ν•œ 점은 bind λ©”μ„œλ“œλ‘œ μƒˆλ‘œ λ§Œλ“  ν•¨μˆ˜λŠ” name ν”„λ‘œνΌν‹°μ— "bound"λΌλŠ” 접두어가 λΆ™λŠ”λ‹€λŠ” 것이닀. 이λ₯Ό 톡해 callμ΄λ‚˜ apply보닀 μ½”λ“œλ₯Ό μΆ”μ ν•˜κΈ°μ— μˆ˜μ›”ν•΄μ§„ 면이 μžˆλ‹€.

const func = function() {
  console.log(this); 
}

const bindFunc = func.bind({ x: 1 });

console.log(func); // window{ ... }
console.log(bindFunc); // { x: 1} 

console.log(func.name); // func
console.log(bindFunc.name); // bound func

🧐 정리

  • μ „μ—­μ—μ„œμ˜ this -> μ „μ—­ 객체

  • 일반 ν•¨μˆ˜ ν˜ΈμΆœμ—μ„œμ˜ this -> μ „μ—­ 객체

  • λ©”μ„œλ“œ ν˜ΈμΆœμ—μ„œμ˜ this -> λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ 주체

  • μƒμ„±μž ν•¨μˆ˜ ν˜ΈμΆœμ—μ„œμ˜ this -> μƒμ„±μž ν•¨μˆ˜κ°€ 생성할 μΈμŠ€ν„΄μŠ€

  • ν™”μ‚΄ν‘œ ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œμ˜ this -> μƒμœ„μŠ€μ½”ν”„μ˜ this

  • call/apply/bind λ©”μ„œλ“œμ— μ˜ν•œ ν˜ΈμΆœμ—μ„œμ˜ this
    -> apply/call/bind λ©”μ„œλ“œμ— 첫 번째 인수둜 μ „λ‹¬ν•œ 객체


πŸ“– 참고자료

  • μ½”μ–΄ μžλ°”μŠ€ν¬λ¦½νŠΈ

      1. this (65p~93p)
  • λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive

      1. this (342p~354p)
  • YOU DON'T KNOW JS

      1. thisλΌλ‚˜ λ­λΌλ‚˜ (29p~37p)
      1. thisκ°€ 이런 거둜ꡰ! (40p~64p)
profile
μš°μ•„ν•œν…Œν¬μ½”μŠ€ 4κΈ° μ›Ή ν”„λ‘ νŠΈμ—”λ“œ

1개의 λŒ“κΈ€

comment-user-thumbnail
2022λ…„ 3μ›” 4일

good

λ‹΅κΈ€ 달기