on
this
this가 정해지는 시기
실행컨텍스트가 활성화 될때 thisBinding을 한다.
실행 컨택스트는 함수가 실행될 때 생성되므로 this는 함수가 실행 될 때 결정된다(동적 binding).
그래서 함수를 어떤 식으로 호출 했느냐에 따라서 this는 얼마든지 달라질 수 있다.
- 전역공간에서 호출 했을 때
- 함수로 호출 했을 때
- 메서드로 호출 했을 때
- callback으로 호출 했을 때
- 생성자 함수로 호출 했을 때
전역 공간에서 호출 했을 때
전역 객체를 가리킨다. 브라우저에서는 window
, node.js 에서는 global
. host 객체라고도 한다.
함수로 호출 했을 때
함수를 호출했을 때도 전역 객체를 가리킨다.
전역 객체에서 함수를 호출했기 때문에 호출한 대상이 전역 객체가 된다.
그런데 내부 함수에서도 this를 전역객체를 가리킨다. 이 부분을 자바스크립트의 오류라고도 이야기한다고 한다.
그래서 ES6에서 나온 게 arrow function이다.
arrow funtion은 thisBinding을 하지 않고 바로 위 컨텍스트에 있는 this를 쓴다.
(하지만 ES5에서는 함수로 호출했을 때의 this는 무조건 전역 객체를 가리킨다.)
메서드로 호출 했을 때
객체내의 함수, 객체의 메서드로 호출 했을 때는 객체가 this로 바인딩 된다.
하지만 메서드 안에서 내부 함수를 호출 했을 때(c();
)는 전역 객체를 가리킨다. (함수에서 this는 무조건 전역객체이기 때문 )
var a = {
b : function(){
console.log(this);
function c (){
console.log(this)
}
c(); // window
}
}
a.b(); // a()
var a = {
b: {
c: function(){
console.log(this);
}
}
}
a.b.c(); // a.b()
객체의 메서드는 인스턴스(객체)와 관련된 동작이다.
메서드는 원래는 함수이지만 어떠한 객체(인스턴스)와 관련된 동작을 하게 되면 메서드라고 칭한다.
메서드 내부 함수에서 this가 전역 객체를 가리키는 문제 해결점
- call, apply 같은 this 바인딩 명령으로 this를 명시시켜 준다.
b : function(){ function c = () =>{ console.log(this.a); // b에서의 this를 따라간다. } c.call(this); }
- this 우회법 : this를 우회해서 표현한다.
- 스코프 체인을 사용해서 다른 변수로 넣어줄 수 있다
var a = 10; var obj = { a : 20, b : function(){ var self = this; // self 말고도 _this, that 등으로도 사용한다 console.log(this.a); // obj를 가리키므로 20 function c (){ console.log(this.a) // window를 가리키므로 10 } c(); function d(){ console.log(self.a); //obj를 가리키게 되서 20 } d(); } } obj.b();
b()
에서this
를self
에 담아 줬기 때문에d()
에서self
를 찾았을 때self
는b()
에서의this
를 담고 있게 된다.
- 스코프 체인을 사용해서 다른 변수로 넣어줄 수 있다
- arrow function을 사용한다 (ES6)
- this를 바인딩하지 않기 때문에 스코프 체인 상에서 상위 this에 바로 접근 할 수 있다.
b : function(){ function c = () =>{ console.log(this.a); // b에서의 this를 따라간다. } c(); }
- this를 바인딩하지 않기 때문에 스코프 체인 상에서 상위 this에 바로 접근 할 수 있다.
callback으로 호출 했을 때
기본적으로는 함수 내부에서와 동일하고(this === 전역객체) 어떻게 호출하느냐에 따라 다르다.
var callback = function(){
console.dir(this);
};
var obj = {
a: 1;
b: function(cb){
cb();
}
}
obj.b(callback);
메소드로 b()
를 실행하면서 callback
을 함수로 넘겨줬다.
obj
의 매개변수 b
에서 callback
이 인자로 넘어가서 cb();
로 호출되었다.
이때 callback
은 매개변수가 아닌 함수의 형태(cb();
)로 실행되었기 때문에 this는 window가 된다.
var callback = function(){
console.dir(this);
};
var obj = {
a: 1;
b: function(cb){
cb.call(this);
}
}
obj.b(callback);
cb()
를 그냥 호출하지 않고 call()
를 이용해서 this를 넘겨주면 b()
컨택스트의 this
인 obj
가 this가 되고 callback
에서 obj
를 this로 받는 다.
이렇게 callback함수에서의 this는 callback함수 자체가 결정하는 것이 아니고 callback 함수를 넘겨받는 대상(위 코드에서는 b()
)이 어떤 형식으로 처리를 하느냐에 따라서 결정된다.
기본적으로 함수라 전역객체이지만 this를 지정해서 처리해주면 그 this를 따른다.
이벤트에서의 callback()
document.body.innerHTML += '<div id="a">클릭하세요</div>';
document.getElementById('a').addEventListener(
'click',
function(){
console.dir(this); // div#a
}
);
addEventListener()
에서이벤트 핸들러로 callback함수를 넘기면 this는 이벤트가 발생한 그 타겟대상 엘리멘트로 호출된다.
이건 addEventListener()
가 callback함수를 처리할 때 this를 그렇게 지정하도록 정의가 되어 있기 때문이다.
이벤트 실행시에도 this를 지정해주고 싶으면 아래 코드처럼 콜백함수에 this를 bind 시켜주면 된다.
document.getElementById('a').addEventListener(
'click',
function(){
console.dir(this); // div#a
}.bind(obj)
);
callback으로 호출 했을 때의 this 정리
- callback 함수는 기본적으로 함수의 this와 같다. (전역객체 window)
- 제어권을 가진 함수가 콜백의 this를 지정해둔 경우도 있다. (ex.
addEventListener()
) - 이 경우에도 this를 바인딩해서 콜백에 넘기면 그 this를 따른다.
생성자 함수로 호출 했을 때
생성자 함수 new 연산자를 사용 했을 때의 this는 무엇을 가리킬까?
new 연산자를 썼다는 말은 생성자 함수의 내용을 바탕으로 인스턴트 객체를 만드는 명령이다.
새로 만들 인스턴트 객체 그 자체가 this가 된다.
function Person(n, a){
this.name = n;
this.age = a;
}
var laura = Person('로라', 20);
console.log(window.name, window.age); // 로라 20
이렇게 함수로 Person()
을 실행하면 this는 전역객체 window가 들어가게 되므로 window의 프로퍼티 name
과 age
로 값이 들어간다.
function Person(n, a){
this.name = n;
this.age = a;
}
var laura = new Person('로라', 20);
console.log(laura); // Person(){name: '로라', age:20}
new 연산자를 사용해서 Person
을 생성자 함수로 호출하면 laura
라는 변수에 Person
의 인스턴트 객체가 생성되어 들어가는 데 이때 this
는 인스턴트 자신이므로 this는 Person()
이 되어 Person()
의 name
과 age
에 각각 ‘로라’, 20이라는 값이 할당되어 생성된다.
Reference
- 인프런 코어 자바스크립트
Discussion and feedback