Modern Javascript Deep Dive - 22์žฅ this

1. this ํ‚ค์›Œ๋“œ

๋ฉ”์„œ๋“œ๊ฐ€ ์ž์‹ ์ด ์†ํ•œ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐธ์กฐํ•˜๋ ค๋ฉด ๋จผ์ € ์ž์‹ ์ด ์†ํ•œ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์‹๋ณ„์ž๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์–ด์•ผํ•œ๋‹ค.

const circle = {
  // ํ”„๋กœํผํ‹ฐ: ๊ฐ์ฒด ๊ณ ์œ ์˜ ์ƒํƒœ ๋ฐ์ดํ„ฐ
  radius: 5,
  // ๋ฉ”์„œ๋“œ: ์ƒํƒœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋™์ž‘
  getDiameter() {
    // ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ์ž์‹ ์ด ์†ํ•œ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋‚˜ ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋ฅผ ์ฐธ์กฐํ•˜๋ ค๋ฉด
    // ์ž์‹ ์ด ์†ํ•œ ๊ฐ์ฒด์ธ circle์„ ์ฐธ์กฐ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    return 2 * circle.radius;
  },
};

console.log(circle.getDiameter()); // 10

์œ„ ์˜ˆ์ œ์˜ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์€ circle ๋ณ€์ˆ˜์— ํ• ๋‹น๋˜๊ธฐ ์ง์ „์— ํ‰๊ฐ€๋œ๋‹ค.

โ†’ getDiameter() ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์—๋Š” ์ด๋ฏธ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์˜ ํ‰๊ฐ€๊ฐ€ ์™„๋ฃŒ๋˜์–ด ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๊ณ  circle ์‹๋ณ„์ž์— ์ƒ์„ฑ๋œ ๊ฐ์ฒด๊ฐ€ ํ• ๋‹น๋œ ์ดํ›„๋‹ค.

โ†’ ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ circle ์‹๋ณ„์ž๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ž๊ธฐ ์ž์‹ ์ด ์†ํ•œ ๊ฐ์ฒด๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ์ฐธ์กฐํ•˜๋Š” ๋ฐฉ์‹์€ ์ผ๋ฐ˜์ ์ด์ง€ ์•Š์œผ๋ฉฐ ๋ฐ”๋žŒ์งํ•˜์ง€๋„ ์•Š๋‹ค.

function Circle(radius) {
	// ์ด ์‹œ์ ์—๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ์ž์‹ ์ด ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์‹๋ณ„์ž๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค.
	????.radius = radius;
}

Circle.prototype.getDiameter = function () {
	// ์ด์‹œ์ ์—๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ์ž์‹ ์ด ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์‹๋ณ„์ž๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค.
	return 2 * ????.radius;
}

// ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด ๋จผ์ € ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.
const circle = new Circle(5);

์ƒ์„ฑ์ž ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ๋Š” ํ”„๋กœํผํ‹ฐ ๋˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์ž์‹ ์ด ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์ƒ์„ฑ์ž ํ•จ์ˆ˜์— ์˜ํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ์‹์€ ๋จผ์ € ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•œ ์ดํ›„ new ์—ฐ์‚ฐ์ž์™€ ํ•จ๊ป˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋‹จ๊ณ„๊ฐ€ ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•˜๋‹ค.

โ†’ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด ๋จผ์ € ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค.

this๋Š” ์ž์‹ ์ด ์†ํ•œ ๊ฐ์ฒด ๋˜๋Š” ์ž์‹ ์ด ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ž๊ธฐ ์ฐธ์กฐ ๋ณ€์ˆ˜๋‹ค. this๋ฅผ ํ†ตํ•ด ์ž์‹ ์ด ์†ํ•œ ๊ฐ์ฒด ๋˜๋Š” ์ž์‹ ์ด ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค์˜ ํ”„๋กœํผํ‹ฐ๋‚˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

this๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์— ์˜ํ•ด ์•”๋ฌต์ ์œผ๋กœ ์ƒ์„ฑ๋˜๋ฉฐ, ์ฝ”๋“œ ์–ด๋””์„œ๋“  ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

โ†’ this๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ’, ์ฆ‰ this ๋ฐ”์ธ๋”ฉ์€ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ฐฉ์‹์— ์˜ํ•ด ๋™์ ์œผ๋กœ ๊ฒฐ์ •๋œ๋‹ค.

// ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด
const circle = {
  radius: 5,
  getDiameter() {
    // this๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
    return 2 * this.radius;
  },
}

console.log(circle.getDiameter()); // 10
// ์ƒ์„ฑ์ž ํ•จ์ˆ˜
function Circle(radius) {
  // this๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
  this.radius = radius;
}

Circle.prototype.getDiameter = function() {
  // this๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
  return 2 * this.radius;
}

// ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
const circle = new Circle(5);
console.log(circle.getDiameter()); // 10

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ this๋Š” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๋ฐฉ์‹์— ๋”ฐ๋ผ this์— ๋ฐ”์ธ๋”ฉ๋  ๊ฐ’, ์ฆ‰ this ๋ฐ”์ธ๋”ฉ์ด ๋™์ ์œผ๋กœ ๊ฒฐ์ •๋œ๋‹ค.

this๋Š” ์ฝ”๋“œ ์–ด๋””์„œ๋“ ์ง€ ์ฐธ์กฐ ๊ฐ€๋Šฅํ•˜๋‹ค.

// this๋Š” ์–ด๋””์„œ๋“ ์ง€ ์ฐธ์กฐ ๊ฐ€๋Šฅํ•˜๋‹ค.
// ์ „์—ญ์—์„œ this๋Š” ์ „์—ญ ๊ฐ์ฒด window๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
console.log(this); // window

function square(number) {
  // ์ผ๋ฐ˜ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ this๋Š” ์ „์—ญ ๊ฐ์ฒด window๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
  console.log(this); // window
  return number * number;
}
square(2);

const person = {
  name: 'Son',
  getName() {
    // ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ this๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
    console.log(this); // {name: "Son", getName: function}
    return this.name;
  },
}
console.log(person.getName()); // Son

function Person(name) {
  this.name = name;
  // ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ this๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
  console.log(this); // Person {name: "Son"}
}

const me = new Person('Son');

2. ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ฐฉ์‹๊ณผ this ๋ฐ”์ธ๋”ฉ

this ๋ฐ”์ธ๋”ฉ(this์— ๋ฐ”์ธ๋”ฉ ๊ฐ’)์€ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ฐฉ์‹, ์ฆ‰ ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ป๊ฒŒ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ๊ฒฐ์ •๋œ๋‹ค.

ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹

  • ์ผ๋ฐ˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ
  • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
  • ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ํ˜ธ์ถœ
  • Function.prototype.apply/call/bind ๋ฉ”์„œ๋“œ์— ์˜ํ•œ ๊ฐ„์ ‘ ํ˜ธ์ถœ
// this ๋ฐ”์ธ๋”ฉ์€ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ๊ฒฐ์ •๋œ๋‹ค.
const foo = function() {
  console.dir(this);
}

// 1. ์ผ๋ฐ˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ
foo(); // window

// 2. ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
const obj = { foo };
obj.foo();

// 3. ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ํ˜ธ์ถœ
new foo(); // foo {}

// 4. Function.prototype.apply/call/bind ๋ฉ”์„œ๋“œ์— ์˜ํ•œ ๊ฐ„์ ‘ ํ˜ธ์ถœ
const bar = { name: 'bar' };
foo.call(bar); // bar
foo.apply(bar); // bar
foo.bind(bar)(); // bar

2.1 ์ผ๋ฐ˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ

๊ธฐ๋ณธ์ ์œผ๋กœ this์—๋Š” ์ „์—ญ ๊ฐ์ฒด ๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.

function foo() {
  console.log("foo's this: ", this); // window
  function bar() {
    console.log("bar's this: ", this); // window
  }
  bar();
}
foo();

์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœํ•˜๋ฉด ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this์—๋Š” ์ „์—ญ ๊ฐ์ฒด๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.

this๋Š” ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋‚˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ž๊ธฐ ์ฐธ์กฐ ๋ณ€์ˆ˜์ด๋ฏ€๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜์—์„œ this๋Š” ์˜๋ฏธ๊ฐ€ ์—†๋‹ค. โ†’ strict mode๊ฐ€ ์ ์šฉ๋œ ์ผ๋ฐ˜ ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this์—๋Š” undefined๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.

function foo() {
  'use strict';

  console.log("foo's this: ", this); // undefined
  function bar() {
    console.log("bar's this: ", this); // undefined
  }
  bar();
}
foo();
// var ํ‚ค์›Œ๋“œ๋กœ ์„ ์–ธํ•œ ์ „์—ญ ๋ณ€์ˆ˜ value๋Š” ์ „์—ญ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋‹ค.
var value = 1;
// const ํ‚ค์›Œ๋“œ๋กœ ์„ ์–ธํ•œ ์ „์—ญ ๋ณ€์ˆ˜ value๋Š” ์ „์—ญ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์•„๋‹ˆ๋‹ค.
// const value = 1;

const obj = {
  value: 100,
  foo() {
    console.log("foo's this: ", this); // {value: 100, foo: function}
    console.log("foo's this.value: ", this.value); // 100

    // ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ์ •์˜ํ•œ ์ค‘์ฒฉ ํ•จ์ˆ˜
    function bar() {
      console.log("bar's this: ", this); // window
      console.log("bar's this.value: ", this.value); // 1
    }

    // ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ์ •์˜ํ•œ ์ค‘์ฒฉ ํ•จ์ˆ˜๋„ ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ๋˜๋ฉด ์ค‘์ฒฉ ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this์—๋Š”
    // ์ „์—ญ ๊ฐ์ฒด๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.
    bar();
  },
};

obj.foo();

์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ๋œ๋‹ค๋ฉด ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this์—๋„ ์ „์—ญ ๊ฐ์ฒด๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.

์–ด๋– ํ•œ ํ•จ์ˆ˜๋ผ๋„ ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ๋˜๋ฉด this์— ์ „์—ญ ๊ฐ์ฒด๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.

var value = 1;

const obj = {
  value: 100,
  foo() {
    console.log("foo's this: ", this); // {value: 100, foo: function}

    // ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this์—๋Š” ์ „์—ญ ๊ฐ์ฒด๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.
    setTimeout(function bar() {
      console.log("bar's this: ", this); // window
      console.log("bar's this.value: ", this.value); // 1
    }, 100);
  },
}

obj.foo();

์ด์ฒ˜๋Ÿผ ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ๋œ ๋ชจ๋“  ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this์—๋Š” ์ „์—ญ ๊ฐ์ฒด๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.

๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์˜ ์ค‘์ฒฉ ํ•จ์ˆ˜๋‚˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ this ๋ฐ”์ธ๋”ฉ์„ ๋ฉ”์„œ๋“œ์˜ this ๋ฐ”์ธ๋”ฉ๊ณผ ์ผ์น˜์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

var value = 1;

const obj = {
  value: 100,
  foo() {
    // this ๋ฐ”์ธ๋”ฉ(obj)์„ ๋ณ€์ˆ˜ that์— ํ• ๋‹นํ•œ๋‹ค.
    const that = this;

    // ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this์—๋Š” that์„ ๋ฐ”์ธ๋”ฉํ•œ๋‹ค.
    setTimeout(function bar() {
      console.log(that.value); // 100
    }, 100);
  },
}

obj.foo();
var value = 1;

const obj = {
  value: 100,
  foo() {
    // ์ฝœ๋ฐฑ ํ•จ์ˆ˜์— ๋ช…์‹œ์ ์œผ๋กœ this๋ฅผ ๋ฐ”์ธ๋”ฉํ•œ๋‹ค.
    setTimeout(
      function bar() {
        console.log(this.value) // 100
      }.bind(this), 100)
  },
}

obj.foo();

๋˜๋Š” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ this ๋ฐ”์ธ๋”ฉ์„ ์ผ์น˜์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ๋‹ค.

var value = 1;

const obj = {
  value: 100,
  foo() {
    // ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this๋Š” ์ƒ์œ„ ์Šค์ฝ”ํ”„์˜ this๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
    setTimeout(() => console.log(this.value), 100); // 100
  },
}

obj.foo();

2.2 ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ

๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์˜ this์—๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด, ์ฆ‰ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์•ž์˜ ๋งˆ์นจํ‘œ(.) ์—ฐ์‚ฐ์ž ์•ž์— ๊ธฐ์ˆ ํ•œ ๊ฐ์ฒด๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.

๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์˜ this๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์†Œ์œ ํ•œ ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด์— ๋ฐ”์ธ๋”ฉ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

const person = {
  name: 'Son',
  getName() {
    // ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์˜ this๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด์— ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.
    return this.name;
  },
}

// ๋ฉ”์„œ๋“œ getName์„ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด๋Š” person์ด๋‹ค.
console.log(person.getName()); // Son

โ†’ getName ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•จ์ˆ˜ ๊ฐ์ฒด, ์ฆ‰ getName ๋ฉ”์„œ๋“œ๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ์— ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๋  ์ˆ˜๋„ ์žˆ๊ณ  ์ผ๋ฐ˜ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜์—ฌ ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ๋  ์ˆ˜๋„ ์žˆ๋‹ค.

const anotherPerson = {
  name: 'Son',
};
// getName ๋ฉ”์„œ๋“œ๋ฅผ anotherPerson ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๋กœ ํ• ๋‹น
anotherPerson.getName = persongetName;

// getName ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด๋Š” anotherPerson์ด๋‹ค.
console.log(anotherPerson.getName()); // Son

// getName ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ€์ˆ˜์— ํ• ๋‹น
const getName = person.getName;

// getName ๋ฉ”์„œ๋“œ๋ฅผ ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ
console.log(getName()); // ""
// ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ๋œ getName ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this.name์€ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์—์„œ window.name๊ณผ ๊ฐ™๋‹ค.

ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋œ this๋„ ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด์— ๋ฐ”์ธ๋”ฉ ๋œ๋‹ค.

function Person(name) {
  this.name = name;
}

Person.prototype.getName = function() {
  return this.name;
}

const me = new Person('Son');

// getName ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด๋Š” me๋‹ค.
console.log(me.getName()); // Son

Person.prototype.name = 'Sonny';

// getName ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด๋Š” Person.prototype์ด๋‹ค.
console.log(Person.prototype.getName()); // Sonny

2.3 ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ํ˜ธ์ถœ

์ƒ์„ฑ์ž ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this์—๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.

// ์ƒ์„ฑ์ž ํ•จ์ˆ˜
function Circle(radius) {
  // ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑํ•  ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
  this.radius = radius;
  this.getDiameter = function() {
    return 2 * this.radius;
  }
}

const circle1 = new Circle(5);
const circle2 = new Circle(10);

console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 20

// new ์—ฐ์‚ฐ์ž์™€ ํ•จ๊ป˜ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.
const circle3 = Circle(15);

// ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ๋œ Circle์—๋Š” ๋ฐ˜ํ™˜๋ฌธ์ด ์—†์œผ๋ฏ€๋กœ ์•”๋ฌต์ ์œผ๋กœ undefined๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
console.log(circle3); // undefined

// ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ๋œ Circle ๋‚ด๋ถ€์˜ this๋Š” ์ „์—ญ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
console.log(radius); // 15

2.4 Function.prototype.apply/call/bind ๋ฉ”์„œ๋“œ์— ์˜ํ•œ ๊ฐ„์ ‘ ํ˜ธ์ถœ

apply, call ๋ฉ”์„œ๋“œ๋Š” this๋กœ ์‚ฌ์šฉํ•  ๊ฐ์ฒด์™€ ์ธ์ˆ˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์•„ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

function getThisBinding() {
  return this;
}

// this๋กœ ์‚ฌ์šฉํ•  ๊ฐ์ฒด
const thisArg = { a: 1 };

console.log(getThisBinding()); // window

// getThisBinding ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•œ ๊ฐ์ฒด๋ฅผ getThisBinding ํ•จ์ˆ˜์˜ this์— ๋ฐ”์ธ๋”ฉํžŒ๋‹ค.
console.log(getThisBinding.apply(thisArg)); // {a: 1}
console.log(getThisBinding.call(thisArg)); // {a: 1}

apply์™€ call ๋ฉ”์„œ๋“œ์˜ ๋ณธ์งˆ์ ์ธ ๊ธฐ๋Šฅ์€ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

apply์™€ call ๋ฉ”์„œ๋“œ๋Š” ํ˜ธ์ถœํ•  ํ•จ์ˆ˜์— ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹๋งŒ ๋‹ค๋ฅผ ๋ฟ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.

function getThisBinding() {
  console.log(arguments);
  return this;
}

// this๋กœ ์‚ฌ์šฉํ•  ๊ฐ์ฒด
const thisArg = { a: 1 };

// apply ๋ฉ”์„œ๋“œ๋Š” ํ˜ธ์ถœํ•  ํ•จ์ˆ˜์˜ ์ธ์ˆ˜๋ฅผ ๋ฐฐ์—ด๋กœ ๋ฌถ์–ด ์ „๋‹ฌํ•œ๋‹ค.
console.log(getThisBinding.apply(thisArg, [1, 2, 3]));

// call ๋ฉ”์„œ๋“œ๋Š” ํ˜ธ์ถœํ•  ํ•จ์ˆ˜์˜ ์ธ์ˆ˜๋ฅผ ๋ฐฐ์—ด๋กœ ๋ฌถ์–ด ์ „๋‹ฌํ•œ๋‹ค.
console.log(getThisBinding.call(thisArg, 1, 2, 3));

// [Arguments] { '0': 1, '1': 2, '2': 3 }
// { a: 1 }
// [Arguments] { '0': 1, '1': 2, '2': 3 }
// { a: 1 }

apply์™€ call ๋ฉ”์„œ๋“œ์˜ ๋Œ€ํ‘œ์ ์ธ ์šฉ๋„๋Š” arguments ๊ฐ์ฒด์™€ ๊ฐ™์€ ์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด์— ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋‹ค. arguments ๊ฐ์ฒด๋Š” ๋ฐฐ์—ด์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— Array.prototype.slice ๊ฐ™์€ ๋ฐฐ์—ด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋‚˜ apply์™€ call ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ๊ฐ€๋Šฅํ•˜๋‹ค.

function convertArgsToArray() {
  console.log(arguments);

  // Array.prototype.slice๋ฅผ ์ธ์ˆ˜ ์—†์ด ํ˜ธ์ถœํ•˜๋ฉด ๋ฐฐ์—ด์˜ ๋ณต์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•œ๋‹ค.
  const arr = Array.prototype.slice.call(arguments);
  // const arr = Array.prototype.slice.apply(arguments);
  console.log(arr);

  return arr;
}

convertArgsToArray(1, 2, 3); // [1, 2, 3]

Function.prototype.bind ๋ฉ”์„œ๋“œ๋Š” apply์™€ call ๋ฉ”์„œ๋“œ์™€ ๋‹ฌ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  this๋กœ ์‚ฌ์šฉํ•  ๊ฐ์ฒด๋งŒ ์ „๋‹ฌํ•œ๋‹ค.

function getThisBinding() {
  return this;
}

// this๋กœ ์‚ฌ์šฉํ•  ๊ฐ์ฒด
const thisArg = { a: 1 };

// bind ๋ฉ”์„œ๋“œ๋Š” ํ•จ์ˆ˜์— this๋กœ ์‚ฌ์šฉํ•  ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.
// bind ๋ฉ”์„œ๋“œ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.
console.log(getThisBinding.bind(thisArg));
// bind ๋ฉ”์„œ๋“œ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์ง€๋Š” ์•Š์œผ๋ฏ€๋กœ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.
console.log(getThisBinding.bind(thisArg)());

// [Function: bound getThisBinding]
// { a: 1 }
const person = {
  name: 'Son',
  foo(callback) {
    setTimeout(callback, 100);
  },
}

person.foo(function() {
  console.log(`Hi! my name is ${this.name}.`); // Hi! my name is .
});

binding ํ•˜์ง€ ์•Š์œผ๋ฉด person.foo์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ this.name ์€ window.name ๊ณผ ๊ฐ™๋‹ค.

const person = {
  name: 'Son',
  foo(callback) {
    // bind ๋ฉ”์„œ๋“œ๋กœ callback ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ this ๋ฐ”์ธ๋”ฉ์„ ์ „๋‹ฌ
    setTimeout(callback.bind(this), 100);
  },
}

person.foo(function() {
  console.log(`Hi! my name is ${this.name}.`); // Hi! my name is Son.
});

Written by@Sunny Son
๊ฐœ๋ฐœ์ž๋Š” ์˜ค๋Š˜๋„ ๋š ๋š 

GitHubFacebook