[Javascript] this 바인딩
JS this 바인딩, JS this, JS this binding, call apply bind
정의
JavaScript 의 this 는 호출 방식에 따라 결정 되는 동적 바인딩. 4 가지 호출 방식 + arrow function (lexical) 규칙.
5 가지 규칙
| # | 규칙 | 예 | this 값 |
|---|---|---|---|
| 1 | 일반 호출 | fn() | undefined (strict) / globalThis |
| 2 | 메서드 호출 | obj.fn() | obj |
| 3 | 명시적 | fn.call(x), fn.apply(x) | x |
| 4 | 생성자 | new Fn() | 새 인스턴스 |
| 5 | 화살표 | () => {} | lexical (정의 위치) |
메서드 vs 일반 호출
const obj = {
name: 'Alice',
greet() { return this.name; }
};
obj.greet(); // 'Alice' (메서드 호출)
const fn = obj.greet;
fn(); // undefined (일반 호출, strict)
함수를 변수에 담는 순간 컨텍스트 손실.
call / apply / bind
fn.call(thisArg, arg1, arg2);
fn.apply(thisArg, [arg1, arg2]);
const bound = fn.bind(thisArg, arg1);
- call: 즉시 호출, 인자 쉼표
- apply: 즉시 호출, 인자 배열
- bind: 새 함수 반환 (this 영구 바인딩)
function greet(prefix, suffix) {
return `${prefix} ${this.name} ${suffix}`;
}
greet.call({name: 'A'}, 'Hi', '!'); // 'Hi A !'
greet.apply({name: 'A'}, ['Hi', '!']); // 'Hi A !'
const bound = greet.bind({name: 'A'}, 'Hi');
bound('!'); // 'Hi A !'
화살표 함수의 lexical this
class Counter {
constructor() {
this.count = 0;
setInterval(() => {
this.count++; // ✓ Counter 인스턴스의 this
}, 1000);
}
}
화살표 함수는 자체 this 가 없다. 정의 위치의 this 를 사용. arrow function 참고.
일반 함수였다면
setInterval(function() {
this.count++; // ❌ this 는 globalThis 또는 undefined
}, 1000);
// 옛 해결책
const self = this;
setInterval(function() {
self.count++;
}, 1000);
new 호출
function Person(name) {
this.name = name; // 새 객체에 할당
}
const p = new Person('Alice');
p.name; // 'Alice'
new 호출 시:
- 새 빈 객체 생성
[[Prototype]] = Person.prototypethis = 새 객체- 함수 실행
- 명시적 return 객체 없으면 새 객체 반환
이벤트 핸들러
button.addEventListener('click', function() {
console.log(this); // button (DOM element)
});
button.addEventListener('click', () => {
console.log(this); // 외부 스코프의 this (window 등)
});
DOM 이벤트는 일반 함수면 this = 이벤트 타겟. 화살표 함수면 외부 this.
class 메서드의 this
class Btn {
constructor() { this.clicks = 0; }
onClick() { this.clicks++; } // this 손실 위험
}
const b = new Btn();
button.addEventListener('click', b.onClick); // ❌ this 가 button
button.addEventListener('click', b.onClick.bind(b)); // ✓
button.addEventListener('click', () => b.onClick()); // ✓
class Btn2 {
clicks = 0;
onClick = () => this.clicks++; // ✓ class field arrow, auto bound
}
우선순위
1. new 바인딩 (가장 강함)
2. 명시적 (call/apply/bind)
3. 메서드 호출
4. 일반 호출 (가장 약함)
const a = { name: 'a' };
const b = { name: 'b' };
function greet() { return this.name; }
const bound = greet.bind(a);
bound.call(b); // 'a' (bind 가 call 보다 우선)
함정
1. arrow 함수에 call 무의미
const fn = () => this;
fn.call({ x: 1 }); // 외부 this 그대로 반환
2. 메서드 분리
const obj = { greet() { return this; } };
const m = obj.greet;
m(); // undefined (강제 변환 없는 strict 모드)
3. nested 함수
const obj = {
name: 'A',
outer() {
function inner() {
return this.name; // undefined!
}
return inner();
}
};
해결: 화살표 함수 또는 변수 보존.
참고
이 글의 용어 (5개)
- [Javascript] Arrow Functionjavascript
- 정의 화살표 함수 (arrow function) 는 ES2015 (ES6) 에서 도입된 함수 표현식. 모양. 더 짧은 문법뿐 아니라 가 lexical 로 바인딩 되는 본질적 차이…
- [Javascript] Classjavascript
- 정의 ES6 는 prototype chain 위의 문법 설탕. C++/Java 스타일 OOP 와 닮았지만 내부는 . 구조 상속 super 의 의미 - : 부모 constructo…
- [Javascript] functionjavascript
- 정의 은 JavaScript 에서 함수를 만드는 가장 기본적인 키워드. 호이스팅, 동적 바인딩, 객체, 호출 등 과 구분되는 고유한 특성을 가진다. 함수가 값 으로 다뤄지는 의 …
- [Javascript] Lexical Environmentjavascript
- 정의 Lexical Environment (어휘적 환경) 는 ECMAScript 명세 (§9.1) 가 정의한 내부 객체. 함수가 호출될 때마다 새로 만들어지며, 이 호출의 변수들…
- [Javascript] Prototype Chainjavascript
- 정의 JavaScript 의 모든 객체는 (내부 슬롯) 을 가진다. 속성 lookup 시 자신에게 없으면 prototype chain 을 따라 올라가며 검색. 접근 함수의 pro…
💬 댓글