js, call과 apply api
call과 apply
- 모든 함수는 call과 apply 메서드를 가지고 있다.
- call과 apply는 함수에 인자를 넣는 것과 거의 동일하게 동작한다.
- 다만 call은 인자 각각을 넣고 apply는 배열을 넣는다.
fn(...arg)
와fn(arr)
와 유사하다. - 다만, call과 apply의 첫 번째 인자는, 해당 함수의 컨텍스트로 사용할 객체를 넣는다. 함수 내부에
this
를 사용할 경우 값을 삽입하며, 사용하지 않으면 null을 삽입한다.
<script>const log = console.log;</script>
<script>
// 보통의 함수
function add(x, y){
return x + y;
}
log(add(3,4)); // 7
log(add.call(null, 3,4)); // 7
log(add.apply(null, [3,4])); // 7
// 고차함수
function fn_and_multi(fn){
return function(x,y){
return function(m){
return fn(x,y) * m;
}
}
}
let m = fn_and_multi(add);
let m2 = m.call(null, 2, 3); // 2 + 3 = 5
let m3 = m.call(null, 2, 3)(4); // 5 * 4 = 20
log(m3); // 20
</script>
2. call 과 this
- call을 사용하는 이유는 this를 명시하기 위해서이다.
<script>
function sayHi(){
return this.name;
}
let kim = {name:"kim"};
let choi = {name:"choi"};
log(sayHi.call(kim)); // kim
log(sayHi.call(choi)); // choi
</script>
this의 분실
- call과 apply를 사용하는 중요한 이유는 this가 무엇인지 정의되지 않는 상황을 대응하기 위해서이다.
- 아래 예제를 보자.
- user 객체는
createUserName(name)
을 사용하여 회원의 아이디를 생성한다. createUserName 메서드는 user 객체의registerDate()
메서드를 참조한다. 이때this.registerDate()
형태를 사용한다. 이때 this는 “Object”로서 user를 가리킨다. - 데코레이터 패턴을 적용하기 위하여
createUserNameUpper(fn)
을 정의할 때, 이때fn
는 더 이상 user의 메서드가 아니다. “Window”를 가리킨다. - 이때 this를 명시하기 위하여 apply 와 call을 사용한다.
3. this가 정의되지 않았을 때 명시한다.
<script>
let user = {
registerDate(){
return new Date().getTime();
},
createUserName(name){
log(this);
return `${name}-${this.registerDate()}`
}
}
// log(this) : object
log(user.createUserName("kim")); // kim-{number}
// decorator 적용
function createUserNameUpper(fn){
return function(name){
const upper = name.toUpperCase();
return fn(upper);
}
}
user.createUserName = createUserNameUpper(user.createUserName);
// log(this) : window
// log(user.createUserName('kim')); // Uncaught TypeError: this.registerDate is not a function
function createUserNameUpper(fn){
return function(name){
const upper = name.toUpperCase();
return fn.call(this, upper); // this를 명시한다.
}
}
user.createUserName = createUserNameUpper(user.createUserName);
log(user.createUserName('kim')); // KIM-{number}
</script>
참고 : https://ko.javascript.info/call-apply-decorators