[JavaScript] this๊ฐ ๋ฌด์์ผ๊น์? ์ฝ๋ ์์ ๋ก ์ฝ๊ฒ ์์๋ด ์๋ค.
this ํค์๋์ ์ ์
์๋ฐ์คํฌ๋ฆฝํธ์์ this๋ ํ์ฌ ์คํ ์ปจํ ์คํธ๋ฅผ ์ฐธ์กฐํ๋ ํน๋ณํ ํค์๋์ ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์คํ ์ปจํ ์คํธ๊ฐ ์์ฑ๋ ๋ ํจ๊ป ๊ฒฐ์ ์ด ๋๋๋ฐ์.
์ฆ, this์ ๊ฐ์ ํจ์๊ฐ ์ด๋ป๊ฒ ํธ์ถ๋์๋์ง์ ๋ฐ๋ผ ๋ณํ๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก๋ ํจ์๋ฅผ ํธ์ถํ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํฉ๋๋ค.
์ผ๋ฐ ํจ์์์์ this
์ผ๋ฐํจ์์์ this๋ '์ ์ญ ๊ฐ์ฒด'๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
์ ์ญ ๊ฐ์ฒด๋?
๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์๋ window,
Node.js ํ๊ฒฝ์์๋ global ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
function main() {
console.log(this);
}
main(); // window ๊ฐ์ฒด ๋๋ global ๊ฐ์ฒด ์ถ๋ ฅ
์์ ๊ฐ์ด ์ด๋ ๊ฒ ์ ์ญ์ ์ผ๋ก ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ์
function main() {
console.log(this);
}
windoow.main(); // window ๊ฐ์ฒด ์ถ๋ ฅ
๋ธ๋ผ์ฐ์ ํ๊ฒฝ ๊ธฐ์ค์ผ๋ก window ๊ฐ์ฒด์ main ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
(์ ์ญ์์์ ํธ์ถ์ window๋ฅผ ์๋ตํ ๊ฒ๊ณผ ๊ฐ๋ค๊ณ ๋ด๋ ๋ฌด๋ฐฉํฉ๋๋ค.)
์์์ this๋ 'ํจ์๋ฅผ ํธ์ถํ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐ' ํ๋ค๊ณ ์ค๋ช ํ์ต๋๋ค.
main ํจ์๋ฅผ ์ง์ ์ ์ผ๋ก ํธ์ถํ ๊ฐ์ฒด๋ window ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ main ํจ์์ this๋ window ๊ฐ์ฒด๊ฐ ๋๋ ๊ฒ์ ๋๋ค.
๋ค๋ง 'use strict' ๋ชจ๋๋ฅผ ์ฌ์ฉํ ๋์๋ ์ ์ญ ๊ณต๊ฐ์์ window ๊ฐ์ฒด๋ฅผ ํตํด ํจ์๋ฅผ ํธ์ถํ์ง ์์ผ๋ฉด ํด๋น ํจ์์ this๋ undefined๋ฅผ ์ถ๋ ฅํ๊ฒ ๋ฉ๋๋ค.
๋ฉ์๋์์์ this
๊ฐ์ฒด์ ๋ฉ์๋์์ this๋ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
const obj = {
name: 'yong',
sayHello: function () {
console.log(this);
},
};
obj.sayHello(); // {name: 'yong', sayHello: ƒ} ์ถ๋ ฅ
์ ์ฝ๋๋ฅผ ๋ณด๋ฉด obj๋ผ๋ ๊ฐ์ฒด๋ก๋ถํฐ sayHello ๋ฉ์๋๋ฅผ ํธ์ถํ์ต๋๋ค.
const obj = {
name: 'yong',
sayHello: function () {
console.log(this.name);
},
};
const obj2 = obj.sayHello;
obj.sayHello(); // {name: 'yong', sayHello: ƒ} ์ถ๋ ฅ
obj2(); // window ๊ฐ์ฒด ์ถ๋ ฅ
obj2๋ ์ obj์ sayHello๋ฅผ ์ฐธ์กฐํจ์๋ ๋ถ๊ตฌํ๊ณ ์ window ๊ฐ์ฒด๊ฐ ์ถ๋ ฅ๋ ๊น์?
๋ฐ๋ก obj์ ํธ์ถ ์ฃผ์ฒด๋ window๊ฐ ๋๊ธฐ ๋๋ฌธ์
๋๋ค. ( window.obj2() == obj2() )
const obj = {
name: 'yong',
sayHello: {
name: 'jun',
sayBye: function () {
console.log(this);
},
},
};
obj.sayHello.sayBye(); // {name: 'jun', sayBye: ƒ} ์ถ๋ ฅ
์ ์ฝ๋์์๋ sayBye๋ฉ์๋๋ฅผ ์ง์ ์ ์ผ๋ก ์คํํ ๊ฑด sayHello๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ sayHello ๊ฐ์ฒด๊ฐ ์ถ๋ ฅ์ด ๋์์ต๋๋ค.
์ฆ, ์ด๋ค ํจ์๋ฅผ ๋ฉ์๋๋ก์ ํธ์ถํ๋ ๊ฒฝ์ฐ ํธ์ถ ์ฃผ์ฒด๋ ๋ฐ๋ก ํจ์๋ช (ํ๋กํผํฐ๋ช ) ์์ ๊ฐ์ฒด์ ๋๋ค.
์ ํ๊ธฐ๋ฒ์ ๊ฒฝ์ฐ ๋ง์ง๋ง ์ (.) ์์ ๋ช ์๋ ๊ฐ์ฒด๊ฐ ๊ณง this๊ฐ ๋๋ ๊ฒ์ ๋๋ค.
์์ฑ์ ํจ์์์์ this
new ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ์ ํจ์๋ฅผ ํธ์ถํ ๋ 'this'๋ ์๋ก ์์ฑ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
์์ฑ์ ํจ์๋ฅผ ํธ์ถํ๋ฉด ์ฐ์ ์์ฑ์์ prototype ํ๋กํผํฐ๋ฅผ ์ฐธ์กฐํ๋ __proto__๋ผ๋ ํ๋กํผํฐ๊ฐ ์๋ ๊ฐ์ฑ(์ธ์คํด์ค)๋ฅผ ๋ง๋ค๊ณ , ๋ฏธ๋ฆฌ ์ค๋น๋ ๊ณตํต ์์ฑ ๋ฐ ๊ฐ์ฑ์ ํด๋น ๊ฐ์ฒด(this)์ ๋ถ์ฌํฉ๋๋ค. ์ด๋ ๊ฒ ํด์ ๊ตฌ์ฒด์ ์ธ ์ธ์คํด์ค๊ฐ ๋ง๋ค์ด์ง๋๋ค.
(ํด๋น ๋ด์ฉ์ JavasScript์ prototype์ ๋ํ ์ดํด๊ฐ ํ์ํฉ๋๋ค.)
const Human = function (name, age) {
this.name = name;
this.age = age;
};
const yong = new Human('yong', 3);
const jun = new Human('jun', 10);
console.log(yong); // {name: 'yong', age: 3} ์ถ๋ ฅ
console.log(jun); // {name: 'jun', age: 10} ์ถ๋ ฅ
ํ์ดํ ํจ์์์์ this
ํ์ดํ ํจ์๋ ์คํ ์ปจํ ์คํธ๋ฅผ ์์ฑํ ๋ this ๋ฐ์ธ๋ฉ ๊ณผ์ ์์ฒด๊ฐ ๋น ์ง๊ฒ ๋์ด, ์์ ์ค์ฝํ์ this๋ฅผ ๊ทธ๋๋ก ํ์ฉํฉ๋๋ค.
์ฆ, ์์ ๋ง์ this๊ฐ ์๊ณ ์์ ์ ๊ฐ์ธ๊ณ ์๋ scope๋ก ์ฌ๋ผ๊ฐ์ this๋ฅผ ์ฐพ๊ฒ ๋ฉ๋๋ค.
// innerFunction ์ผ๋ฐ ํจ์
const obj = {
name: 'yong',
main: function () {
const innerFunction = function () {
console.log(this);
};
innerFunction();
},
};
obj.main(); // Window ๊ฐ์ฒด ์ถ๋ ฅ
// innerFunction ํ์ดํ ํจ์
const obj = {
name: 'yong',
main: function () {
const innerFunction = () => {
console.log(this);
};
innerFunction();
},
};
obj.main(); // {name: 'yong', main: ƒ} ์ถ๋ ฅ
์ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅธ์ง ๋ณผ๊น์?
๋จผ์ innerFunction ์ผ๋ฐ ํจ์ ๋จผ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
innerFunction ํจ์๋ฅผ ํธ์ถํ ์ฃผ์ฒด๋ window์ด๊ธฐ ๋๋ฌธ์ window ๊ฐ์ฒด๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
๋ค์์ผ๋ก innerFunction ํ์ดํ ํจ์๋ฅผ ์ดํด๋ณด๋ฉด,
ํ์ดํ ํจ์์ this๋ ์์ ์ค์ฝํ์ this๋ฅผ ๊ทธ๋๋ก ํ์ฉํ๋ค๊ณ ํ์ต๋๋ค.
๊ทธ๋์, ์์ ์ค์ฝํ์ธ main ๋ฉ์๋์ this๋ obj๊ฐ ํธ์ถ์ ํ๊ธฐ ๋๋ฌธ์ main ๋ฉ์๋์ this๋ obj ๊ฐ์ฒด๊ฐ ๋ฉ๋๋ค.
์ฆ, innerFunction์ main ๋ฉ์๋์ this๋ฅผ ๊ทธ๋๋ก ํ์ฉํด์ this๋ obj ๊ฐ์ฒด๊ฐ ๋์ด์ obj ๊ฐ์ฒด๋ฅผ ์ถ๋ ฅํ๊ฒ ๋ฉ๋๋ค.
์ผ๋ฐ ํจ์์ ํ์ดํ ํจ์์ this์ ๋ํ ์ฐจ์ด๋ฅผ ์ ๋ฆฌํด ๋ณด๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
- ํ์ดํ ํจ์: ์ ์ธ๋ ์์ ์์ ๊ฒฐ์ ์ด ๋ฉ๋๋ค.
- ์ผ๋ฐ ํจ์: ์ด๋์ ์ ์ธ์ด ๋์๋์ง ์๊ด์์ด ํจ์๊ฐ ํธ์ถ๋ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ์ this๊ฐ ๋์ ์ผ๋ก ํ ๋น๋ฉ๋๋ค.
๋ช ์์ ์ผ๋ก this๋ฅผ ๋ฐ์ธ๋ฉํ๋ ๋ฐฉ๋ฒ (call/apply/bind)
์ํฉ๋ง๋ค ๋ฌ๋ผ์ง๋ this์ ๋ํด์ ๋ช ์์ ์ผ๋ก this๋ฅผ ์ง์ ํด์ค ์ ์์ต๋๋ค.
call ๋ฉ์๋
call ๋ฉ์๋๋ ๋ฉ์๋์ ํธ์ถ ์ฃผ์ฒด์ธ ํจ์๋ฅผ this ๊ฐ ๋ฐ ๊ฐ๊ฐ ์ ๋ฌ๋ ์ธ์์ ํจ๊ป ํจ์๋ฅผ ์ฆ์ ์คํํ๋๋ก ํ๋ ๋ฉ์๋์ ๋๋ค.
// ํจ์
const func = function (a, b, c) {
console.log(this, a, b, c);
};
func(1, 2, 3); // Window 1 2 3๊ฐ์ฒด ์ถ๋ ฅ
func.call({ x: 1 }, 4, 5, 6); // {x: 1} 4 5 6 ์ถ๋ ฅ
// ๋ฉ์๋
const obj = {
a:1,
method: function (x,y) {
console.log(this,x,y);
}
}
obj.method(2,3); // {a: 1, method: ƒ} 2 3 ์ถ๋ ฅ
obj.method.call({z:1},4,5); // {z: 1} 4 5 ์ถ๋ ฅ
call ๋ฉ์๋์ ์ฒซ ๋ฒ์งธ ์ธ์๋ก๋ this๋ก ๋ฐ์ธ๋ฉ ํ ๊ฐ์ ์ ๋ฌํด์ฃผ์ด์ this๋ฅผ ๋ฐ์ธ๋ฉํฉ๋๋ค.
์ดํ์ ์ธ์๋ค์ ํธ์ถํ ํจ์์ ๋งค๊ฐ๋ณ์๋กํฉ๋๋ค.
apply ๋ฉ์๋
apply ๋ฉ์๋๋ call ๋ฉ์๋์ ๊ธฐ๋ฅ์ ์ผ๋ก ๋งค์ฐ ๋์ผํฉ๋๋ค.
call ๋ฉ์๋๋ ์ฒซ ๋ฒ์งธ ์ธ์๋ฅผ ์ ์ธํ ๋ชจ๋ ์ธ์๋ค์ ํธ์ถํ ํจ์์ ๋งค๊ฐ๋ณ์๋ก ์ง์ ํ๋ ๋ฐ๋ฉด,
apply ๋ฉ์๋๋ ๋ ๋ฒ์งธ ์ธ์๋ฅผ ๋ฐฐ์ด๋ก ๋ฐ์ ๊ทธ ๋ฐฐ์ด์ ์์๋ค์ ํธ์ถํ ํจ์์ ๋งค๊ฐ๋ณ์๋ก ์ง์ ํฉ๋๋ค.
const func = function (a, b, c) {
console.log(this, a, b, c);
};
func(1, 2, 3); // Window 1 2 3์ถ๋ ฅ
func.apply({ x: 1 }, [4, 5, 6]); // {x: 1} 4 5 6 ์ถ๋ ฅ
const obj = {
a: 1,
method: function (x, y) {
console.log(this, x, y);
},
};
obj.method(2, 3); // {a: 1, method: ƒ} 2 3 ์ถ๋ ฅ
obj.method.apply({ z: 1 }, [4, 5]); // {z: 1} 4 5 ์ถ๋ ฅ
bind ๋ฉ์๋
bind ๋ฉ์๋๋ ES5์ ์ถ๊ฐ๋ ๊ธฐ๋ฅ์ ๋๋ค.
bind๋ call/apply ๋ฉ์๋์ ๋ค๋ฅด๊ฒ ์ฆ์ ํธ์ถํ์ง ์๊ณ ๋๊ฒจ๋ฐ์ this ๋ฐ ์ธ์๋ค์ ๋ฐํ์ผ๋ก ์๋ก์ด ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.
const main = function () {
console.log(this);
};
const mainBind = main.bind({ name: 'mainBind' });
main(); // Window ๊ฐ์ฒด ์ถ๋ ฅ
mainBind(); // {name: 'mainBind'} ์ถ๋ ฅ
์ฃผ์ํ ์ ์ ์ด๋ฏธ bind ๋ ๊ฒ์ ๋ค์ bind๋ฅผ ํ ์ ์์ต๋๋ค.
์ฆ, ์ต์ด๋ก bind ํ ๊ฒ์ ๋ํด์๋ง ์ ์ฉ์ด ๋ฉ๋๋ค.
const main = function () {
console.log(this);
};
const mainBind = main.bind({ name: 'mainBind' });
const mainBindBind = mainBind.bind({ name: 'mainBindBind' });
main(); // Window ๊ฐ์ฒด ์ถ๋ ฅ
mainBind(); // {name: 'mainBind'}
mainBindBind(); // {name: 'mainBind'}
๋ ๋ค๋ฅธ ์ฃผ์ํ ์ ์ผ๋ก๋ ํ์ดํ ํจ์์์๋ bind๊ฐ ์ ์ฉ๋์ง ์์ต๋๋ค.
ํ์ดํ ํจ์๋ bind๋ฅผ ํด ์ค ์์ ๋ง์ this๋ฅผ ๊ฐ๊ณ ์์ง ์๊ธฐ ๋๋ฌธ์ bind๋ฅผ ํ ์ ์์ต๋๋ค.
์ ์ธ๋๋ ์์ ์์ ๊ฒฐ์ ์ด ๋๊ณ ์ดํ์๋ ๋ณ๊ฒฝ๋์ง ์๊ธฐ ๋๋ฌธ์ bind๋ฅผ ํด ์ค ์๋ฏธ๊ฐ ์๊ณ bind๋ฅผ ํ๋ค๊ณ ํ๋๋ผ๋ ๋ฌด์๋ฅผ ํด๋ฒ๋ฆฝ๋๋ค.
const obj = {
name: 'yong',
main: function () {
const innerFunction = (() => {
console.log(this);
}).bind({name:'bind'});
innerFunction();
},
};
obj.main(); // {name: 'yong', main: ƒ}
const greet = () => {
console.log(`Hello, ${this.name}`);
};
const boundGreet = greet.bind({ name: 'yong' });
boundGreet(); // 'Hello, undefined'
โ ์ ๋ฆฌ
- this์ ๊ฐ์ ํจ์๊ฐ ์ด๋ป๊ฒ ํธ์ถ๋์๋์ง์ ๋ฐ๋ผ ๋ณํ๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก๋ ํจ์๋ฅผ ํธ์ถํ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ค.
- ์๊ฒฉ ๋ชจ๋์์๋ ์ผ๋ฐ ํจ์์ this๊ฐ 'undefined'์ ๋๋ค.
- ์ผ๋ฐํจ์์์ this๋ '์ ์ญ ๊ฐ์ฒด'๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
- ๊ฐ์ฒด์ ๋ฉ์๋์์ this๋ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
- new ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ์ ํจ์๋ฅผ ํธ์ถํ ๋ 'this'๋ ์๋ก ์์ฑ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
- ํ์ดํ ํจ์๋ ์์ ์ค์ฝํ์ this๋ฅผ ๊ทธ๋๋ก ํ์ฉ
- ์ผ๋ฐ ํจ์: ์คํ ์์ ์์ this๊ฐ ๊ฒฐ์ ๋จ
- ํ์ดํ ํจ์: ์ ์ธ ์์ ์์ this๊ฐ ๊ฒฐ์ ๋จ
- call๊ณผ 'apply ๋ฉ์๋๋ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ๋ฐ์ ํน์ ๊ฐ์ฒด๋ฅผ 'this'๋ก ์ค์ ํ๊ณ , ๋๋จธ์ง ์ธ์๋ค์ ํจ์์ ๋งค๊ฐ๋ณ์๋ก ์ฌ์ฉํ์ฌ ํจ์๋ฅผ ํธ์ถ
- call ๋ฉ์๋๋ ์ฒซ ๋ฒ์งธ ์ธ์๋ฅผ ์ ์ธํ ๋ชจ๋ ์ธ์๋ค์ ํธ์ถํ ํจ์์ ๋งค๊ฐ๋ณ์๋ก ์ง์
- apply ๋ฉ์๋๋ ๋ ๋ฒ์งธ ์ธ์๋ฅผ ๋ฐฐ์ด๋ก ๋ฐ์ ๊ทธ ๋ฐฐ์ด์ ์์๋ค์ ํธ์ถํ ํจ์์ ๋งค๊ฐ๋ณ์๋ก ์ง์
- bind๋ ๋๊ฒจ๋ฐ์ this ๋ฐ ์ธ์๋ค์ ๋ฐํ์ผ๋ก ์๋ก์ด ํจ์๋ฅผ ๋ฐํ
์ฐธ๊ณ ๋ฌธํ: