자바스크립트에서의 this
는 어디서든 사용할 수 있고, 상황에 따라 this
가 바라보는 대상이 달라진다.
기본적으로 실행 컨텍스트가 생성될 때 함께 생성된다. 즉, this
는 함수가 호출될 때 결정된다.
함수 안에서만 사용 가능하고 약속된 변수라고 할 수 있다. 변수처럼 작동하지만, this는 수정될 수 없다.
this
는 전역객체(window / global)을 가르킨다.console.log(this);
console.log(window);
console.log(this === window); // true
this
는 전역객체(window / global)을 가르킨다.// 함수 내부에서 this 호출
function a() {
console.log(this);
}
a();
// 외부함수 b의 내부함수 c 내부에서 this 호출
function b() {
function c() {
console.log(this);
}
c();
}
b();
// d 객체 내의 메소드 e 안에 있는 f함수 내부에서 this 호출
var d = {
e: function() {
function f() {
console.log(this);
}
f();
}
}
d.e();
this
는 메소드 호출하는 주체를 가르킨다.this
가 된다.var a = {
b: function() {
console.log(this);
}
}
a.b(); // a 객체를 가르킨다. {b: f()}
var a = {
b: {
c: function() {
console.log(this);
}
}
}
a.b.c(); // a.b의 객체를 가르킨다. {c: f()}
함수는 전역객체의 메소드다 라고 생각하면 편하다..ㅎ
this
는 기본적으로 함수 내부에서와 동일하다.(기본적으로 함수의 this
와 같다.)callback
의 this
를 명시한 경우 그에 따른다.this
를 바인딩한 채로 callback
을 넘기면 그에 따른다.var callback = function() {
console.dir(this);
};
var obj = {
a: 1,
b: function(cb) {
cb(); // window
cb.call(this); // 전혀 다른 결과
}
};
obj.b(callback);
setTimeout(callback, 100);
setTimeout(callback.bind(obj), 100);
bind
가 없었던 시절에는 한 번 더 감싸서 변수를 이용하는 방식으로 활용했다.
this
는 인스턴스(instance
)를 가르킨다.function Person(n, a) {
this.name = n;
this.age = a;
}
var mook = new Person("mook", 30);
console.log(mook);
call, apply, bind 메소드에 대해 이해를 해야한다.
function a(x, y, z) {
console.log(this, x, y, z);
}
var b = {
c: "eee"
};
a.call(b, 1, 2, 3);
a.apply(b, [1, 2, 3]);
var c = a.bind(b);
c(1, 2, 3);
var d = a.bind(b, 1, 2);
d(3);
결과는 ▸Object {c: "eee") 1 2 3
으로 동일하게 출력된다.
func.call(thisArg[, arg1[, arg2[, ...]]])
즉시 호출을 하는 명령이다.
첫번째 인자는 this
를 받고, 두번째 인자부터 쭉 나열해서 받는다.
func.apply(thisArg, [argsArray])
즉시 호출을 하는 명령이다.
첫번째 인자는 this
를 받고, 두번째 인자는 매개변수를 담은 배열을 받는다.
func.bind(thisArg[, arg1[, arg2[, ...]]])
call
과 apply
와 달리 bind
는 새로운 함수를 생성(currying)할뿐 호출을 담당하지는 않는다.
첫번째 인자는 this
를 받고, 두번째 인자부터 쭉 나열해서 받는다.
내부함수에서의 우회법
var a = 10;
var obj = {
a: 20,
b: function() {
console.log(this.a); // 20
function c() {
console.log(this.a); // 10
}
c();
}
}
obj.b();
obj.b()
는 메소드 호출이라 obj
객체를 가리키고, c()
는 일반함수 호출이라 전역의 a
를 가르킨다.
그렇다면 함수 c
안에서 obj을 바로볼 수 있게 this를 사용할 수는 없을까?
결론부터 말하자면, 스코프 체인(Scope Chain)을 이용해 우회가 가능하다.
var a = 10;
var obj = {
a: 20,
b: function() {
var self = this;
console.log(this.a); // 20
function c() {
console.log(self.a); // 10
}
c();
}
}
obj.b();
위와 같이 this
를 self
라는 변수에 담고, 변수 self
를 활용하면 내부함수는 자신의 스코프에서 self
을 바라보고 찾다가 없으면 스코프 체인을 타고 상위로 올라가며 this
를 탐색한다.
var a = 10;
var obj = {
a: 20,
b: function() {
console.log(this.a);
},
c: () => {
console.log(this.a);
}
}
obj.b(); // 20
obj.c(); // 10
화살표 함수는 실행컨텍스트 생성시 this
를 바인딩하지 않는다.
화살표함수 내부에 this
가 존재하지 않기 때문에 스코프 체인에 따라 상위 컨텍스트의 this
에 접근하게 된다.
따라서 obj.c()
는 상위 컨텍스트의 this
가 전역객체를 가리키기 때문에 10
이 된다.
🔎 참고자료 🔎
- MDN
- 생활코딩
- PoiemaWeb
- javascript info
- 코어 자바스크립트
- 러닝 자바스크립트
- 인사이드 자바스크립트