읽는 데 4분 12. March 2020
Function.prototype.call가 뭐죠?

기본 사용

Function.prototype.call은 모든 함수에서 사용할 수 있다. 첫번째 매개변수는 call 함수가 실행하는 함수에 컨텍스트로 전달한다. 예를 들어, TwoNumber라는 함수가 있고, 이 함수안의 summul 함수는 생성자를 통해 받은 매개변수 두개의 값을 더하거나 곱해서 반환하는 함수다.

function TwoNumber(a, b) {
  this.a = a
  this.b = b

  this.sum = function () {
    return this.a + this.b
  }

  this.mul = function () {
    return this.a * this.b
  }
}

const n = new TwoNumber(1, 2)

const sum = n.sum()
const mul = n.mul()

console.log(sum, mul)

// output: 3 2

두 개의 매개변수를 받아서 각각 변수 a와 b에 저장하고 summul은 해당 객체가 가지고 있는 a와 b를 더하거나 곱해서 값을 반환하는 간단한 함수다. call 함수를 사용하면 call 함수가 호출하는 객체에 재할당한다.

const _d = n.sum.call({ a: 3, b: 5 })
const _e = n.mul.call({ a: 3, b: 5 })

console.log(_d, _e)

console.log(n.sum(), n.mul())

// output: 8 15
//         3 2

기존 출력 값이 3 2이고 call 함수를 이용해서 재할당한 객체의 출력 값은 8 15이다. 기존 객체는 유지가 된다는 걸 알 수 있다.

클래스 흉내

/** @param {string} name */
/** @param {number} age */
function Animal(name, age) {
  this.name = name
  this.age = age
}

function Dog(name, age) {
  Animal.call(this, name, age)
  this.bark = function () {
    console.log(`${this.name}: wal! wal!`)
  }
}

function Bird(name, age) {
  Animal.call(this, name, age)
  this.bark = function () {
    console.log(`${this.name}: Jak! Jak!`)
  }
}

const dog = new Dog('James', 2)
const bird = new Bird('Ari', 1)

dog.bark()
bird.bark()

// output: James: wal! wal!
//          Ari: Jak! Jak!

이름과 나이 값을 매개변수로 받고 해당 객체에 바인딩 시키는 함수 Animal과 이 함수와 관련된 Dog, Bird 함수가 있다. 각각의 함수는 Animal 함수와 마찬가지로 이름과 나이를 매개변수로 받고 Animal을 호출한다. 여기서, this 값으로 Animal을 호출하고 입력받은 이름과 나이를 같이 넘긴다.

해당 객체로 재할당 시킨다. bark 함수는 각각 '이름: wal! wal!', '이름: Jak! Jak!'을 출력한다. 이렇듯 타 언어에서 클래스를 사용해서 만들 수 있는 기능은 자바스크립트에서는 이런 방식으로 흉내낼 수 있다. (ES6 부터는 타 언어에서 사용하던 것 처럼 class로 작성하고 super()나 constructor()를 사용하면 된다)

마치 Animal 클래스를 상속받은 Dog, Bird 클래스를 구현한 것과 같은 흉내를 낼 수 있다.

객체의 타입 알아내기

Object.prototype.toString 함수는 객체 내의 this 값을 보고 객체 타입을 문자열로 반환한다. call 함수를 응용하면 this 값을 매개변수로 오는 값으로 바꿔 타입 값을 확인할 수 있다.

console.log(Object.prototype.toString.call(undefined))
console.log(Object.prototype.toString.call(null))
console.log(Object.prototype.toString.call(true))
console.log(Object.prototype.toString.call([]))
console.log(Object.prototype.toString.call(function () {}))
console.log(Object.prototype.toString.call(new Date()))
console.log(Object.prototype.toString.call(/^abc+d/))
console.log(Object.prototype.toString.call(23455))
console.log(Object.prototype.toString.call(1.234))
console.log(Object.prototype.toString.call(-0.2))
console.log(Object.prototype.toString.call('undefined'))
console.log(Object.prototype.toString.call(new Error('error')))

// output:  [object Undefined]
//          [object Null]
//          [object Boolean]
//          [object Array]
//          [object Function]
//          [object Date]
//          [object RegExp]
//          [object Number]
//          [object Number]
//          [object Number]
//          [object String]

참고