ZeroCho 블로그의 '자바스크립트의 this는 무엇인가?' 글을 참조하여 작성하였습니다.
크롬의 콘솔창에서 this;
를 입력하면 Window 객체를 가리키게 된다.
function a() {
console.log(this);
};
a(); // Window 객체
기본적으로 Window 객체를 가리키는 것을 알 수 있다.
let obj = {
a: function() {
console.log(this);
}
};
obj.a(); // obj
객체 메서드 안의 this
는 해당 객체를 가리킨다.
이는 객체의 메서드를 호출할 때 this
를 내부적으로 바꾸어 주기 때문이다.
하지만 다음과 같이 하면 결과가 달라진다.
let a2 = obj.a;
a2(); // window 객체
호출을 할 때 호출하는 함수가 객체의 메서드인지 그냥 함수인지가 중요하다.
a2
는obj.a
를 꺼내온 것이기 때문에 더이상 obj의 메서드가 아니다.
함수 메서드 삼총사 bind, call, apply 그리고 arguments 글을 참조하도록 하자.
명시적으로 this를 바꾸는 함수 메서드 삼총사 bind
, call
, apply
를 사용하면 this가 Window 객체가 아닌 다른 객체를 가리키도록 할 수 있다.
let obj2 = { c: 'd' };
function b() {
console.log(this);
}
b(); // Window
b.bind(obj2).call(); // obj2
b.call(obj2); // obj2
b.apply(obj2); // obj2
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function() {
console.log(this.name, this.age);
}
생성자 함수도 함수이므로, new
를 사용하지 않고 호출하면
Person('frenchkebab', 26);
console.log(window.name, window.age); // frenchkebab 26
this.name
은 window.name
,
this.age
는 window.age
가 되어버린다.
이를 막으려면 new
예약어를 사용해야 한다.
let hero = new Person('hero', 33); // Person {name: 'Hero', age: 33}
hero.sayHi(); // Hero 33
이렇게 new
를 붙이면 this
가 생성자를 통해 생성된 인스턴스가 된다.
이렇게 실수로
new
를 붙이지 않는 문제를 막는 장치인class
가 ES6에 추가되었다.
document.body.onclick = function() {
console.log(this); // <body>
얘는 그냥 함수인데 this
가 window
가 아니라 <body>
이다.
bind
한 것도 아니고new
를 붙인 것도 아니고그럼 누가 바꾼걸까?
바로 이벤트가 발생할 때, 내부적으로 this
가 바뀐 것이다.
내부적으로 바뀐 것이기 때문에 외우라고 한다...........
$('div').on('click', function() {
console.log(this);
});
이러한 제이쿼리 코드의 경우 this
는 클릭한 div
가 된다.
내부적으로 function을 호출할 때 this를 그렇게 바꾸어 버린다.
이것도 어쩔 수 없이 외우라고 한다.....
$('div').on('click', function() {
console.log(this); // <div>
function inner() {
console.log('inner', this); // inner Window
}
inner();
});
이 경우에는 미쳐버리게도 this
가 window 객체를 가리킨다.
함수의 this
는 기본적으로 window라는 원칙을 충실히 따른 것이다.
click 이벤트 리스너가 내부적으로 this
를 바꾸었음에도 명시적으로 알리지 않은 것이 문제이다.
이를 해결하기 위해서는,
$('div').on('click', function() {
console.log(this); // <div>
var that = this;
function inner() {
console.log('inner', that); // inner <div>
}
inner();
});
이렇게 변수에 this
를 저장해 주어야 한다.
혹은 ES6 화살표 함수를 사용하면 가능하다.
$('div').on('click', function() {
console.log(this); // <div>
const inner = () => {
console.log('inner', this); // inner <div>
}
inner();
});
ES6 화살표 함수는
this
로 window객체 대신 상위 함수의this
를 가져온다. (이 경우<div>
)
this
는 기본적으로 window이다. 하지만 아래의 경우this
가 바뀐다.
- 객체 메서드
bind
,call
,apply
new
그리고 이벤트리스너 등도
this
를 내부적으로 바꿀 수 있으니this
를 확인해 보아야 한다.또한, 내가 선언한 function의
this
는 항상 window라는 것을 잊지 말 것!