객체는 상태를 나타내는 프로퍼티와 동작을 나타내는 메서드를 하나의 논리적인 단위로 묶은 복합적인 자료구조입니다.
객체 내부의 메서드는 자신이 속한 객체를 가리키는 특별한 식별자인 this를 사용할 수 있습니다.
this
는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수
(self-referencing variable) 입니다.
this에 바인딩되는 값은 함수 호출 방식에 의해 동적으로 결정됩니다.
함수 호출 방식 | this 바인딩 |
---|---|
일반 함수 호출 | 전역 객체 |
메서드 호출 | 메서드를 호출한 객체 |
생성자 함수 호출 | 생성자 함수가 (미래에) 생성할 인스턴스 |
Function.prototype.apply/call/bind 메서드에 의한 간접 호출 | Function.prototype.apply/call/bind 메서드에 첫번째 인수로 전달할 객체 |
const foo = fuction() {
console.dir(this);
}
// 1️⃣ 일반 함수 호출
foo(); // window
// 2️⃣ 메서드 호출
// foo 프로퍼티에 함수 객체를 할당해 호출
const obj = { foo };
obj.foo(); //obj
// 3️⃣ 생성자 함수 호출
new foo(); // foo {}
// 4️⃣ Function.prototype.apply/call/bind 메서드에 의한 간접 호출
const bar = { name: 'bar' };
foo.apply(bar); //bar
foo.call(bar); //bar
foo.bind(bar); //bar
// ✚ 메서드 내의 중첨함수여도 일반함수로 호출되며녀 this가 전역 객체로 바인딩된다.
const obj2 = {
value: 100,
foo() {
console.log("foo's this: ", this) // {value: 100, foo: f}
// 메서드 내에서 정의한 중첩함수
function bar() {
console.log("bar's this: ", this) // window
}
bar();
}
};
obj.foo();
// 중첩 함수의 역할은 헬퍼 함수인데 외부 함수인 메서드와 this에 바인딩된 값이 다르면 안된다 ->
// 1. 변수를 만들어 참조하기
const obj3 = {
value: 100,
foo() {
const that = this;
function bar() {
console.log("bar's this.value: ", that.value) // 100
}
bar();
}
};
obj.foo();
// 2. Function.prototype.apply/call/bind 메서드 사용
const obj4 = {
value: 100,
foo() {
function bar() {
console.log("bar's this.value: ", this.value);
}
bar.bind(this)(); // bar에 .bind(this)를 적용한 후 실행
}
};
obj4.foo();
// 3. 화살표 함수 사용
const obj5 = {
value: 100,
foo() {
const bar = () => {
console.log("bar's this.value: ", this.value);
};
bar();
}
};
obj4.foo();
apply
, call
, bind
는 Function.prototype의 메서드이므로 모든 함수가 상속받아 사용할 수 있습니다.
apply
와 call
의 본질적인 기능은 함수를 호출하는 것입니다. 또한 첫번째 인자로 this로 사용할 객체를 받아 바인딩합니다.
두번째 인자로는 함수에 전달할 인자 리스트를 받습니다. 여기서 차이가 있는데 apply
는 인수를 배열로 묶어 전달하고, call
은 인수를 쉼표로 구분해 전달합니다.
function getThisBinding() {
console.log(arguments);
return this;
}
// this로 사용할 객체
const thisArg = { value: 1 };
console.log(getThisBinding.apply(thisArg, [1, 2, 3]));
// Arguments(3) [1, 2, 3, callee: f, Symbol(Symbol.iterator): f]
// {value: 1}
console.log(getThisBinding.call(thisArg, 1, 2, 3));
// Arguments(3) [1, 2, 3, callee: f, Symbol(Symbol.iterator): f]
// {value: 1}
bind
는 함수를 호출하지 않고 this로 사용할 객체만 전달합니다.
function getThisBinding() {
return this;
}
// this로 사용할 객체
const thisArg = { value: 1 };
console.log(getThisBinding.bind(thisArg)());
// {value: 1}
참고자료
모던 자바스크립트 Deep Dive