
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의 값이 명시적으로 필요할때에, 함수 자체를 받아야 할때에 사용되면 좋다.
'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 |
댓글