어떤 함수가 실행될 때 실행 컨텍스트
(execute context)가 block scope가 아닌 function scope
로 생성된다. 이렇게 생성되는 Javascript의 모든 function scope 내에서 this
라는 특수한 식별자가 자동으로 설정된다. this는 실행컨텍스트의 구성 요소 중 하나로 함수가 실행되는 동안 이용할 수 있다.
현재의 실행 컨텍스트를 기반으로 호출자가 누구인지를 나타내는 식별자이다.
전역 실행컨텍스트의 this, 즉 아무 함수에도 속하지 않은 범위에서 this는 전역객체를 참조한다.
웹 브라우저에서 this를 선언하면 window가 출력된다.
a = 37;
console.log(window.a); // 37
함수 내부에서 this의 값은 기본값으로 전역객체를 참조한다.
function f1() {
return this;
}
// 브라우저
f1() === window; // true
// Node.js
f1() === global; // true
함수를 어떤 객체의 메서드로 호출하면 this
의 값은 그 객체를 사용한다.
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // 37
함수가 정의된 방법이나 위치에 전혀 영향을 받지 않는다. 어디로부터 호출되었는지가 중요.
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37
다른 예시도 살펴보자.
var obj = {
fn: function(a,b) {
return this;
}
};
var obj2 = {
method: obj.fn
};
console.log( obj2.method() === obj2 ); //true
console.log( obj.fn() === obj ); //true
var obj = {
foo: function(){
console.log(this);
}
}
var fn = obj.foo;
console.log(fn();) //window - 주의해야한다. fn이라는 변수에 할당된 함수가 실행된 것이므로 this는 전역객체를 호출한다.
함수를 new
키워드와 함께 생성자로 사용하면 this는 새로 생긴 객체에 묶인다.
function C() {
this.a = 37;
}
var o = new C();
console.log(o.a); // 37
function C2() {
this.a = 37;
return {a: 38};
}
o = new C2();
console.log(o.a); // 38
함수를 실행하는 방법에 function()이외에 call()
, apply()
라는 메서드가 있다. this의 값을 한 문맥에서 다른 문맥으로 넘기려면 이들을 사용해야 한다.
💡call()
나 apply()
의 첫번째 매개변수로 객체를 제공하면 this가 그 객체에 묶인다.
var obj = {a: 'Custom'};
var a = 'Global';
function whatsThis() {
return this.a;
}
whatsThis(); // 'Global'
whatsThis.call(obj); // 'Custom'
whatsThis.apply(obj); // 'Custom'
두 메서드의 첫번째 매개변수 뒤에 이어지는 인수들은 함수 호출에 사용할 매개변수이며 여기서 두 메서드의 차이를 알 수 있다.
function add(c, d) {
return this.a + this.b + c + d;
}
var o = {a: 1, b: 3};
// 이어지는 인수들은 함수 호출에 사용할 매개변수
add.call(o, 5, 7); // 16
// 두 번째 매개변수는 배열,
// 각 요소를 함수 호출에 사용
add.apply(o, [10, 20]); // 34
❓ 그럼 apply()의 두번째 매개변수는 무조건 배열의 형태로만 와야하는 건가?
bind
메서드가 호출되면 새로운 함수를 생성한다. 받게되는 첫번째 인자의 value로는 this 키워드를 설정하고 이어지는 인자들은 바인드된 함수의 인수에 제공된다.
앞의 메서드들과 다르게 새로운 함수를 생성한다는 점!
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81 - 함수의 메서드이므로 전역 스코프가 아닌 부모 obj에서 호출됐음
var retrieveX = module.getX;
retrieveX();
// 9 반환 - 함수가 전역 스코프에서 호출됐음 (주의)
// module과 바인딩된 'this'가 있는 새로운 함수 생성
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
this
화살표 함수에서의 this는 자신을 감싼 정적 범위(lexical context)이다. 즉 this는 바인딩을 하지 않아 자신만의 this를 만들지 않고 자신을 포함하는 외부 scope에서 this를 계승받는다.
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
call(),bind(),apply()를 사용해 호출 할 때 this의 값을 인수로 넘겨줘도 무시된다. 해당 메서드를 화살표 함수에서 사용하려면 첫번째 매개변수를 null로 지정해야 한다.
🩹간단한 예시로 다시 정리해보자!
var obj = {
i:10,
b: () => console.log (this.i,this), //undefined, window
c: function() {
console.log(this.i, this) //10, obj
}
}
참고 출처
MDN | this-Javascript