๐ ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ต์ฌ) 22์ฅ. this
01. this ํค์๋
๊ฐ์ฒด : ์ํ(state)๋ฅผ ๋ํ๋ด๋ ํ๋กํผํฐ์ ๋์(behavior)๋ฅผ ๋ํ๋ด๋ ๋ฉ์๋๋ฅผ ํ๋์ ๋ ผ๋ฆฌ์ ์ธ ๋จ์๋ก ๋ฌถ์ ๋ณตํฉ์ ์ธ ์๋ฃ๊ตฌ์กฐ๋ค.
๋์์ ๋ํ๋ด๋ ๋ฉ์๋๋ ์์ ์ด ์ํ ๊ฐ์ฒด์ ์ํ, ์ฆ ํ๋กํผํฐ๋ฅผ ์ฐธ์กฐํ๊ณ ๋ณ๊ฒฝํ ์ ์์ด์ผ ํ๋ค.
โก๏ธ ์ด๋ ์์ ์ด ์ํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ณ์๋ฅผ ์ฐธ์กฐํ ์ ์์ด์ผ ํ๋๋ฐ, ์ด๋ this๋ฅผ ์ฌ์ฉํ๋ค.
<๊ฐ์ฒด ๋ฆฌํฐ๋ด ๋ฐฉ์์ผ๋ก ์์ฑํ ๊ฐ์ฒด์ ๊ฒฝ์ฐ>
const circle = {
// ํ๋กํผํฐ: ๊ฐ์ฒด ๊ณ ์ ์ ์ํ ๋ฐ์ดํฐ
radius: 5,
// ๋ฉ์๋: ์ํ ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํ๊ณ ์กฐ์ํ๋ ๋์
getDiameter() {
// ์ด ๋ฉ์๋๊ฐ ์์ ์ด ์ํ ๊ฐ์ฒด์ ํ๋กํผํฐ๋ ๋ค๋ฅธ ๋ฉ์๋๋ฅผ ์ฐธ์กฐํ๋ ค๋ฉด
// ์์ ์ด ์ํ ๊ฐ์ฒด์ธ circle์ ์ฐธ์กฐํ ์ ์์ด์ผ ํ๋ค.
return 2 * circle.radius;
}
};
console.log(circle.getDiameter()); // 10
getDiameter๋ฉ์๋ ๋ด์์ ๋ฉ์๋ ์์ ์ด ์ํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ณ์ circle์ ์ฐธ์กฐํ๊ณ ์๋ค.
โก๏ธ circle.getDiameter();ํธ์ถํ๋ ์์ ์๋ ์ด๋ฏธ circle๊ฐ์ฒด๊ฐ ์์ฑ๋์ด ์์ผ๋ฏ๋ก ๋ฉ์๋ ๋ด๋ถ์์ circle์๋ณ์๋ฅผ ์ฐธ์กฐํ ์ ์๋ค.
ํ์ง๋ง ์์ ์ด ์ํ ๊ฐ์ฒด๋ฅผ ์ฌ๊ท์ ์ผ๋ก ์ฐธ์กฐํ๋ ๋ฐฉ์์ ๋ฐ๋์งํ์ง ์์.
<์์ฑ์ ํจ์ ๋ฐฉ์์ผ๋ก ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ ๊ฒฝ์ฐ>
function Circle(radius) {
// ์ด ์์ ์๋ ์์ฑ์ ํจ์ ์์ ์ด ์์ฑํ ์ธ์คํด์ค๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ณ์๋ฅผ ์ ์ ์๋ค.
????.radius = radius;
}
Circle.prototype.getDiameter = function () {
// ์ด ์์ ์๋ ์์ฑ์ ํจ์ ์์ ์ด ์์ฑํ ์ธ์คํด์ค๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ณ์๋ฅผ ์ ์ ์๋ค.
return 2 * ????.radius;
};
// ์์ฑ์ ํจ์๋ก ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ ค๋ฉด ๋จผ์ ์์ฑ์ ํจ์๋ฅผ ์ ์ํด์ผ ํ๋ค.
const circle = new Circle(5);
โก๏ธ ํจ์๋ฅผ ์ ์ธํ๋ ์์ ์๋ ์์ ์ด ์์ฑํ ์ธ์คํด์ค๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ณ์๋ฅผ ์ ์ ์๋ค.
๐ก ์์ฑ์ ํจ์๋ฅผ ์ ์ํ๋ ์์ ์๋ ์ธ์คํด์ค๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ณ์๋ฅผ ์ ์ ์๊ธฐ ๋๋ฌธ์ ํน์ํ ์๋ณ์ this ๋ฅผ ์ฌ์ฉํ๋ค.
๐ก this
- ์์ ์ด ์ํ ๊ฐ์ฒด ๋๋ ์์ ์ด ์์ฑํ ์ธ์คํด์ค๋ฅผ ๊ฐ๋ฆฌํค๋ ์๊ธฐ ์ฐธ์กฐ ๋ณ์(self-referenceing variable)๋ค.
- ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ์ํด ์๋ฌต์ ์ผ๋ก ์์ฑ๋๋ฉฐ, ์ฝ๋ ์ด๋์๋ ์ฐธ์กฐํ ์ ์๋ค.
- ํจ์๋ฅผ ํธ์ถํ๋ฉด arguments๊ฐ์ฒด์ this๊ฐ ์๋ฌต์ ์ผ๋ก ํจ์ ๋ด๋ถ์ ์ ๋ฌ๋๋ค.
- this๋ฐ์ธ๋ฉ์ ํจ์ ํธ์ถ ๋ฐฉ์์ ์ํด ๋์ ์ผ๋ก ๊ฒฐ์ ๋๋ค.
02. ํจ์ ํธ์ถ ๋ฐฉ์๊ณผ this ๋ฐ์ธ๋ฉ
this๋ฐ์ธ๋ฉ์ ํจ์ ํธ์ถ ๋ฐฉ์, ์ฆ ํจ์๊ฐ ์ด๋ป๊ฒ ํธ์ถ๋์๋์ง์ ๋ฐ๋ผ ๋์ ์ผ๋ก ๊ฒฐ์ ๋๋ค.
(์ฌ๊ธฐ์ this๋ฐ์ธ๋ฉ์ด๋, this์ this๊ฐ ๊ฐ๋ฆฌํฌ ๊ฐ์ฒด๋ฅผ ๋ฐ์ธ๋ฉํ๋ ๊ฒ)
1) ์ผ๋ฐ ํจ์ ํธ์ถ
์ผ๋ฐ ํจ์๋ก ํธ์ถํ๋ ๊ฒฝ์ฐ ๊ธฐ๋ณธ์ ์ผ๋ก this์๋ ์ ์ญ ๊ฐ์ฒด๊ฐ ๋ฐ์ธ๋ฉ๋๋ค.
strict mode์์๋ this์ undefined๊ฐ ๋ฐ์ธ๋ฉ๋๋ค.
์ผ๋ฐํจ์๋ก ํธ์ถ๋ ๋ชจ๋ ํจ์(์ค์ฒฉ ํจ์, ์ฝ๋ฐฑ ํจ์ ํฌํจ) ๋ด๋ถ์ this์๋ ์ ์ญ ๊ฐ์ฒด๊ฐ ๋ฐ์ธ๋ฉ๋๋ค.
๐ฅ ๋ฉ์๋ ๋ด๋ถ ์ค์ฒฉ ํจ์๋ ์ฝ๋ฐฑ ํจ์์ this๋ฐ์ธ๋ฉ์ ๋ฉ์๋์ this์ ์ผ์น ์ํค๊ธฐ ์ํ ๋ฐฉ๋ฒ
- ๋ณ์ that ์ฌ์ฉ
- Function.prototype.apply/call/bind ๋ฉ์๋ ํ์ฉ
- ํ์ดํ ํจ์ ํ์ฉ
2) ๋ฉ์๋ ํธ์ถ
- ๋ฉ์๋ ๋ด๋ถ์ this์๋ ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด๊ฐ ๋ฐ์ธ๋ฉ๋๋ค. (=๋ฉ์๋ ์ด๋ฆ ์์ ๋ง์นจํ ์ฐ์ฐ์ ์์ ๊ธฐ์ ํ ๊ฐ์ฒด๊ฐ ๋ฐ์ธ๋ฉ๋๋ค๋ ๋ป)
- โ ๏ธ ๋ฉ์๋๋ฅผ ์์ ํ ๊ฐ์ฒด X, ํธ์ถํ ๊ฐ์ฒด O ์ ๋ฐ์ธ๋ฉ ๋จ์ ์ฃผ์ํ์.
const person = {
name: 'Lee',
getName() {
// ๋ฉ์๋ ๋ด๋ถ์ this๋ ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด์ ๋ฐ์ธ๋ฉ๋๋ค.
return this.name;
}
};
// ๋ฉ์๋ getName์ ํธ์ถํ ๊ฐ์ฒด๋ person์ด๋ค.
console.log(person.getName()); // Lee
(โก๏ธ ๋ง์ฝ getName๋ฉ์๋๋ฅผ ์ผ๋ฐ ๋ณ์์ ํ ๋นํ์ฌ ํธ์ถํ๋ฉด ์ผ๋ฐ ํจ์๋ก ํธ์ถ๋๋ค.)
<์์ 22-16>
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
};
const me = new Person('Lee');
// getName ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด๋ me๋ค.
console.log(me.getName()); // โ Lee
Person.prototype.name = 'Kim';
// getName ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด๋ Person.prototype์ด๋ค.
console.log(Person.prototype.getName()); // โก Kim
โก๏ธ ํ๋กํ ํ์ ๋ฉ์๋ ๋ด๋ถ์์ ์ฌ์ฉ๋ this๋ ์ผ๋ฐ ๋ฉ์๋์ ๋์ผํ๊ฒ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด์ ๋ฐ์ธ๋ฉ ๋๋ค.
โก๏ธ โ ์ ๊ฒฝ์ฐ getName๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด๋ me์ด๋ค.
๋ฉ์๋ ๋ด๋ถ์ this์๋ ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด๊ฐ ๋ฐ์ธ๋ฉ๋๋ค๊ณ ํ์ผ๋ฏ๋ก,
-> getName๋ฉ์๋ ๋ด๋ถ์ this๋ me๋ฅผ ๊ฐ๋ฆฌํค๋ฉฐ this.name๊ฐ์ Lee๋ค.
โก๏ธ โก์ ๊ฒฝ์ฐ getName๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด๋ Person.prototype์ด๋ค.
- ํ๋กํ ํ์ ๋ฉ์๋ ๋ด๋ถ์์ ์ฌ์ฉ๋ this๋ ์ผ๋ฐ ๋ฉ์๋์ ๋์ผํ๊ฒ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด์ ๋ฐ์ธ๋ฉ ๋๋ค๊ณ ํ์ผ๋ฏ๋ก,
-> getName๋ฉ์๋ ๋ด๋ถ์ this๋ Person.prototype์ ๊ฐ๋ฆฌํค๋ฉฐ this.name๊ฐ์ Kim์ด๋ค.
3) ์์ฑ์ ํจ์ ํธ์ถ
์์ฑ์ ํจ์ ๋ด๋ถ์ this์๋ ์์ฑ์ ํจ์๊ฐ (๋ฏธ๋์) ์์ฑํ ์ธ์คํด์ค๊ฐ ๋ฐ์ธ๋ฉ๋๋ค.
// ์์ฑ์ ํจ์
function Circle(radius) {
// ์์ฑ์ ํจ์ ๋ด๋ถ์ this๋ ์์ฑ์ ํจ์๊ฐ ์์ฑํ ์ธ์คํด์ค๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
};
}
// ๋ฐ์ง๋ฆ์ด 5์ธ Circle ๊ฐ์ฒด๋ฅผ ์์ฑ
const circle1 = new Circle(5);
// ๋ฐ์ง๋ฆ์ด 10์ธ Circle ๊ฐ์ฒด๋ฅผ ์์ฑ
const circle2 = new Circle(10);
console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 20
(โก๏ธ new์ฐ์ฐ์์ ํจ๊ป ํธ์ถํ์ง ์์ผ๋ฉด ์ผ๋ฐ ํจ์๋ก ํธ์ถ๋๋ค.)
(โก๏ธ Circleํจ์์ ๋ฐํ ๊ฐ์ด ์์ผ๋ฉด ์๋ฌต์ ์ผ๋ก undefined๋ฅผ ๋ฐํํ๋ค.)
// ์์ฑ์ ํจ์
function Circle(radius) {
// ์์ฑ์ ํจ์ ๋ด๋ถ์ this๋ ์์ฑ์ ํจ์๊ฐ ์์ฑํ ์ธ์คํด์ค๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
};
}
// new ์ฐ์ฐ์์ ํจ๊ป ํธ์ถํ์ง ์์ผ๋ฉด ์์ฑ์ ํจ์๋ก ๋์ํ์ง ์๋๋ค. ์ฆ, ์ผ๋ฐ์ ์ธ ํจ์์ ํธ์ถ์ด๋ค.
const circle3 = Circle(15);
// ์ผ๋ฐ ํจ์๋ก ํธ์ถ๋ Circle์๋ ๋ฐํ๋ฌธ์ด ์์ผ๋ฏ๋ก ์๋ฌต์ ์ผ๋ก undefined๋ฅผ ๋ฐํํ๋ค.
console.log(circle3); // undefined
// ์ผ๋ฐ ํจ์๋ก ํธ์ถ๋ Circle ๋ด๋ถ์ this๋ ์ ์ญ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
console.log(radius); // 15
โก๏ธ new ์ฐ์ฐ์์ ํจ๊ป ํธ์ถํ์ง ์์์
- ์์ฑ์ ํจ์๋ก ๋์ํ์ง ์๊ณ , ์ผ๋ฐ ํจ์๋ก ํธ์ถ๋ ๊ฒฝ์ฐ
-> Circle๋ด๋ถ์ this๋ ์ ์ญ ๊ฐ์ฒดwindow๋ฅผ ๊ฐ๋ฆฌํค๊ธฐ ๋๋ฌธ์
-> this.radius๋ ๊ฒฐ๊ตญ window.radius๊ฐ ๋์ด console.log(radius);๋ฅผ ์คํํ๋ฉด window.radius๊ฐ์ด ๋ฆฌํด๋์ด ์ถ๋ ฅ๋๊ฒ ๋๋ค.
4) Function.prototype.apply/call/bind ๋ฉ์๋์ ์ํ ๊ฐ์ ํธ์ถ
apply, call, bind๋ฉ์๋๋ Function.prototype์ ๋ฉ์๋๋ค.
โก๏ธ ์ด๋ค ๋ฉ์๋๋ ๋ชจ๋ ํจ์๊ฐ ์์๋ฐ์ ์ฌ์ฉํ ์ ์๋ค.
1. Function.prototype.apply, Function.prototype.call ๋ฉ์๋
apply์ call๋ฉ์๋๋ ํจ์์ this๋ก ์ฌ์ฉํ ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๊ณ ํจ์๋ฅผ ํธ์ถํ๋ค.
apply์ call ๋ฉ์๋์ ๋ณธ์ง์ ์ธ ๊ธฐ๋ฅ์ ๋์ผํ๋ค.
๋ค๋ง ์ธ์๋ฅผ ์ ๋ฌํ๋ ๋ฐฉ์๋ง ๋ค๋ฅด๋ค.
์๋ ์์ ๋ฅผ ํตํด ์ธ์ ์ ๋ฌ์ ์ดํด๋ณด์.
function getThisBinding() {
console.log(arguments);
return this;
}
// this๋ก ์ฌ์ฉํ ๊ฐ์ฒด
const thisArg = { a: 1 };
// getThisBinding ํจ์๋ฅผ ํธ์ถํ๋ฉด์ ์ธ์๋ก ์ ๋ฌํ ๊ฐ์ฒด๋ฅผ getThisBinding ํจ์์ this์ ๋ฐ์ธ๋ฉํ๋ค.
// apply ๋ฉ์๋๋ ํธ์ถํ ํจ์์ ์ธ์๋ฅผ ๋ฐฐ์ด๋ก ๋ฌถ์ด ์ ๋ฌํ๋ค.
console.log(getThisBinding.apply(thisArg, [1, 2, 3]));
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// {a: 1}
// call ๋ฉ์๋๋ ํธ์ถํ ํจ์์ ์ธ์๋ฅผ ์ผํ๋ก ๊ตฌ๋ถํ ๋ฆฌ์คํธ ํ์์ผ๋ก ์ ๋ฌํ๋ค.
console.log(getThisBinding.call(thisArg, 1, 2, 3));
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// {a: 1}
โก๏ธ apply๋ฉ์๋๋ ํจ์์ ์ธ์๋ฅผ ๋ฐฐ์ด๋ก ๋ฌถ์ด ์ ๋ฌํ๊ณ ,
โก๏ธ call๋ฉ์๋๋ ํจ์์ ์ธ์๋ฅผ ์ผํ๋ก ๊ตฌ๋ถํ ๋ฆฌ์คํธ ํ์์ผ๋ก ์ ๋ฌํ๋ค.
2. Function.prototype.bind ๋ฉ์๋
bind ๋ฉ์๋๋ apply์ call ๋ฉ์๋์ ๋ฌ๋ฆฌ ํจ์๋ฅผ ํธ์ถํ์ง๋ ์๊ณ this๋ก ์ฌ์ฉํ ๊ฐ์ฒด๋ง ์ ๋ฌํ๋ค.
๐ฅ bindํจ์๋ ๋ฉ์๋์ this์ ๋ฉ์๋ ๋ด๋ถ์ ์ค์ฒฉ ํจ์ ๋๋ ์ฝ๋ฐฑ ํจ์์ this๊ฐ ๋ถ์ผ์นํ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ ์ฉํ๊ฒ ์ฌ์ฉ๋๋ค.
<์์ 22-23>
const person = {
name: 'Lee',
foo(callback) {
// โ
setTimeout(callback, 100);
}
};
person.foo(function () {
console.log(`Hi! my name is ${this.name}.`); // โก Hi! my name is .
// ์ผ๋ฐ ํจ์๋ก ํธ์ถ๋ ์ฝ๋ฐฑ ํจ์ ๋ด๋ถ์ this.name์ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์ window.name๊ณผ ๊ฐ๋ค.
// ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์ window.name์ ๋ธ๋ผ์ฐ์ ์ฐฝ์ ์ด๋ฆ์ ๋ํ๋ด๋ ๋นํธ์ธ ํ๋กํผํฐ์ด๋ฉฐ ๊ธฐ๋ณธ๊ฐ์ ''์ด๋ค.
// Node.js ํ๊ฒฝ์์ this.name์ undefined๋ค.
});
โก๏ธ person.foo ๋ฉ์๋๊ฐ ํธ์ถ๋๋ โ ์ ์์ , ์ฝ๋ฐฑ ํจ์๊ฐ ํธ์ถ๋๊ธฐ ์ง์ ์ this๊ฐ์ foo๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด, ์ฆ person์ด๋ค.
๐ฅ ํ์ง๋ง ์ฝ๋ฐฑ ํจ์๊ฐ ํธ์ถ๋ โก์ ์์ ์์ this๋ ์ ์ญ ๊ฐ์ฒด window๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
๋ฐ๋ผ์ person.foo์ ์ฝ๋ฐฑ ํจ์ ๋ด๋ถ์์ this.name์ window.name๊ณผ ๊ฐ๋ค.
๐ฅ person.foo์ ์ฝ๋ฐฑ ํจ์๋ ์ธ๋ถ ํจ์ person.foo๋ฅผ ๋๋ ํฌํผ ํจ์(๋ณด์กฐ ํจ์) ์ญํ ์ ํ๊ธฐ ๋๋ฌธ์
์ธ๋ถ ํจ์ person.foo ๋ด๋ถ์ this์ ์ฝ๋ฐฑ ํจ์ ๋ด๋ถ์ this๊ฐ ์์ดํ๋ฉด ๋ฌธ๋งฅ์ ๋ฌธ์ ๊ฐ ๋๋ค.
โก๏ธ ์ด๋ฌํ ๊ฒฝ์ฐ ์๋ ์์์ ๊ฐ์ด bind ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ์ด๋ฅผ ํด๊ฒฐํ๋ค!
<์์ 22-24>
const person = {
name: 'Lee',
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 Lee.
});
<์ด์ ๋ฆฌ>
ํจ์ ํธ์ถ ๋ฐฉ์ | this ๋ฐ์ธ๋ฉ |
์ผ๋ฐ ํจ์ ํธ์ถ | ์ ์ญ ๊ฐ์ฒด |
๋ฉ์๋ ํธ์ถ | ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด |
์์ฑ์ ํจ์ ํธ์ถ | ์์ฑ์ ํจ์๊ฐ (๋ฏธ๋์) ์์ฑํ ์ธ์คํด์ค |
Function.prototype.apply/call/bind ๋ฉ์๋์ ์ํ ๊ฐ์ ํธ์ถ | Function.prototype.apply/call/bind ๋ฉ์๋์ ์ฒซ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌํ ๊ฐ์ฒด |
๐ ์ฐธ๊ณ ์๋ฃ