🌈 인프런의
코어 자바스크립트(정재남)
수강 후, 이해한 내용을 정리한 글입니다.
VariableEnvironment, LexicalEnvironment, ThisBinding이다.
이 중 ThisBinding에 대해 알아보자.
Biding은 값을 결정하는 행위이다. 즉, ThisBinding이란 This를 결정하는 행위이다.
앞서 말했듯이 ThisBinding은 Execution Context의 구성요소이다. 그러므로 this를 binding 하는 시점은 Execution Context가 활성화될 때 즉, 함수가 호출될 때이다.
this를 호출하는 방식에 의해 결정된다. this를 호출하는 방식에는 5가지의 경우의 수가 있다.
하나씩 살펴보자.
1) 전역 공간에서 this 호출: 전역 객체
전역 공간에서 this를 호출하면 전역 객체인 window
혹은global
이 바인딩된다. 둘의 차이는 런타임의 차이이다.
// 브라우저에서
console.log(this) // window
// node.js에서
console.log(this) // global
2) 함수 호출 시 this 호출: 전역 객체
(예외: 화살표 함수)
함수 호출 시에 this를 호출하면 전역 객체인 window
혹은global
이 바인딩 된다. 주의할 점은 전역 공간이 아닌 함수 내부에서 함수가 호출돼도 전역 객체가 바인딩 된다는 것이다.
// 브라우저에서
function a() {
console.log(this); // 🟢 window
}
a(); // 🟢 함수 호출 => 전역 객체 바인딩
function b() {
function c() {
console.log(this); // 🔵 window
}
c(); // 🔵 함수 호출 => 전역 객체 바인딩
}
b();
하지만 화살표 함수는 예외이다. 화살표 함수는 자신을 포함하고 있는 함수의 this 바인딩을 상속한다. 아래는 함수 c를 함수 선언식으로 선언한 경우와 화살표 함수로 선언한 경우를 비교한 것이다.
// Case1. 함수 선언식
var a = 10;
var obj = {
a: 20;
b: function() {
console.log(this.a);
function c () {
console.log(this.a); // window.a = 10
}
c()<; // 함수 호출 => 전역 객체 바인딩
}
}
obj.b();
// Case2. 화살표 함수
var a = 10;
var obj = {
a: 20;
b: function() {
console.log(this.a); // 2️⃣ obj.a = 20
const c = () => {
console.log(this.a); // 4️⃣ 스코프 체인 => obj.a = 20
}
c(); // 3️⃣ 바인딩 ❌
}
}
obj.b(); // 1️⃣ 메서드 b 호출 => 메서드 호출한 객체 obj 바인딩
함수 선언식의 경우 바인딩하므로 바인딩 된 전역 객체가 this가 된다. 하지만 화살표 함수는 바인딩하지 않고 상속하므로 스코프 체인을 타고 외부 함수 b의 this인 obj를 함수 c의 this에 그대로 할당한다.
3) 메서드 호출 시 this 호출: 메서드를 호출한 주체
메서드 호출시 this를 호출하면 메서드를 호출한 주체가 바인딩된다. 즉, 메서드 명 앞의 객체가 바인딩 된다.
// 예제1
var a = {
b: function() {
console.log(this); // a
}
}
a.b() // 메서드 b 호출 => 메서드를 호출한 객체 a 바인딩
// 예제2
var a = {
b: {
c: function () {
console.log(this); // a.b
}
}
}
a.b['c'](); // 메서드 c 호출 => 메서드를 호출한 객체 a.b 바인딩
4) callback 호출 시 this 호출: 개발자가 바인딩한 객체
→제어권을 가진 함수가 지정한 객체
→ 전역 객체
callback 호출 시 this를 호출하면 개발자가 바인딩한 객체, 제어권을 가진 함수가 지정한 객체, 전역 객체가 우선순위로 바인딩 된다. 아래 예시를 보자.
개발자가 바인딩한 객체, 제어권을 가진 함수가 지정한 객체, 전역 객체가 모두 존재하는 경우 개발자가 바인딩한 객체가 바인딩 된다.
// Case1. 개발자가 바인딩한 객체⭕️ 제어권을 가진 함수가 지정한 객체⭕️ 전역 객체⭕️
// => 개발자가 바인딩한 객체 바인딩
document.body.innerHTML += '<div id="a">클릭하세요</div>';
var obj = {a: 1};
document.getElementById('a').addEventListener(
'click',
// 1️⃣ 개발자가 obj 객체 바인딩
function() {
console.dir(this); // 2️⃣ obj
}.bind(obj)
);
개발자가 바인딩한 객체가 없고 제어권을 가진 함수가 지정한 객체, 전역 객체만 존재하는 경우 제어권을 가진 함수가 지정한 객체가 바인딩 된다.
// Case2. 개발자가 바인딩한 객체❌ 제어권을 가진 함수가 지정한 객체⭕️ 전역 객체⭕️
// => 제어권을 가진 함수가 지정한 객체 바인딩
document.body.innerHTML += '<div id="a">클릭하세요</div>';
document.getElementById('a').addEventListener(
'click',
// 1️⃣ 개발자가 바인딩하지 않음 → addEventListener가 지정한 객체인 currentTarget 바인딩
function() {
console.dir(this); // 2️⃣ <div id="a">클릭하세요</div>
}
);
개발자가 바인딩한 객체, 제어권을 가진 함수가 지정한 객체가 없고 전역 객체만 존재하는 경우 전역 객체가 바인딩 된다.
// Case2. 개발자가 바인딩한 객체❌ 제어권을 가진 함수가 지정한 객체❌ 전역 객체⭕️
// => 전역 객체 바인딩
var callback = function() {
console.dir(this); // 2️⃣ window(브라우저)
};
var obj = {
a: 1;
};
// 1️⃣ 개발자가 바인딩하지 않음 → setTimeout가 지정한 객체 없음 → 전역 객체
setTimeout(callback, 100);
5) 생성자 함수 호출 시 this 호출: 인스턴스
생성자 함수 호출 시 this를 호출하면 인스턴스 객체가 바인딩 된다.
function Person(n, a) {
this.name = n; // 2️⃣ roy.name = '재남'
this.age = a; // roy.age = 30
}
var roy = new Person('재남', 30); // 1️⃣ 생성자 함수 Person 호출 => 인스턴스인 roy 바인딩
console.log(roy); // 3️⃣ {name: '재남', age: 30}
전역공간
과 2️⃣함수 호출 시
에는 전역 객체, 3️⃣메서드 호출 시
에는 메서드를 호출한 주체, 4️⃣callback 호출 시
에는 개발자가 바인딩한 객체, 제어권을 가진 함수가 지정한 객체, 전역 객체를 우선순위로, 5️⃣생성자 함수 호출 시
에는 인스턴스가 this에 바인딩된다.