Function.prototype.call
MDN에서는 다음과 같이 설명한다.
The call() method calls a function with a given this value and arguments provided individually.
즉, 함수의 내장 메소드인데, 함수가 실행될 때의 this 를 인자로 주어진 값으로 바꾸어서 실행한다는 말이다.
Syntax는 아래와 같다.
func.call([thisArg[, arg1, arg2, ...argN]])
예로,
const obj = {
testString: 'test',
sayTestString: function() {
console.log(this.testString);
}
};
const obj2 = {
testString: 'test2'
};
obj.sayTestString(); // 'test';
obj.sayTestString.call(obj2); // 'test2'
처음에 obj.sayTestString
이라는 메소드를 실행했을 때, this
가 obj
이기 때문에 test
가 출력된다.
두번째의 경우 call
메소드에 obj2
를 인자로 넘겨주는 것으로 sayTestString
메소드가 실행될 때의 this
를 obj2
로 바꾸어 주었다. 그렇기 때문에, obj2
의 testString
인 test2
가 로그에 출력된다.
만약, call
을 통하여 실행하는 메소드가 인자를 받는다면, call
메소드에 인자로 넘겨주면 된다. 예로,
const obj = {
testString: 'test',
sayTestString: function(str1, str2) {
console.log(`${this.testString} ${str1} and ${str2}`);
}
};
const obj2 = {
testString: 'I received:',
};
obj.sayTestString.call(obj2, 'abc','def'); // 'I received: abc and def'
Function.prototype.apply
apply
메소드는 call
과 동일하다. 다만, 넘겨지는 인자를 하나의 배열에 담아서 넘겨준다는 것에서 차이가 있다. Syntax 는 아래와 같다.
func.apply(thisArg, [ argsArray])
const obj = {
testString: 'test',
sayTestString: function(str1, str2) {
console.log(`${this.testString} ${str1} and ${str2}`);
}
};
const obj2 = {
testString: 'I received:',
};
obj.sayTestString.apply(obj2, ['abc','def']); // 'I received: abc and def'
그렇다면 call, apply 는 언제 사용하는 걸까?
주로 배열 메소드를 유사 배열 객체(array like object)에 사용할 때를 들 수 있다.
유사배열 객체란, 배열의 형태를 가진 객체를 말한다. 객체가 유사배열로 취급되기 위해서는 2가지 조건이 충족되어야 한다.
length
라는 key 값이 반드시 있어야 한다. length
의 value 값으로는 객체 내용물의 갯수가 담긴다.예시를 보자.
위의 조건에 따르면, 유사 배열 객체는 아래와 같이 구성된다.
const obj = {
0: ‘a’,
1: ‘b’,
2: ‘c’,
length: ‘3’
}
각각의 내용물에 접근하기 위해서는, obj[0]
와 같이 접근하면 된다. 그 길이를 알기 위해선 obj.length
를 하면 된다. 분명히 객체이지만, 마치 배열 처럼 접근하는 것을 볼 수 있다.
하지만, 유사배열 객체에 배열 메소드를 사용하면 실행이 되지 않는다. 당연하게도 그 이유는, 이 객체가 유사배열이지 진짜 배열은 아니기 때문이다.
const obj = {
0: 'a',
1: 'b',
2: 'c',
length: '3'
}
obj.push('d'); // TypeError: obj.push is not a function
이러한 상황에서, call
혹은 apply
를 사용하면, 배열 메소드를 유사배열에 사용할 수 있다.
const obj = {
0: 'a',
1: 'b',
2: 'c',
length: '3'
}
Array.prototype.push.call(obj, ‘d’);
// { '0': 'a', '1': 'b', '2': 'c', '3': 'd', length: 4 }
여기서 주목해야할 점이 하나 있다. 새로 넣어준 d
가 3
이라는 key값으로 들어갔다는 것.
위와 같이 유사 배열 객체에 배열 메소드를 사용하여 객체를 정보를 추가할 때,length
에 따라서 다음 index
값이 새로운 key 값이 된다.
그렇기 때문에, 만약 유사 배열에 들어있는 내용물의 key들이 인덱스의 형태가 아닐 경우, 문제의 가능성이 생긴다.
const obj = {
a: ‘a’,
b ‘b’,
c: ‘c’,
length: ‘3’
}
Array.prototype.push.call(obj, ‘d’);
// { '3': 'd', a: 'a', b: 'b', c: 'c', length: 4 }
위와 같이 여전히 3 이라는 키값으로 들어가기 때문에, 키값의 통일성이 사라지고, 배열의 순서 특성을 잃게 된다.
유사배열 객체는 에서 종종 나타나는데, 예로 html collection 이 있다.
const arrLike = document.querySelectorAll(‘div’);
bind 메소드에 대해서 MDN 에서는 다음과 같이 설명한다.
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
즉, 특정 함수의 this 를 인자로 넘겨진 값으로 지정해준다.
예로,
const obj = {
testString: 'test',
testFunction: function() {
console.log(this.testString);
}
}
const getFunction = obj.testFunction;
getFunction(); // undefined
const getFunctionBinded = getFunction.bind(obj);
getFunctionBinded(); // test
getFunction
이 처음 호출 되었을 때, this
는 Window
이다. 그렇기 때문에, testString
을 찾지 못해 undefined
를 반환한다.
obj
안에 있는 testString
에 접근하기 위해서는, bind
메소드를 통해 this
를 obj
로 지정해 주어야 한다. bind
로 지정해 준 이후, 함수를 호출하면 test
라고 로그에 찍히는 것을 확인할 수 있다.
정독했습니다. 코딩 잘하시네요