전의 포스팅으로 this에 바인딩될 객체는 함수 호출 방식에 따라 결정된다는 것을 알아보았습니다. 하지만 개발자가 명시적으로 바인딩하는 방법은 없을까요?
func.apply(thisArg, [argsArray])
apply는 첫인자에 func함수 this에다가 바인딩할 객체, argsArray에 함수에 전달할 argument 배열을 받습니다.
var Person = function (name) {
this.name = name;
};
var foo = {};
// apply 메소드는 생성자함수 Person을 호출한다. 이때 this에 객체 foo를 바인딩한다.
Person.apply(foo, ['jinwoo']);
console.log(foo); // { name: 'jinwoo' }
apply 메소드의 본질적인 기능은 함수 호출이며 this를 특정 객체에 바인딩해주는 것 입니다.
위의 예시를 이해해봅시다. 먼저 Person이라는 함수가 선언되어있습니다. Person의 객체에는 this의 name 프로퍼티가 선언되어있습니다.
apply의 첫번째 인자에 바인딩할 객체 foo를 할당하고, 두 번째 인자에 함수에 전달할 argument를 넣어줍니다.
그리고 foo를 호출해주면 this가 잘 바인딩되어 foo에서 name 프로퍼티가 동적으로 값이 할당됨을 볼 수 있습니다.
call 메소드의 경우 apply와 기능은 같지만 두번째 인자의 배열의 형태로 넘겨주던 것을 하나의 인자로 넘겨준다는 차이점이 있습니다.
Person.apply(foo, [1, 2, 3]);
Person.call(foo, 1, 2, 3);
그렇다면 이 둘 메소드를 사용하는 예시를 살펴봅시다.
function Person(name) {
this.name = name;
}
Person.prototype.doSomething = function(callback) {
if(typeof callback == 'function') {
// --------- 1
callback();
}
};
function foo() {
console.log(this.name); // --------- 2
}
var p = new Person('Lee');
p.doSomething(foo); // undefined
1의 시점에서 callback을 실행합니다. Person 객체에서 실행하기 때문에 this는 Person을 가리킵니다.
2의 시점을 볼까요. 다들 아시다시피 일반함수의 this는 전역객체 window를 가리킵니다. 따라서 마지막 줄에 콜백을 실행하는 모습을 보면 this가 상이하기 때문에 undefined가 발생하는 것을 확인할 수 있습니다.
앞서 살펴본 apply, call 을 사용해 상이한 this를 바이딩 시켜 올바른 작동을 구현해볼 수 있습니다.
function Person(name) {
this.name = name;
}
Person.prototype.doSomething = function (callback) {
if (typeof callback == 'function') {
callback.call(this);
callback.apply(this); // 위의 call과 같습니다.
}
};
function foo() {
console.log(this.name);
}
var p = new Person('Lee');
p.doSomething(foo); // 'Lee'
bind는 this가 바인딩된 새로운 함수를 리턴해줍니다. 다만 apply와 call 메소드와 같이 함수를 실행하지 않기 때문에 명시적으로 함수를 호출 해야합니다.
function Person(name) {
this.name = name;
}
Person.prototype.doSomething = function (callback) {
if (typeof callback == 'function') {
callback.bind(this)();
}
};
function foo() {
console.log(this.name);
}
var p = new Person('Lee');
p.doSomething(foo); // 'Lee'
this가 호출 방식에 따라 정해지고 어떤 특성으로 정해지는 지 알아보고, 또 개발자가 직접 바인딩해주는 방법도 알아보았습니다.
우리의 자바스크립트는 앞서 알아본 바에 의하면 생성자 함수를 의도하고 만들어진 함수를 그냥 함수로 호출할 수도 있습니다. 명시적인 차이는 없으니깐요. 그렇다면 만약 의도한 바와 다르게 사용하게 된다면 예상하지 못한 에러가 발생될것입니다. 생성자 함수는 생성자 함수로 사용되길 기대하고 만들었기 때문이죠.
이를 생성자 함수를 작성할 때 위험성을 아에 회피하는 패턴을 만든다면 어떨까요? 든든~하지 않을까요?
다음 포스팅에선 이를 위험성을 회피하기 위해 사용되는 패턴을 알아보겠습니다.!
참고: 책- 모던자바스크립트 딥 다이브