๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

[Medium] ๐Ÿ“„ this Binding

1. What is this in JavaScript?โ€‹

JavaScript์—์„œ this๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?

this๋Š” JavaScript์˜ ํ‚ค์›Œ๋“œ๋กœ, ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋  ๋•Œ์˜ ์ปจํ…์ŠคํŠธ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. this์˜ ๊ฐ’์€ ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ป๊ฒŒ ํ˜ธ์ถœ๋˜๋Š”์ง€์— ๋”ฐ๋ผ ๊ฒฐ์ •๋˜๋ฉฐ, ์–ด๋””์—์„œ ์ •์˜๋˜์—ˆ๋Š”์ง€์™€๋Š” ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

this์˜ ๋ฐ”์ธ๋”ฉ ๊ทœ์น™โ€‹

JavaScript์—์„œ this์˜ ๋ฐ”์ธ๋”ฉ์—๋Š” ๋„ค ๊ฐ€์ง€ ๊ทœ์น™์ด ์žˆ์Šต๋‹ˆ๋‹ค(์šฐ์„ ์ˆœ์œ„ ๋†’์€ ์ˆœ):

  1. new ๋ฐ”์ธ๋”ฉ: new ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ
  2. ๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ: call, apply, bind๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ this๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •
  3. ์•”์‹œ์  ๋ฐ”์ธ๋”ฉ: ๊ฐ์ฒด ๋ฉ”์„œ๋“œ๋กœ ํ˜ธ์ถœ
  4. ๊ธฐ๋ณธ ๋ฐ”์ธ๋”ฉ: ๊ธฐํƒ€ ์ƒํ™ฉ์—์„œ์˜ ๊ธฐ๋ณธ ๋™์ž‘

2. Please explain the difference of this in different contextsโ€‹

์„œ๋กœ ๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ์—์„œ this์˜ ์ฐจ์ด๋ฅผ ์„ค๋ช…ํ•ด ์ฃผ์„ธ์š”

1. ์ „์—ญ ํ™˜๊ฒฝ์—์„œ์˜ thisโ€‹

console.log(this); // ๋ธŒ๋ผ์šฐ์ €: window, Node.js: global

function globalFunction() {
console.log(this); // ๋น„์—„๊ฒฉ ๋ชจ๋“œ: window/global, ์—„๊ฒฉ ๋ชจ๋“œ: undefined
}

globalFunction();
'use strict';

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

strictFunction();

2. ์ผ๋ฐ˜ ํ•จ์ˆ˜(Function)์—์„œ์˜ thisโ€‹

์ผ๋ฐ˜ ํ•จ์ˆ˜์˜ this๋Š” ํ˜ธ์ถœ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค:

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

// ์ง์ ‘ ํ˜ธ์ถœ: this๋Š” ์ „์—ญ ๊ฐ์ฒด(๋น„์—„๊ฒฉ ๋ชจ๋“œ) ๋˜๋Š” undefined(์—„๊ฒฉ ๋ชจ๋“œ)๋ฅผ ๊ฐ€๋ฆฌํ‚ด
regularFunction(); // window (๋น„์—„๊ฒฉ ๋ชจ๋“œ) ๋˜๋Š” undefined (์—„๊ฒฉ ๋ชจ๋“œ)

// ๊ฐ์ฒด ๋ฉ”์„œ๋“œ๋กœ ํ˜ธ์ถœ: this๋Š” ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ด
const obj = {
method: regularFunction,
};
obj.method(); // obj

// call/apply/bind ์‚ฌ์šฉ: this๋Š” ์ง€์ •๋œ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ด
const customObj = { name: 'Custom' };
regularFunction.call(customObj); // customObj

3. ํ™”์‚ดํ‘œ ํ•จ์ˆ˜(Arrow Function)์—์„œ์˜ thisโ€‹

ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋Š” ์ž์ฒด this๋ฅผ ๊ฐ€์ง€์ง€ ์•Š์œผ๋ฉฐ, ์™ธ๋ถ€ ์Šค์ฝ”ํ”„์˜ this๋ฅผ ์ƒ์†ํ•ฉ๋‹ˆ๋‹ค(๋ ‰์‹œ์ปฌ ์Šค์ฝ”ํ”„).

const obj = {
name: 'Object',

// ์ผ๋ฐ˜ ํ•จ์ˆ˜
regularMethod: function () {
console.log('regularMethod this:', this); // obj

// ๋‚ด๋ถ€ ์ผ๋ฐ˜ ํ•จ์ˆ˜: this๊ฐ€ ๋ณ€๊ฒฝ๋จ
function innerRegular() {
console.log('innerRegular this:', this); // window/undefined
}
innerRegular();

// ๋‚ด๋ถ€ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜: this๋Š” ์™ธ๋ถ€์—์„œ ์ƒ์†
const innerArrow = () => {
console.log('innerArrow this:', this); // obj
};
innerArrow();
},

// ํ™”์‚ดํ‘œ ํ•จ์ˆ˜
arrowMethod: () => {
console.log('arrowMethod this:', this); // window(์ „์—ญ์—์„œ ์ƒ์†)
},
};

obj.regularMethod();
obj.arrowMethod();

4. ๊ฐ์ฒด ๋ฉ”์„œ๋“œ์—์„œ์˜ thisโ€‹

const person = {
name: 'John',
age: 30,

// ์ผ๋ฐ˜ ํ•จ์ˆ˜: this๋Š” person์„ ๊ฐ€๋ฆฌํ‚ด
greet: function () {
console.log(`Hello, I'm ${this.name}`); // "Hello, I'm John"
},

// ES6 ์ถ•์•ฝ ๋ฉ”์„œ๋“œ: this๋Š” person์„ ๊ฐ€๋ฆฌํ‚ด
introduce() {
console.log(`I'm ${this.name}, ${this.age} years old`);
},

// ํ™”์‚ดํ‘œ ํ•จ์ˆ˜: this๋Š” ์™ธ๋ถ€(์—ฌ๊ธฐ์„œ๋Š” ์ „์—ญ)์—์„œ ์ƒ์†
arrowGreet: () => {
console.log(`Hello, I'm ${this.name}`); // "Hello, I'm undefined"
},
};

person.greet(); // "Hello, I'm John"
person.introduce(); // "I'm John, 30 years old"
person.arrowGreet(); // "Hello, I'm undefined"

5. ์ƒ์„ฑ์ž ํ•จ์ˆ˜์—์„œ์˜ thisโ€‹

function Person(name, age) {
this.name = name;
this.age = age;

this.greet = function () {
console.log(`Hello, I'm ${this.name}`);
};
}

const john = new Person('John', 30);
john.greet(); // "Hello, I'm John"
console.log(john.name); // "John"

6. Class์—์„œ์˜ thisโ€‹

class Person {
constructor(name) {
this.name = name;
}

// ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ: this๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ด
greet() {
console.log(`Hello, I'm ${this.name}`);
}

// ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ์†์„ฑ: this๋Š” ์ธ์Šคํ„ด์Šค์— ๋ฐ”์ธ๋”ฉ๋จ
arrowGreet = () => {
console.log(`Hi, I'm ${this.name}`);
};
}

const john = new Person('John');
john.greet(); // "Hello, I'm John"

// ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜๋ฉด this ๋ฐ”์ธ๋”ฉ์ด ์‚ฌ๋ผ์ง
const greet = john.greet;
greet(); // ์˜ค๋ฅ˜: Cannot read property 'name' of undefined

// ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ์†์„ฑ์€ this ๋ฐ”์ธ๋”ฉ์„ ์žƒ์ง€ ์•Š์Œ
const arrowGreet = john.arrowGreet;
arrowGreet(); // "Hi, I'm John"

3. Quiz: What will be printed?โ€‹

ํ€ด์ฆˆ: ๋‹ค์Œ ์ฝ”๋“œ๋Š” ๋ฌด์—‡์„ ์ถœ๋ ฅํ• ๊นŒ์š”?

๋ฌธ์ œ 1: ๊ฐ์ฒด ๋ฉ”์„œ๋“œ์™€ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜โ€‹

const obj = {
name: 'Object',
regularFunc: function () {
console.log('A:', this.name);
},
arrowFunc: () => {
console.log('B:', this.name);
},
};

obj.regularFunc();
obj.arrowFunc();
ํด๋ฆญํ•˜์—ฌ ์ •๋‹ต ๋ณด๊ธฐ
// A: Object
// B: undefined

์„ค๋ช…:

  • regularFunc๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ, obj.regularFunc()๋กœ ํ˜ธ์ถœ๋˜๋ฏ€๋กœ this๋Š” obj๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋ฉฐ, "A: Object"๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค
  • arrowFunc๋Š” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋กœ, ์ž์ฒด this๊ฐ€ ์—†๊ณ  ์™ธ๋ถ€(์ „์—ญ)์˜ this๋ฅผ ์ƒ์†ํ•ฉ๋‹ˆ๋‹ค. ์ „์—ญ์— name ์†์„ฑ์ด ์—†์œผ๋ฏ€๋กœ "B: undefined"๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค

๋ฌธ์ œ 2: ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ์ „๋‹ฌโ€‹

const person = {
name: 'John',
greet: function () {
console.log(`Hello, ${this.name}`);
},
};

person.greet(); // 1

const greet = person.greet;
greet(); // 2

setTimeout(person.greet, 1000); // 3
ํด๋ฆญํ•˜์—ฌ ์ •๋‹ต ๋ณด๊ธฐ
// 1: "Hello, John"
// 2: "Hello, undefined" ๋˜๋Š” ์˜ค๋ฅ˜(์—„๊ฒฉ ๋ชจ๋“œ)
// 3: "Hello, undefined" ๋˜๋Š” ์˜ค๋ฅ˜(์—„๊ฒฉ ๋ชจ๋“œ)

์„ค๋ช…:

  1. person.greet() - ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœํ•˜๋ฏ€๋กœ this๋Š” person์„ ๊ฐ€๋ฆฌํ‚ด
  2. greet() - ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•œ ํ›„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋ฉด this๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ , ์ „์—ญ ๋˜๋Š” undefined๋ฅผ ๊ฐ€๋ฆฌํ‚ด
  3. setTimeout(person.greet, 1000) - ๋ฉ”์„œ๋“œ๊ฐ€ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋กœ ์ „๋‹ฌ๋˜์–ด this๊ฐ€ ์‚ฌ๋ผ์ง

๋ฌธ์ œ 3: ์ค‘์ฒฉ ํ•จ์ˆ˜โ€‹

const obj = {
name: 'Outer',
method: function () {
console.log('A:', this.name);

function inner() {
console.log('B:', this.name);
}
inner();

const arrow = () => {
console.log('C:', this.name);
};
arrow();
},
};

obj.method();
ํด๋ฆญํ•˜์—ฌ ์ •๋‹ต ๋ณด๊ธฐ
// A: Outer
// B: undefined
// C: Outer

์„ค๋ช…:

  • A - method๊ฐ€ obj๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœ๋˜๋ฏ€๋กœ this๋Š” obj๋ฅผ ๊ฐ€๋ฆฌํ‚ด
  • B - inner๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜๋กœ ์ง์ ‘ ํ˜ธ์ถœ๋˜๋ฏ€๋กœ this๋Š” ์ „์—ญ ๋˜๋Š” undefined๋ฅผ ๊ฐ€๋ฆฌํ‚ด
  • C - arrow๋Š” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋กœ ์™ธ๋ถ€ method์˜ this๋ฅผ ์ƒ์†ํ•˜์—ฌ obj๋ฅผ ๊ฐ€๋ฆฌํ‚ด

๋ฌธ์ œ 4: setTimeout๊ณผ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜โ€‹

const obj = {
name: 'Object',

method1: function () {
setTimeout(function () {
console.log('A:', this.name);
}, 100);
},

method2: function () {
setTimeout(() => {
console.log('B:', this.name);
}, 100);
},
};

obj.method1();
obj.method2();
ํด๋ฆญํ•˜์—ฌ ์ •๋‹ต ๋ณด๊ธฐ
// A: undefined
// B: Object

์„ค๋ช…:

  • A - setTimeout์˜ ์ฝœ๋ฐฑ์ด ์ผ๋ฐ˜ ํ•จ์ˆ˜์ด๋ฏ€๋กœ, ์‹คํ–‰ ์‹œ this๋Š” ์ „์—ญ์„ ๊ฐ€๋ฆฌํ‚ด
  • B - setTimeout์˜ ์ฝœ๋ฐฑ์ด ํ™”์‚ดํ‘œ ํ•จ์ˆ˜์ด๋ฏ€๋กœ, ์™ธ๋ถ€ method2์˜ this๋ฅผ ์ƒ์†ํ•˜์—ฌ obj๋ฅผ ๊ฐ€๋ฆฌํ‚ด

๋ฌธ์ œ 5: ๋ณต์žกํ•œ this ๋ฐ”์ธ๋”ฉโ€‹

const obj1 = {
name: 'obj1',
getThis: function () {
return this;
},
};

const obj2 = {
name: 'obj2',
};

console.log('A:', obj1.getThis().name);

const getThis = obj1.getThis;
console.log('B:', getThis() === window); // ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ ๊ฐ€์ •

obj2.getThis = obj1.getThis;
console.log('C:', obj2.getThis().name);

const boundGetThis = obj1.getThis.bind(obj2);
console.log('D:', boundGetThis().name);
ํด๋ฆญํ•˜์—ฌ ์ •๋‹ต ๋ณด๊ธฐ
// A: obj1
// B: true
// C: obj2
// D: obj2

์„ค๋ช…:

  • A - obj1์„ ํ†ตํ•ด ํ˜ธ์ถœํ•˜๋ฏ€๋กœ this๋Š” obj1์„ ๊ฐ€๋ฆฌํ‚ด
  • B - ์ง์ ‘ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ this๋Š” ์ „์—ญ(window)์„ ๊ฐ€๋ฆฌํ‚ด
  • C - obj2๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœํ•˜๋ฏ€๋กœ this๋Š” obj2๋ฅผ ๊ฐ€๋ฆฌํ‚ด
  • D - bind๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ this๋ฅผ obj2๋กœ ๋ฐ”์ธ๋”ฉ

๋ฌธ์ œ 6: ์ƒ์„ฑ์ž ํ•จ์ˆ˜์™€ ํ”„๋กœํ† ํƒ€์ž…โ€‹

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

Person.prototype.greet = function () {
console.log(`Hello, I'm ${this.name}`);
};

Person.prototype.delayedGreet = function () {
setTimeout(function () {
console.log('A:', this.name);
}, 100);
};

Person.prototype.arrowDelayedGreet = function () {
setTimeout(() => {
console.log('B:', this.name);
}, 100);
};

const john = new Person('John');
john.delayedGreet();
john.arrowDelayedGreet();
ํด๋ฆญํ•˜์—ฌ ์ •๋‹ต ๋ณด๊ธฐ
// A: undefined
// B: John

์„ค๋ช…:

  • A - setTimeout์˜ ์ผ๋ฐ˜ ํ•จ์ˆ˜ ์ฝœ๋ฐฑ์œผ๋กœ, this๋Š” ์ „์—ญ์„ ๊ฐ€๋ฆฌํ‚ด
  • B - setTimeout์˜ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ์ฝœ๋ฐฑ์œผ๋กœ, ์™ธ๋ถ€ arrowDelayedGreet์˜ this๋ฅผ ์ƒ์†ํ•˜์—ฌ john์„ ๊ฐ€๋ฆฌํ‚ด

๋ฌธ์ œ 7: ์ „์—ญ ๋ณ€์ˆ˜ vs ๊ฐ์ฒด ์†์„ฑโ€‹

var name = 'jjjj';

var obj = {
a: function () {
name = 'john';
console.log(this.name);
},
};

obj.a();
ํด๋ฆญํ•˜์—ฌ ์ •๋‹ต ๋ณด๊ธฐ
// undefined

์„ค๋ช…:

์ด ๋ฌธ์ œ์˜ ํ•ต์‹ฌ์€ ์ „์—ญ ๋ณ€์ˆ˜์™€ ๊ฐ์ฒด ์†์„ฑ์˜ ์ฐจ์ด๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค:

  1. obj.a()์˜ this๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ:

    • obj.a()๋กœ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ this๋Š” obj๋ฅผ ๊ฐ€๋ฆฌํ‚ด
  2. name = 'john'์€ ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์ •ํ•จ:

    name = 'john'; // var/let/const ์—†์ด, ์ „์—ญ name์„ ์ˆ˜์ •
    // ๋‹ค์Œ๊ณผ ๋™์ผ
    window.name = 'john'; // ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ
  3. this.name์€ ๊ฐ์ฒด ์†์„ฑ์— ์ ‘๊ทผํ•จ:

    console.log(this.name); // console.log(obj.name)๊ณผ ๋™์ผ
  4. obj ๊ฐ์ฒด์—๋Š” name ์†์„ฑ์ด ์—†์Œ:

    obj.name; // undefined(obj ๊ฐ์ฒด ๋‚ด์— name์ด ์ •์˜๋˜์ง€ ์•Š์Œ)

์ „์ฒด ์‹คํ–‰ ๊ณผ์ •:

// ์ดˆ๊ธฐ ์ƒํƒœ
window.name = 'jjjj'; // ์ „์—ญ ๋ณ€์ˆ˜
obj = {
a: function () { /* ... */ },
// ์ฃผ์˜: obj์—๋Š” name ์†์„ฑ์ด ์—†์Œ!
};

// obj.a() ์‹คํ–‰
obj.a();
โ†“
// 1. name = 'john' โ†’ ์ „์—ญ window.name ์ˆ˜์ •
window.name = 'john'; // โœ… ์ „์—ญ ๋ณ€์ˆ˜๊ฐ€ ์ˆ˜์ •๋จ

// 2. this.name โ†’ obj.name์— ์ ‘๊ทผ
this.name; // obj.name๊ณผ ๋™์ผ
obj.name; // undefined(obj์— name ์†์„ฑ์ด ์—†์Œ)

ํ”ํ•œ ์˜คํ•ด:

๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด 'john'์ด ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋Š”๋ฐ, ์ด๋Š”:

  • โŒ name = 'john'์ด obj์— ์†์„ฑ์„ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ์˜คํ•ด
  • โŒ this.name์ด ์ „์—ญ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•œ๋‹ค๊ณ  ์˜คํ•ด

์˜ฌ๋ฐ”๋ฅธ ์ดํ•ด:

  • โœ… name = 'john'์€ ์ „์—ญ ๋ณ€์ˆ˜๋งŒ ์ˆ˜์ •ํ•˜๋ฉฐ obj์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ
  • โœ… this.name์ด ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ obj.name์ด์ง€, ์ „์—ญ name์ด ์•„๋‹˜

'john'์„ ์ถœ๋ ฅํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

var obj = {
a: function () {
this.name = 'john'; // โœ… obj์— name ์†์„ฑ ์ถ”๊ฐ€
console.log(this.name); // 'john'
},
};

obj.a(); // 'john' ์ถœ๋ ฅ
console.log(obj.name); // 'john'

๋ฌธ์ œ 8: ์ „์—ญ ๋ณ€์ˆ˜ ํ•จ์ •(์‹ฌํ™”)โ€‹

var name = 'global';

var obj = {
name: 'object',
a: function () {
name = 'modified'; // ์ฃผ์˜: var/let/const ์—†์Œ
console.log('1:', name); // ์ „์—ญ ๋ณ€์ˆ˜์— ์ ‘๊ทผ
console.log('2:', this.name); // ๊ฐ์ฒด ์†์„ฑ์— ์ ‘๊ทผ
},
};

obj.a();
console.log('3:', name); // ์ „์—ญ ๋ณ€์ˆ˜
console.log('4:', obj.name); // ๊ฐ์ฒด ์†์„ฑ
ํด๋ฆญํ•˜์—ฌ ์ •๋‹ต ๋ณด๊ธฐ
// 1: modified
// 2: object
// 3: modified
// 4: object

์„ค๋ช…:

// ์ดˆ๊ธฐ ์ƒํƒœ
window.name = 'global'; // ์ „์—ญ ๋ณ€์ˆ˜
obj.name = 'object'; // ๊ฐ์ฒด ์†์„ฑ

// obj.a() ์‹คํ–‰
name = 'modified'; // ์ „์—ญ window.name ์ˆ˜์ •

console.log('1:', name); // ์ „์—ญ ์ ‘๊ทผ: 'modified'
console.log('2:', this.name); // obj.name ์ ‘๊ทผ: 'object'

// ์‹คํ–‰ ์™„๋ฃŒ ํ›„
console.log('3:', name); // ์ „์—ญ: 'modified'
console.log('4:', obj.name); // ๊ฐ์ฒด: 'object'(์ˆ˜์ •๋˜์ง€ ์•Š์Œ)

ํ•ต์‹ฌ ๊ฐœ๋…:

  • name(this. ์—†์ด) โ†’ ์ „์—ญ ๋ณ€์ˆ˜์— ์ ‘๊ทผ
  • this.name(this. ์žˆ์Œ) โ†’ ๊ฐ์ฒด ์†์„ฑ์— ์ ‘๊ทผ
  • ์ด ๋‘˜์€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค!

4. How to preserve this in callbacks?โ€‹

์ฝœ๋ฐฑ ํ•จ์ˆ˜์—์„œ this๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

๋ฐฉ๋ฒ• 1: ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ์‚ฌ์šฉโ€‹

const obj = {
name: 'Object',

method: function () {
// โœ… ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋Š” ์™ธ๋ถ€์˜ this๋ฅผ ์ƒ์†ํ•จ
setTimeout(() => {
console.log(this.name); // "Object"
}, 1000);
},
};

obj.method();

๋ฐฉ๋ฒ• 2: bind() ์‚ฌ์šฉโ€‹

const obj = {
name: 'Object',

method: function () {
// โœ… bind๋กœ this ๋ฐ”์ธ๋”ฉ
setTimeout(
function () {
console.log(this.name); // "Object"
}.bind(this),
1000
);
},
};

obj.method();

๋ฐฉ๋ฒ• 3: this๋ฅผ ๋ณ€์ˆ˜์— ์ €์žฅ(์ด์ „ ๋ฐฉ๋ฒ•)โ€‹

const obj = {
name: 'Object',

method: function () {
// โœ… this๋ฅผ ๋ณ€์ˆ˜์— ์ €์žฅ
const self = this;
setTimeout(function () {
console.log(self.name); // "Object"
}, 1000);
},
};

obj.method();

๋ฐฉ๋ฒ• 4: call() ๋˜๋Š” apply() ์‚ฌ์šฉโ€‹

function greet() {
console.log(`Hello, I'm ${this.name}`);
}

const person1 = { name: 'John' };
const person2 = { name: 'Jane' };

greet.call(person1); // "Hello, I'm John"
greet.apply(person2); // "Hello, I'm Jane"

5. Common this pitfallsโ€‹

ํ”ํ•œ this ํ•จ์ •

ํ•จ์ • 1: ๊ฐ์ฒด ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ€์ˆ˜์— ํ• ๋‹นโ€‹

const obj = {
name: 'Object',
greet: function () {
console.log(this.name);
},
};

obj.greet(); // โœ… "Object"

const greet = obj.greet;
greet(); // โŒ undefined(this๊ฐ€ ์‚ฌ๋ผ์ง)

// ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: bind ์‚ฌ์šฉ
const boundGreet = obj.greet.bind(obj);
boundGreet(); // โœ… "Object"

ํ•จ์ • 2: ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ์—์„œ์˜ thisโ€‹

const button = document.querySelector('button');

const obj = {
name: 'Object',

// โŒ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜: this๊ฐ€ button์„ ๊ฐ€๋ฆฌํ‚ค์ง€ ์•Š์Œ
handleClick1: () => {
console.log(this); // window
},

// โœ… ์ผ๋ฐ˜ ํ•จ์ˆ˜: this๋Š” ์ด๋ฒคํŠธ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•œ ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ด
handleClick2: function () {
console.log(this); // button ์š”์†Œ
},

// โœ… ๊ฐ์ฒด์˜ this์— ์ ‘๊ทผํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋กœ ๋ž˜ํ•‘
handleClick3: function () {
button.addEventListener('click', () => {
console.log(this.name); // "Object"
});
},
};

ํ•จ์ • 3: ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ์˜ ์ฝœ๋ฐฑโ€‹

const obj = {
name: 'Object',
items: [1, 2, 3],

// โŒ ์ผ๋ฐ˜ ํ•จ์ˆ˜ ์ฝœ๋ฐฑ์€ this๋ฅผ ์žƒ์Œ
processItems1: function () {
this.items.forEach(function (item) {
console.log(this.name, item); // undefined 1, undefined 2, undefined 3
});
},

// โœ… ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ์ฝœ๋ฐฑ์€ this๋ฅผ ์œ ์ง€ํ•จ
processItems2: function () {
this.items.forEach((item) => {
console.log(this.name, item); // "Object" 1, "Object" 2, "Object" 3
});
},

// โœ… forEach์˜ thisArg ๋งค๊ฐœ๋ณ€์ˆ˜ ์‚ฌ์šฉ
processItems3: function () {
this.items.forEach(function (item) {
console.log(this.name, item); // "Object" 1, "Object" 2, "Object" 3
}, this); // ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ this ์ง€์ •
},
};

6. this binding rules summaryโ€‹

this ๋ฐ”์ธ๋”ฉ ๊ทœ์น™ ์š”์•ฝ

์šฐ์„ ์ˆœ์œ„(๋†’์€ ์ˆœ)โ€‹

// 1. new ๋ฐ”์ธ๋”ฉ(์ตœ๊ณ  ์šฐ์„ ์ˆœ์œ„)
function Person(name) {
this.name = name;
}
const john = new Person('John');
console.log(john.name); // "John"

// 2. ๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ(call/apply/bind)
function greet() {
console.log(this.name);
}
const obj = { name: 'Object' };
greet.call(obj); // "Object"

// 3. ์•”์‹œ์  ๋ฐ”์ธ๋”ฉ(๊ฐ์ฒด ๋ฉ”์„œ๋“œ)
const obj2 = {
name: 'Object2',
greet: greet,
};
obj2.greet(); // "Object2"

// 4. ๊ธฐ๋ณธ ๋ฐ”์ธ๋”ฉ(์ตœ์ € ์šฐ์„ ์ˆœ์œ„)
greet(); // undefined(์—„๊ฒฉ ๋ชจ๋“œ) ๋˜๋Š” window.name

Function vs Arrow Function ๋น„๊ตํ‘œโ€‹

ํŠน์„ฑFunctionArrow Function
์ž์ฒด this ๋ณด์œ โœ… ์žˆ์ŒโŒ ์—†์Œ
this ๊ฒฐ์ • ์š”์ธํ˜ธ์ถœ ๋ฐฉ์‹์ •์˜ ์œ„์น˜(๋ ‰์‹œ์ปฌ ์Šค์ฝ”ํ”„)
call/apply/bind๋กœ this ๋ณ€๊ฒฝ ๊ฐ€๋Šฅโœ… ๊ฐ€๋ŠฅโŒ ๋ถˆ๊ฐ€๋Šฅ
์ƒ์„ฑ์ž๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅโœ… ๊ฐ€๋ŠฅโŒ ๋ถˆ๊ฐ€๋Šฅ
arguments ๊ฐ์ฒด ๋ณด์œ โœ… ์žˆ์ŒโŒ ์—†์Œ
์ ํ•ฉํ•œ ์ƒํ™ฉ๊ฐ์ฒด ๋ฉ”์„œ๋“œ, ์ƒ์„ฑ์ž์ฝœ๋ฐฑ ํ•จ์ˆ˜, ์™ธ๋ถ€ this ์ƒ์†์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

๊ธฐ์–ต๋ฒ•โ€‹

"ํ™”์‚ดํ‘œ๋Š” ์ƒ์†, ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ"

  • ํ™”์‚ดํ‘œ ํ•จ์ˆ˜: this๋Š” ์™ธ๋ถ€ ์Šค์ฝ”ํ”„์—์„œ ์ƒ์†๋˜๋ฉฐ, ์ •์˜ ์‹œ์ ์— ๊ฒฐ์ •๋จ
  • ์ผ๋ฐ˜ ํ•จ์ˆ˜: this๋Š” ํ˜ธ์ถœ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๊ฒฐ์ •๋˜๋ฉฐ, ์‹คํ–‰ ์‹œ์ ์— ๊ฒฐ์ •๋จ

7. Best practicesโ€‹

๋ชจ๋ฒ” ์‚ฌ๋ก€

โœ… ๊ถŒ์žฅ ๋ฐฉ๋ฒ•โ€‹

// 1. ๊ฐ์ฒด ๋ฉ”์„œ๋“œ์—๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜ ๋˜๋Š” ES6 ๋ฉ”์„œ๋“œ ์ถ•์•ฝ ์‚ฌ์šฉ
const obj = {
name: 'Object',

// โœ… ์ข‹์Œ: ์ผ๋ฐ˜ ํ•จ์ˆ˜
greet: function () {
console.log(this.name);
},

// โœ… ์ข‹์Œ: ES6 ์ถ•์•ฝ
introduce() {
console.log(this.name);
},
};

// 2. ์ฝœ๋ฐฑ ํ•จ์ˆ˜์—๋Š” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ์‚ฌ์šฉ
class Component {
constructor() {
this.name = 'Component';
}

mount() {
// โœ… ์ข‹์Œ: ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๊ฐ€ this๋ฅผ ์œ ์ง€ํ•จ
setTimeout(() => {
console.log(this.name);
}, 1000);
}
}

// 3. ๋™์  this๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ผ๋ฐ˜ ํ•จ์ˆ˜ ์‚ฌ์šฉ
const button = {
label: 'Click me',

// โœ… ์ข‹์Œ: DOM ์š”์†Œ์˜ this์— ์ ‘๊ทผํ•ด์•ผ ํ•จ
handleClick: function () {
console.log(this); // button DOM ์š”์†Œ
},
};

โŒ ๋น„๊ถŒ์žฅ ๋ฐฉ๋ฒ•โ€‹

// 1. ๊ฐ์ฒด ๋ฉ”์„œ๋“œ์— ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
const obj = {
name: 'Object',

// โŒ ๋‚˜์จ: this๊ฐ€ obj๋ฅผ ๊ฐ€๋ฆฌํ‚ค์ง€ ์•Š์Œ
greet: () => {
console.log(this.name); // undefined
},
};

// 2. ์ƒ์„ฑ์ž์— ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
// โŒ ๋‚˜์จ: ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋Š” ์ƒ์„ฑ์ž๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ
const Person = (name) => {
this.name = name; // ์˜ค๋ฅ˜!
};

// 3. arguments์— ์ ‘๊ทผํ•ด์•ผ ํ•  ๋•Œ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
// โŒ ๋‚˜์จ: ํ™”์‚ดํ‘œ ํ•จ์ˆ˜์—๋Š” arguments๊ฐ€ ์—†์Œ
const sum = () => {
console.log(arguments); // ReferenceError
};

Referenceโ€‹