본문 바로가기
JavaScript | 자바스크립트

함수의 메서드 - call, apply, bind

by Pig_CoLa 2020. 7. 17.
SMALL

this에서 잠깐 튀어나왔던 call, apply, bind에 대해 다루는 글이다.

 

함수를 호출하는 일반적인 방법은 함수뒤에 전달인자를 소괄호 ( )로 묶어 호출하게된다.

이러한 방법말고 call, apply와 같이 원하는 this와 전달인자를 바인딩하여 실행하는 메서드가 있고,

bind와 같이 무언가를 바인딩한 함수 자체를 돌려주는 메서드가 있다.

사용방법

함수명.call, 함수명.apply, 함수명.bind로 메서드 이기 때문에 역시 호출해줘야 한다.

각 메서드 모두 첫번째 전달인자로는 this를 받는다.

 

호출할 함수가 this에 관한 작업을 하지 않는다면 null, undefined등 어떤값을 넣어주어도 무방하다.

다만 undefined는 의도치 않게 들어갈 수도 있는 값이기 때문에 null을 써주어 의도한것임을 명시하길 권장한다.

 

아래는 각각의 특성과 세부적인 사용방법이다.

call

함수명.call(this, ...전달인자들)

특징으로는 전달인자를 rest파라미터로 풀어진채로 받는다.

function hi(a, b) {
    this.num += a
    this.num /= b
}

let obj = {num: 30}

hi.call(obj, 70, 20) // this에 obj가 바인딩되어 함수가 동작한다.
console.log(obj.num) // 5

apply

함수명.apply(this, [전달인자1, 전달인자2, ...])

특징으로는 전달인자를 하나의 배열로 받는다.

function hi(a, b) {
    this.num += a
    this.num /= b
}

let obj = {num: 30}

hi.apply(obj, [70, 20]) // this에 obj가 바인딩되어 함수가 동작한다.
console.log(obj.num) // 5

bind

함수명.bind(this, ...전달인자들)

특징으로는 전달인자를 rest파라미터로 받으며, 함수의 호출이 이뤄지지 않고,

this와 전달인자가 바인딩되어있는 함수 자체를 돌려준다.

함수 자체를 넣어줘야 하지만 this값은 명시적으로 넣어줘야 할 상황에 쓰이기 좋다.

function hi(a, b) {
    this.num += a
    this.num /= b
}

let obj = {num: 30}

let boundHi = hi.bind(obj, 70, 20) // this에 obj가 바인딩된 함수가 return 된다.
console.log(obj.num) // 30

boundHi()
console.log(obj.num) // 5

다른 prototype의 메서드 사용하기

가령 숫자만 있는 배열에서 Math.max와 같은 Math의 메서드를 사용하고 싶어도

배열이기에 사용이 불가능하여 동일한 기능을 하는 함수를 제작하거나,

유사배열(Array가 아니지만 배열의 형태를 띄고있는)에서 배열의 메서드를 사용하고 싶을때

call, apply 등을 활용하여 사용할 수 있다.

let arr = [9,1,2,5,4,3,6]

Math.max(arr) // NaN

Math.max.apply(null, arr) // 9

// Math.max(...arr)와 동일하나 예시를 위해 작성하였을 뿐이다.
let comments = document.querySelectorAll('.comment')
// NodeList(5) [li.comment, li.comment, li.comment, li.comment, li.comment]

comments.filter((val) => (val.textContent === 'hi'))
// Uncaught TypeError: comments.filter is not a function

Array.prototype.filter.call(comments,(val) => (val.textContent === 'hi'))
// [요소의 textContent가 'hi'인 필터된 무언가들]

bind로 커링

커링이 무엇인지는 저번 클로저에서 설명하였다.

그럼 커링을 구현하기 위해선 클로저만 가능할까?

 

bind메서드를 사용하면 this뿐만 아니라 전달인자도 바인딩되기 때문에

원하는 전달인자만 미리 바인딩 해둔 뒤 재사용이 가능하다.

function sumAandB(a, b) {
    return a + b
}

let sum100 = sumAandB.bind(null, 100)

sum100(40) // 140
sum100(26) // 126
sum100(11) // 111

setTimeout / setInterval

함수를 비동기로 호출하기 위하여

setTimeout 또는 setInterval을 사용할 수 있다.

위 함수들의 특징중 하나는 함수 자체를 전달인자로 넣어야 하는것으로

setTimeout(함수, ms(1/1000 단위초), ...전달인자들)과 같은 구문으로 사용된다.

 

하지만 위 함수의 단점은 전달인자로 받은 함수의 this에 window가 바인딩 된다.

이때에 bind메서드를 사용해서 this의 값을 명시적으로 바인딩 하여 사용할 수 있다.

let obj = {log: function () {console.log(this)}, num: 33}
// 화살표 함수는 this를 바인딩하지 않기때문에 사용하게되면 무조건 window를 가르키게된다.

obj.log() // {num: 33, log: ƒ}

// 해당 메서드를 setTimeout을 이용해 1초뒤에 실행하게 만든다면

setTimeout(obj.log, 1000) // bind 사용 안함
3 // setTimeout id

// 1초 뒤

// Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}

setTimeout(obj.log.bind(obj), 1000) // bind 사용
4 // setTimeout id

// 1초 뒤

// {num: 33, log: ƒ}

이와같이 this의 값이 명시적으로 필요할때에, 함수 자체를 받아야 할때에 사용되면 좋다.

LIST

'JavaScript | 자바스크립트' 카테고리의 다른 글

복잡도 - 시간복잡도  (0) 2020.07.19
재귀호출  (0) 2020.07.18
this  (0) 2020.07.16
DOM - 2  (0) 2020.07.16
DOM - 1  (0) 2020.07.15

댓글