객체지향 프로그래밍으로 변환하는 과정에서 분명히 같은 객체의 메소드로 this를 호출하는데 "not a function", "undefiend"라는 오류에 빠지게 되어 this에 대해 정리를 해보고자 한다.
메소드 안에서 사용시 함수를 소유한 객체를 가리킨다.
여기서 중요한 점은 호출한 방법으로 객체가 결정된다는 것이다.
즉, 어떤 놈이 this를 호출했어?
let person = {
name: "KIM",
age: 34,
printThis: function () {
console.log(this); // 메소드에서 this 호출
},
};
person.printThis(); // person이 호출한 놈이다. 즉 this는 person 객체를 뜻한다.
let printThis = person.printThis;
printThis(); // 호눌한 놈은 생략된 'window'다. 즉 this는 window가 된다.
person.printThis(), printThis() 둘 모두 같은 메소드를 호출 했지만,
this가 가리키는 객체는 다르게 나온다.
여기서 printThis() 는 앞에 window.printThis() window가 생략되있다.
결국 person의 메소드 printThis를 호출했지만 호출한놈이 window 이기 때문에
this가 가리키는 객체는 window가 된다.
위와 같은 "호출한놈"이 언어적인 흐름으로 바라본다면 혼동이 오기 쉽다.
let btn = document.querySelector("button");
let person = { name: "kim" };
person.printThis = function () {
console.log(this);
};
person.printThis(); // 함수를 호출한놈이 person이니깐 this는 person을 가져온다.
btn.addEventListener("click", person.printThis); // 같은 함수 호출인데 btn을 가져온다.
이벤트 처리로 클릭시 person.printThis()를 호출하는데 여기서 this는 btn객체를 가리킨다.
"메소드를 "호출한놈"이 btn(Html tag)이 되기 때문이다. (내가 오류에 빠진 이유...)
위와 같은 문제를 해결하기 위해 ES5에서 bind가 태어났다.
btn.addEventListener("click", person.printThis.bind(person));
person.printThis는 객체 person에 싸여있다고 알려주는 것이다!
btn클릭시 this가 person객체를 가리키고 있다. (해결)
let person = {
name: "kim",
age: 34,
printPerson: function () {
console.log(`이름은 ${this.name}입니다. 나이는 ${this.age}살 입니다.`);
},
hello: function () {
setTimeout(function () {
console.log(this);
});
},
};
person.printPerson(); // person이 호출했으니 this는 person을 가져온다.
person.hello(); // person이 호출했으나 함수안에 콜백(setTimeour)이 존재해서 this는 window 가져온다.
person객체의 두 메소드를 실했 했으나 setTimeout 콜백함수가 존재하는 hello메소드에서 this는 window를 가르킨다.
"호출한놈"이 콜백(setTimeout)이 되기 때문이다. (window.setTimeout)
let person = {
name: "kim",
age: 34,
printPerson: function () {
console.log(`이름은 ${this.name}입니다. 나이는 ${this.age}살 입니다.`);
},
hello: function () {
setTimeout(
function () {
console.log(this);
}.bind(this) // bind 적용
);
},
};
setTimeout 콜백함수에 bind(this)로 (여기서 this는 상위 함수(hello)의 this)
hello의 this 즉, person 객체를 가리키게 할 수 있다.
위에서 this는 "호출한놈" 혹은 "window(생략)"를 가리켰다.
하지만, Arrow Function => 문법을 사용하면 조금 달라진다.
화살표 함수는 자신을 포함하고 있는 외부 scope에서 this를 계승받는다.
let person = {
name: "kim",
printThis: function () {
setTimeout(() => {
console.log(this);
});
},
};
person.printThis();
즉, 위 hello 메소드 내에서 콜백 함수시 사용된 bind를 사용 하지 않아도 된다.
Arrow Function을 사용 한다면 bind의 사용 없이 더욱 클린 코딩이 가능하지만,
"외부 스코프에서 계승 받는다" 를 매우 주의 해야 한다.
let person = {
name: "KIM",
printThis: () => {
console.log(this);
}
};
person.printThis()를 실행 하면 window 객체가 호출된다.
호출한놈 person이지만 => 함수를 사용하여 person의 외부 스코프(window)를 계승 받는다.
-addEventListener함수의 콜백 함수에서 사용하면 안된다.
let btn = document.querySelector("button");
btn.addEventListener("click", () => {
console.log(this === window);
});
click 이벤트가 호출하는 this는 window가 된다.
호출한놈 btn이지만 => 함수를 사용하여 btn의 와부 스코프(window)를 계승 받는다.
객체지향 프로그래밍으로 this를 자주 사용하게 되는데 "호출한놈"과 "bind" 그리고 화살표 함수를 잘 이용하여 원하는 객체를 가져 올 수 있도록 하자.