var obj1 = {
name: 'Lee',
getName() {
// 메소드 내부의 this는 메소드를 호출한 객체에 바인딩된다
return this.name;
}
};
// sayName메소드를 obj1객체가 호출하고 있다 -> obj1에 객체에 바인딩된다
console.log(obj1.sayName()); // Lee
const otherObj = {
name : 'Kim'
};
// otherObj에 새로운 프로퍼티 할당
otherObj.getName = obj1.getName;
// 변수에 할당
const getName = obj1.getName;
// 일반함수로서! 호출
// 이때 this는 전역객체 window를 가리키게 됨! window.name의 기본값은 ''임
console.log(getName()); // ''
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
};
var me = new Person('Lee');
// getName 메서드를 호출한 객체는 me다.
// 그래서 me객체의 name에 접근해서 값을 호출
console.log(me.getName()); // Lee
// Person.prototype의 name프로퍼티는 아직 undefined
console.log(Person.prototype.getName()); // undefined
Person.prototype.name = 'Kim';
// getName 메서드를 호출한 객체 Person.prototype의 name프로퍼티에 접근
console.log(Person.prototype.getName()); // Kim
생성자 함수 호출을 통한 바인딩 확인하기
// 생성자 함수
function Circle1(radius) {
// 생성자 함수 내부의 this는 생성자 함수가 앞으로 생성할 인스턴스를 가리킨다.
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius; // this.radius는 상위의 값을 기리킴!
};
}
// this.radius를 없애고, 메소드 내부에서 radius로 바꾸면 똑같이 동작!
function Circle2(radius) {
this.getDiameter = function () {
return 2 * radius; // <- this.radius
};
}
// 반지름이 5인 Circle 객체를 생성
const circle1 = new Circle1(5);
// 반지름이 10인 Circle 객체를 생성
const circle2 = new Circle1(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
console.log(getDiameter()) // 30
일반적인 함수의 호출로 사용할 때
// 일반적인 함수의 호출로 사용할 때
const circle3 = Circle1(15);
// 일반 함수로 호출된 Circle에는 반환문이 없으므로 암묵적으로 undefined를 반환한다.
console.log(circle3); // undefined
// 일반 함수로 호출된 Circle 내부의 this는 전역 객체를 가리킨다.
console.log(radius); // 15
console.log(circle3.radius) //TypeError: Cannot read properties of undefined (reading 'radius')
console.log(circle3.getDiameter()) // TypeError: Cannot read properties of undefined (reading 'getDiameter')
궁금해서 찍어본 console
function Circle3(radius) {
this.radius3 = radius * 2
return 3* radius;
}
console.log(Circle3(100)) // 300
console.log(Circle3(100).radius3) // undefined
circle4 = Circle3(100)
console.log(circle4) // 300
💡 apply, call, bind 메소드는 모두 Function.prototype의 메소드이기 때문에,
모든 함수가 상속받아서 사용할 수 있습니다.
📕 개념
💡 apply와 call메소드의 본질적인 기능은 함수를 호출하는 것으로 같습니다.
다만 호출할 때 인수전달 방식에 차이가 있습니다.
apply메소드는 호출할 함수에 전달될 인수를 배열로 묶어서 전달하고,
call메소드는 인수를 쉼표로 구분해 리스트 형식으로 전달하면서 호출합니다.apply, call과 함께 묶여서 언급되는 bind 메소드는 함수를 따로 호출하지 않고, this로 사용하고자 하는 객체만 담아서 전달합니다.
🔍 용도
💡 apply와 call메소드는
arguments객체와 같은 유사 배열 객체에 배열 메소드를 사용하는 경우에 사용될 수 있습니다.
💡 bind 메소드는
메소드 내부의 this와, 메소드 내부의 중첩함수/콜백함수의 this의 불일치에서 오는 문제를 해결하기 위해서 사용됩니다.
🦾 쓰임새
상속받아보기
function getThisBinding() {
return this;
}
// this로 사용할 객체
const thisArg = { a: 1 };
// console.log(getThisBinding()); // window 정보 출력
// getThisBinding 함수를 호출하면서 인수로 전달한 객체를 getThisBinding 함수의 this에 바인딩한다.
console.log(getThisBinding.apply(thisArg)); // {a: 1}
console.log(getThisBinding.call(thisArg)); // {a: 1}
apply, call 기본 사용 & 유사배열객체에 배열 메소드 사용
function getThisBinding() {
console.log(arguments);
const arr = **Array.prototype.slice.call**(arguments);
// const arr = Array.prototype.slice.apply(arguments);
console.log("함수내부 arr : ", arr); // 함수내부 arr : [ 1, 2, 3 ]
return this;
}
// this로 사용할 객체
const thisArg = { a: 1 };
// getThisBinding 함수를 호출하면서, 인수로 전달한 객체(thisArg)를 함수의 this에 바인딩한다.
// **apply메서드** : 호출할 함수의 인수를 배열로 묶어 전달한다.
console.log(getThisBinding.apply(thisArg, [1, 2, 3]));
// [Arguments] { '0': 1, '1': 2, '2': 3 }
// { a: 1 } // <- 함수내부의 this
// **call 메서드** : 호출할 함수의 인수를 쉼표로 구분한 리스트 형식으로 전달한다.
console.log(getThisBinding.call(thisArg, 1, 2, 3));
// [Arguments] { '0': 1, '1': 2, '2': 3 }
// { a: 1 } // <- 함수내부의 this
this 기본 & this불일치 문제 해결
function getThisBinding() {
return this;
}
// this로 사용할 객체
const thisArg = { a: 1 };
// bind 메서드는 함수에 this로 사용할 객체를 전달한다.
// bind 메서드는 함수를 호출하지는 않는다.
console.log(getThisBinding.bind(thisArg)); // getThisBinding
// bind 메서드는 함수를 호출하지는 않으므로 명시적으로 호출해야 한다.
console.log(getThisBinding.bind(thisArg)()); // {a: 1}
const person = {
name: 'Lee',
foo(callback) {
// bind 메서드로 callback 함수 내부의 this 바인딩을 전달
setTimeout(callback.bind(this), 100);
}
};
person.foo(function () {
console.log(`Hi! my name is ${this.name}.`); // Hi! my name is Lee.
});