[TECH-QA] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ this์™€ ๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ (call, apply, bind)

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ this์˜ ๊ฐ’์€ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ๊ฒฐ์ •๋˜๋ฉฐ, ํ˜ธ์ถœ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ์ฃผ์š” ๊ฒฝ์šฐ์™€ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ „์—ญ ์ปจํ…์ŠคํŠธ์—์„œ์˜ this

ํ•จ์ˆ˜๊ฐ€ ์ „์—ญ ์Šค์ฝ”ํ”„์—์„œ ํ˜ธ์ถœ๋  ๋•Œ, this๋Š” ์ „์—ญ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” window, Node.js์—์„œ๋Š” global์ž…๋‹ˆ๋‹ค.
console.log(this); // ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰ ์‹œ: Window ๊ฐ์ฒด

function sayHello() {
  console.log(this);
}
sayHello(); // Window ๊ฐ์ฒด (์ „์—ญ ํ˜ธ์ถœ)
"use strict" ๋ชจ๋“œ์—์„œ๋Š” ์ „์—ญ ํ˜ธ์ถœ ์‹œ this๊ฐ€ undefined๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
"use strict";

function sayThis() {
  console.log(this);
}

sayThis(); // undefined

๊ฐ์ฒด ๋ฉ”์„œ๋“œ์—์„œ์˜ this

ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ์ผ๋•Œ, this๋Š” ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.
const person = {
  name: "Alice",
  greet: function() {
    console.log(this.name);
  }
};

person.greet(); // "Alice" (this๋Š” person ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ด)
ํ•˜์ง€๋งŒ ํ•จ์ˆ˜๋ฅผ ๊ฐ์ฒด์—์„œ ๋ถ„๋ฆฌํ•ด ํ˜ธ์ถœํ•˜๋ฉด this๊ฐ€ ๊ฐ์ฒด๋ฅผ ์žƒ์–ด๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.
const person = {
  name: "Hannah",
  sayName: function() {
    console.log(this.name);
  }
};

const func = person.sayName;
func(); // undefined (this๋Š” ์ „์—ญ ๊ฐ์ฒด Window๋ฅผ ๊ฐ€๋ฆฌํ‚ด)

๋‚ด๋ถ€ ํ•จ์ˆ˜์—์„œ์˜ this ๋ฌธ์ œ

์ผ๋ฐ˜ ํ•จ์ˆ˜ ์•ˆ์— ๋˜ ๋‹ค๋ฅธ ์ผ๋ฐ˜ ํ•จ์ˆ˜๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ, ๋‚ด๋ถ€ ํ•จ์ˆ˜์˜ this๋Š” ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ this๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์†ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
const obj = {
  name: "Kate",
  outer: function() {
    console.log(this.name); //Kate
    function inner() {
      console.log(this.name); //undefined (this๋Š” Window)
    }
    inner();
  }
};

obj.outer();
// ์ถœ๋ ฅ:
// Outer this: Kate
// Inner this: undefined (this๋Š” Window)

๐Ÿ“ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

๊ฐ์ฒด ๋ฉ”์„œ๋“œ์—์„œ์˜ this๋ฅผ ๋ณ€์ˆ˜์— ์ €์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
const obj = {
  name: "Kate",
  outer: function() {
    const self = this;
    function inner() {
      console.log(self.name); // Inner this: Kate
    }
    inner();
  }
};

obj.outer(); // Inner this: Kate
๊ฐ์ฒด ๋ฉ”์„œ๋“œ์—์„œ์˜ this๋ฅผ ์‚ฌ์šฉํ• ์ˆ˜ ์žˆ๋Š” bind() ์‚ฌ์šฉ๋ฒ•
const obj = {
  name: "Kate",
  outer: function() {
    const inner = function() {
      console.log(this.name);
    }.bind(this);
    inner();
  }
};

obj.outer(); // Inner this: Kate

์ƒ์„ฑ์ž ํ•จ์ˆ˜์—์„œ์˜ this

new ํ‚ค์›Œ๋“œ๋กœ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, this๋Š” ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.
function Car(model) {
  this.model = model;
}

const myCar = new Car("Tesla");

console.log(myCar.model); // "Tesla"

๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ (call, apply, bind)

call, apply, bind๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด this๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ call ์˜ˆ์ œ

function introduce(age) {
  console.log(this.name, age);
}

const user = { name: "Bob" };

introduce.call(user, 25); // "Bob, 25"

๐Ÿ“ apply ์˜ˆ์ œ

function introduce(age) {
  console.log(this.name, age);
}

const user = { name: "Bob" };

introduce.apply(user, [30]); // "Bob 30"

ํ˜ธ์ถœ ์‹œ์ ์— this๋ฅผ ๋™์ ์œผ๋กœ ๊ฒฐ์ •ํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ๋Š” call์ด๋‚˜ apply๊ฐ€ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ bind ์˜ˆ์ œ

function introduce(age) {
  console.log(this.name, age);
}

const user = { name: "Bob" };

const boundIntroduce = introduce.bind(user);

boundIntroduce(35); // "Bob 35"

๐Ÿ“ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜์—์„œ์˜ this(๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…)

const obj = {
  name: "Charlie",
  sayName: function() {
    const arrowFunc = () => console.log(this.name);
    arrowFunc();
  }
};

obj.sayName(); // "Charlie" (this๋Š” obj๋ฅผ ๊ฐ€๋ฆฌํ‚ด)
ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋Š” this๋ฅผ lexical scope(์ •์  ๋ฒ”์œ„)์—์„œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ์ฆ‰, ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋œ ์œ„์น˜์˜ ์ƒ์œ„ ์Šค์ฝ”ํ”„์—์„œ this๋ฅผ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค.

๐Ÿ“ ์ผ๋ฐ˜ ํ•จ์ˆ˜(์™ธ๋ถ€ ์Šค์ฝ”ํ”„์˜ this๋ฅผ ์ €์žฅ)

const obj2 = {
  name: "David",
  sayName: function() {
    const self = this;
    const normalFunc = function() {
      console.log(self.name);
    };
    normalFunc();
  }
};

obj2.sayName(); // "David"
self ๋ณ€์ˆ˜์— ์™ธ๋ถ€ ์Šค์ฝ”ํ”„์˜ this๋ฅผ ์ €์žฅํ•˜์—ฌ ๋‚ด๋ถ€ ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ์„ธ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, "David"๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ํ˜„๋Œ€์ ์ด๊ณ  ๊ฐ„๊ฒฐํ•œ ์ ‘๊ทผ๋ฒ•์€ ์ฒซ ๋ฒˆ์งธ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
  • ํ™”์‚ดํ‘œ ํ•จ์ˆ˜: ๊ฐ„๊ฒฐํ•˜๊ณ  ์ง๊ด€์ 
  • bind(): ๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ ํ•„์š” ์‹œ
  • self ๋ณ€์ˆ˜: ์˜ค๋ž˜๋œ ์ฝ”๋“œ์™€์˜ ํ˜ธํ™˜์„ฑ์ด๋‚˜ ํŠน์ • ์ƒํ™ฉ์—์„œ

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ์˜ this

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋กœ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด, this๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ DOM ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.
document.querySelector("button").addEventListener("click", function() {
  console.log(this); // <button> ์š”์†Œ
});

ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ์˜ this

document.querySelector("button").addEventListener("click", () => {
  console.log(this); // Window ๊ฐ์ฒด (์ƒ์œ„ ์Šค์ฝ”ํ”„์˜ this)
});

๊ฒฐ๊ณผ์ ์œผ๋กœ

  • ์ „์—ญ ํ˜ธ์ถœ: window (strict ๋ชจ๋“œ์—์„œ๋Š” undefined).
  • ๊ฐ์ฒด ๋ฉ”์„œ๋“œ: ํ˜ธ์ถœํ•œ ๊ฐ์ฒด.
  • ๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ: call, apply, bind๋กœ ์ง€์ •ํ•œ ๊ฐ์ฒด.
  • ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ: ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ ์š”์†Œ.
  • ์ƒ์„ฑ์ž ํ•จ์ˆ˜: ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๊ฐ์ฒด.
  • ๋‚ด๋ถ€ ํ•จ์ˆ˜: ํ˜ธ์ถœ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๊ฒฐ์ • (๋ณดํ†ต ์ „์—ญ ๊ฐ์ฒด).
์ผ๋ฐ˜ ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ ๋ฐฉ์‹์— ๋”ฐ๋ผ this๊ฐ€ ์œ ์—ฐํ•˜๊ฒŒ ๋ณ€ํ•œ๋‹ค๋Š” ์ ์—์„œ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜์™€ ๋Œ€๋น„๋ฉ๋‹ˆ๋‹ค. ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋Š” ์ƒ์œ„ ์Šค์ฝ”ํ”„์˜ this๋ฅผ ๊ณ ์ •์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์ผ๋ฐ˜ ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ ์‹œ์ ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋ฏ€๋กœ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์งˆ๋ฌธ์ด ์žˆ์œผ๋ฉด ๋ง์”€ํ•ด์ฃผ์„ธ์š”!