this는 위와 같이 일반 함수 표현식 / 화살표 함수 표현식에서 다르게 동작하지만, 일반 함수 표현식에서의 this는 함수가 어떻게 호출되는지에 따라 또 달라진다. 일반 함수가 함수로 사용되었는지, 메서드로 사용되었는지에 따라 다르게 동작한다.
01. 일반 함수 표현식에서 this
일반 함수에서의 this는 동적 바인딩을 따른다.
즉, 함수가 어떻게 호출되었는지에 따라 this가 결정된다.
#1. 함수 내에서 호출하는 this
기본적으로 함수가 독립적으로 호출되면, this는 전역 객체(window, global)를 참조한다.
🔎 ex1) 전역 함수 호출 시 this
function Constructor() {
this.field = 0; // Constructor 객체 내 this.field = 0
function inner() {
console.log(this.field); // 전역 객체의 field (undefined)
}
inner(); // 호출 컨텍스트: 전역 객체
}
var object = new Constructor(); // new 키워드를 사용해 Constructor를 객체화
전역에서 호출된 일반 함수의 this는 전역 객체를 참조한다.
inner()는 Contructor 내부에 있지만, 독립적인 함수로 호출되므로 inner() 내부의 this는 전역 객체를 참조한다.
이때 전역 객체에 field 속성이 없으므로 undefined가 출력된다.
🔎 ex2) 타이머 함수 안에서의 this
function Constructor() {
this.field = 0; // Constructor 객체 내 this.field = 0
setInterval(function inner() {
console.log(this.field); // 전역 객체의 field (undefined)
}, 1000);
}
var object = new Constructor();
setInterval()과 같이 타이머 함수 내부에서 일반 함수가 호출되면, 그 함수의 this 역시 전역 객체를 가리ㅣㄴ다.
setInterval 내부의 inner() 함수는 일반 함수로 호출되므로, this는 전역 객체를 가리키고, 전역 객체에 field 속성이 없어 undefined가 출력된다.
💡 함수 내 this는 객체로 초기화되지 않는 한 전역 객체를 가리킨다.
this는 함수가 객체로 초기화되지 않는 한, 전역 객체를 가리키며 일반 함수 표현식에서 내부 함수나 콜백 함수 등은 기본적으로 전역 객체를 가리킨다. 그러나 함수가 객체로 초기화되면, 그 함수 내에서 this는 전역 객체가 아닌 객체화된 함수를 가리킨다.
아래 예시 코드를 보면 객체화되었을 때와 기본적으로 전역 객체를 가리키는 this의 차이를 명확하게 알 수 있다.
function Constructor1() {
this.field = 0; // Constructor1 객체의 field
console.log(this.field); // 0, Constructor1 객체의 field
function doublewrapper() {
this.field = 1; // 전역 객체의 field
console.log(this.field); // 1, 전역 객체의 field
function Constructor2() {
console.log(this.field); // undefined, Constructor2 객체의 field
}
new Constructor2();
}
doublewrapper(); // 호출 컨텍스트: 전역 객체
}
new Constructor1();
console.log(field); // 전역 객체의 field = 1
Contructor1에서 this
new Counstuctor1()에 의해 Constructor1은 객체로 초기화되었기 때문에, Contructor1에서 this는 Constructor1객체를 가리킴
this.field = 0은 Constructor1 객체 내에 속성이 설정된 것. this.field는 0을 출력
doublewrapper() 함수 내에서 this
doublewrapper()는 객체화되지 않았으므로 doublewrapper() 함수 내 this는 전역 객체를 가리킴
this.field = 1은 전역 객체의 field를 1로 설정
전역 객체의 field 값인 1을 출력
Constructor2에서 this
new Constructor2()에 의해 객체화 되어 this는 Counstructor2 객체를 가리킴
Constructor2 객체에는 field 속성이 없기 때문에 undefined가 출력
#2. 메서드 내에서 호출하는 this
메서드는 객체의 속성으로 정의된 함수이다.
메서드에서의 this는 메서드를 소유한 객체를 가리킨다. 즉, 메서드가 속한 객체가 this로 바인딩된다.
[JavaScript] this : 함수/메서드 내 this 차이
자바스크립트에서의 this는 일반 함수 표현식과 화살표 함수 표현식에서 다르게 동작한다.
this는 위와 같이 일반 함수 표현식 / 화살표 함수 표현식에서 다르게 동작하지만, 일반 함수 표현식에서의 this는 함수가 어떻게 호출되는지에 따라 또 달라진다. 일반 함수가 함수로 사용되었는지, 메서드로 사용되었는지에 따라 다르게 동작한다.
01. 일반 함수 표현식에서 this
일반 함수에서의 this는 동적 바인딩을 따른다.
즉, 함수가 어떻게 호출되었는지에 따라 this가 결정된다.
#1. 함수 내에서 호출하는 this
기본적으로 함수가 독립적으로 호출되면, this는 전역 객체(window, global)를 참조한다.
🔎 ex1) 전역 함수 호출 시 this
전역에서 호출된 일반 함수의 this는 전역 객체를 참조한다.
inner()는 Contructor 내부에 있지만, 독립적인 함수로 호출되므로 inner() 내부의 this는 전역 객체를 참조한다.
이때 전역 객체에 field 속성이 없으므로 undefined가 출력된다.
🔎 ex2) 타이머 함수 안에서의 this
setInterval()과 같이 타이머 함수 내부에서 일반 함수가 호출되면, 그 함수의 this 역시 전역 객체를 가리ㅣㄴ다.
setInterval 내부의 inner() 함수는 일반 함수로 호출되므로, this는 전역 객체를 가리키고, 전역 객체에 field 속성이 없어 undefined가 출력된다.
💡 함수 내 this는 객체로 초기화되지 않는 한 전역 객체를 가리킨다.
this는 함수가 객체로 초기화되지 않는 한, 전역 객체를 가리키며 일반 함수 표현식에서 내부 함수나 콜백 함수 등은 기본적으로 전역 객체를 가리킨다. 그러나 함수가 객체로 초기화되면, 그 함수 내에서 this는 전역 객체가 아닌 객체화된 함수를 가리킨다.
아래 예시 코드를 보면 객체화되었을 때와 기본적으로 전역 객체를 가리키는 this의 차이를 명확하게 알 수 있다.
#2. 메서드 내에서 호출하는 this
메서드는 객체의 속성으로 정의된 함수이다.
메서드에서의 this는 메서드를 소유한 객체를 가리킨다. 즉, 메서드가 속한 객체가 this로 바인딩된다.
Object.method()가 실행되면 this.field의 this는 호출한 객체인 Object 객체를 참조한다. 메서드가 객체의 속성이기 때문이다.
따라서 this.field는 Object 객체의 field 값을 참조하여 0을 출력한다.
02. 화살표 함수 표현식에서 this
화살표 함수에서 this는 정적 바인딩을 따른다.
이는 화살표 함수가 선언된 위치의 스코프에서 this가 결정된다는 의미이다.
화살표 함수 내부의 this는 상위 스코프의 this를 유지한다.
앞서 setInterval() 안에 일반 함수 표현식으로 작성된 inner() 함수 안에서의 this는 전역 객체를 가리켰다.
반면 위의 예시 코드처럼 setInterval()안에 화살표 함수 표현식으로 작성하면, 화살표 함수 내 this는 Constructor 객체를 가리킨다.
따라서 this.field는 Contructor 객체의 field 값을 가리켜 0을 출력한다.
즉, 화살표 함수는 setInterval을 감싸고 있는 Contructor 함수의 this를 참조하므로, 화살표 함수 내 this는 고정적으로 Constructor 객체를 가리키는 것이다.
일반 함수 표현식에서의 함수, 메서드 내 this와 화살표 함수 표현식에서의 this의 차이를 요약하면 다음과 같다.
object.method()와 object.method_shorten()에서는 this가 object를 가리키고, nickname을 잘 출력한다.
하지만 object.arrow_function()에서는 화살표 함수의 this가 상위 스코프인 전역 객체를 가리키기 때문에 nickname을 찾지 못하고 undefined가 출력된다.
03. 명시적 바인딩(Explicit Binding) - call, apply, bind
명시적 바인딩은 자바스크립트에서 this를 명시적으로 설정하는 방법이다.
함수가 호출될 때 어떤 객체가 this로 설정되어야 하는지를 명시적으로 지정할 수 있다.
이때 주로 사용하는 메서드가 call, apply, bind이다.
#1. 암시적 바인딩(Implicit Binding)
암시적 바인딩은 객체의 메서드로 호출된 함수에서 자동으로 그 객체를 this로 사용한다.
즉, 메서드가 속한 객체가 자동으로 this로 바인딩된다.
#2. 명시적 바인딩(Explicit Binding)
명시적 바인딩은 call, apply, bind를 사용해 함수 호출 시 this를 명시적으로 지정하는 것이다.
#3. 명시적 바인딩과 일반 함수, 화살표 함수의 this 차이
◼︎ 일반 함수에서의 명시적 바인딩
createObject.call({ foo: 21 })로 createObject 함수의 this를 { foo: 21 }로 명시적으로 설정하였다.
따라서 console.log('Inside `createObject`:', this.foo);는 Inside 'createObject' : 21이 출력된다.
내부 bar 메서드는 createObject가 반환한 객체 내에서 호출되므로, this는 그 객체를 가리키며 Inside 'bar' : 42가 출력된다.
◼︎ 화살표 함수에서 명시적 바인딩
bar는 화살표 함수이므로 상위 스코프의 this를 참조하며, this는 정적이다.
따라서 createObject.call에 전달된 { foo: 21 }로 고정되며, createObject 함수의 this를 참조하게 된다.
화살표 함수는 외부 함수(createObject)의 this를 고정으로 사용하므로, 명시적 바인딩으로 this가 바뀌지 않으며 { foo: 21 }의 값이 출력된다.
'ASAC > Front-End' 카테고리의 다른 글