const circle = new Circle(5); // 이렇게 인스턴스를 만드려면, 생성자 함수가 있어야 한다.
// 그래서 만든 생성자 함수
function Circle(radius) {
// 그런데 생성자 함수 자신이 생성할 인스턴스는 알 수 없다.
????.radius = radius;
}
this : 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수.
this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다.
// 근데... 이렇게는 안되나?
function Rect(self, diagonal) {
self.diagonal = diagonal;
}
var rect = {}; // 이렇게 미리 생성되어 있는 인스턴스라면 되긴 되네..
new Rect(rect, 5);
console.log(rect.diagonal); // 5
다양한 함수 호출 방식
1. 일반 함수 호출
2. 메서드 호출
3. 생성자 함수 호출
4. Function.prototype.apply/call/bind 메서드에 의한 간접 호출
var foo = function () {
console.dir(this);
};
// 1. 함수 호출
foo(); // window
// 2. 메서드 호출
var obj = { foo: foo };
obj.foo(); // obj
// 3. 생성자 함수 호출
var instance = new foo(); // instance
// 4. apply/call/bind 호출
var bar = { name: 'bar' };
foo.call(bar); // bar
foo.apply(bar); // bar
foo.bind(bar)(); // bar
var value = 1;
const obj1 = function() {
console.log("obj1", this.value);
}
const obj2 = {
value: 100,
foo() {
console.log("obj2", this.value);
obj1();
}
}
obj2.foo(); // obj2 안에서 obj1을 호출해봐야 그 this는 window다.
var value = 1;
const obj = {
value: 100,
foo() {
const thisObj = this;
setTimeout(function() {
console.log(thisObj.value); // 100
}, 50); // 50ms만큼 대기
}
};
obj.foo();
var value = 1;
const obj = {
value: 100,
foo() {
setTimeout(function() {
console.log(this.value); // 100
}.bind(this), 50); // this를 명시적으로 바인딩
}
};
obj.foo();
var value = 1;
const obj = {
value: 100,
foo() {
// 화살표 함수의 this는 상위 스코프의 this
setTimeout(() => console.log(this.value), 50);
}
};
obj.foo();
const person = {
name: 'Lee',
getName() {
// 메서드 내부의 this는 메서드를 호출한 객체에 바인딩
return this.name;
}
};
// 메서드 getName을 호출한 객체는 person
console.log(person.getName()); // Lee
// 생성자 함수
function Circle(radius) {
// 생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
}
}
const circle1 = new Circle(5);
const circle2 = new Circle(10);
console.log(circle1.getDiameter); // 10
console.log(circle2.getDiameter); // 20
// new 연산자와 함께 호출하지 않으면 생성자 함수로 동작하지 않는다. 즉, 일반적인 함수의 호출이다.
const circle3 = Circle(15);
// 일반 함수로 호출된 Circle에는 반환문이 없으므로 암묵적으로 undefined를 반환한다.
console.log(circle3); // undefined
// 일반 함수로 호출된 Circle 내부의 this는 전역 객체를 가리킨다.
console.log(radius); // 15
// 주어진 this 바인딩과 인수 리스트 배열을 사용하여 함수를 호출한다
Function.prototype.apply(thisArg[, argsArray])
// 주어진 this 바인딩과 ,로 구분도니 인수 리스트를 사용하여 함수를 호출한다
Function.prototype.call(thisArg[, arg1[, arg2[, ...]]])
// 이게 뭔 🐶소리야
function getThisBinding() {
console.log(arguments); // 오 arguments 이렇게 쓸 수가 있네
return this;
}
// this로 사용할 객체
const thisArg = { a: 1 };
// getThisBinding 함수를 호출하면서 인수로 전달한 객체를 getThisBinding 함수의 this에 바인딩한다.
// apply 메서드는 호출할 함수의 인수를 배열로 묶어 전달한다.
console.log(getThisBinding.apply(thisArg, [1, 2, 3]));
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// {a: 1}
// call 메서드는 호출할 함수의 인수를 쉼표로 구분한 리스트 형식으로 전달한다.
console.log(getThisBinding.call(thisArg, 1, 2, 3));
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// {a: 1}
function getThisBinding() {
return this;
}
// this로 사용할 객체
const thisArg = { a: 1 };
// bind 메서드는 첫 번째 인수로 전달한 thisArg로 this 바인딩이 교체되어 다시 태어난다
console.log(getThisBinding.bind(thisArg)); // getThisBinding
// bind 메서드는 함수를 호출하지는 않으므로 명시적으로 호출해야 한다.
console.log(getThisBinding.bind(thisArg)()); // {a: 1}
| 함수 호출 방식 | this바인딩 |
|---|---|
| 일반 함수 호출 | 전역 객체 |
| 메서드 호출 | 메서드를 호출한 객체 |
| 생성자 함수 호출 | 생성자 함수가 생성할 인스턴스 |
| Function.prototype.apply/call/bind | apply/call/bind에 첫번째 인자로 전달한 객체 |