본문 바로가기
JavaScript/JavaScript

JavaScript call apply bind 살펴보기

by 봉이로그 2023. 5. 10.

call / apply / bind를 왜 알아야 할까?

 

위 3가지는 자바스크립트에서 함수 호출 방식을 다양하게 제어 할 수 있도록 도와주는 중요한 기능이다.

함수호출 시 자바스크립트의 this를 명시적으로 지정하여 핸들링 할 수 있기때문이다.

 

여기서 this란?

자바스크립트에서 this값이란 함수를 호출할 때 참조할 객체를 의미한다.

함수 내에서 this를 사용하면 해당 함수를 호출한 객체를 가리킨다.

함수를 다른 방식으로 호출 할 경우 this값이 예기치 않게 변경될 수 있다.

그러한 점을 방지하기 위해 call / apply / bind를 사용하여 this 값을 명시적으로 지정해 줄 수 있다.

 

call

첫번째 인자에 명시할 this객체를 넘기고, 두번째 인자에는 함수 파라미터값을 넘긴다.

apply와 다른점은 두번째 인자가 배열형태가 아니다.

// call.js

const people = { name: "애니" };

const introduceWithJob = function (job) {
  console.log(`${this.name}의 직업은 ${job} 입니다.`);
};

// typescript에서는 this가 명시적으로 타입선언이 안되어 있기에 컴파일상 에러발생
introduceWithJob("개발자"); // undefined의 직업은 개발자 입니다.

// fn.call(this, thisArgs)
introduceWithJob.call(people, "PM"); // 애니의 직업은 PM 입니다.

const introduceWithJobAge = function (job, age) {
  console.log(`${this.name}의 직업은 ${job} 입니다. 나이는 ${age} 입니다.`);
};

introduceWithJobAge.call(people, "작가", 32); // // 애니의 직업은 작가 입니다. 나이는 32 입니다.

 

// call.ts

const obj = {
  name: "일번",
  introduce: function (job: string, age?: number) {
    console.log(`${this.name}의 직업은 ${job} 입니다. 나이는 ${age} 입니다.`);
  },
};

obj.introduce("개발자"); // 일번의 직업은 개발자 입니다. 나이는 undefined 입니다.

obj.introduce.call({ name: "이번" }, "PM", 33); // 이번의 직업은 PM 입니다. 나이는 33 입니다.

 

 

apply

첫번째 인자에 명시할 this객체를 넘기고, 두번째 인자에서는 함수 내부에서 사용되는 파라미터값을 넘긴다.

이때 call과는 다르게 두번째 인자가 배열형태 이다.

// apply.js

const people = { name: "애니" };

const introduceWithJob = function (job) {
  console.log(`${this.name}의 직업은 ${job} 입니다.`);
};

// typescript에서는 this가 명시적으로 타입선언이 안되어 있기에 컴파일상 에러발생
introduceWithJob("개발자"); // undefined의 직업은 개발자 입니다.

// fn.apply(this, thisArgs[함수인자1, 2, ...])
introduceWithJob.apply(people, ["PM"]); // 애니의 직업은 PM 입니다.

const introduceWithJobAge = function (job, age) {
  console.log(`${this.name}의 직업은 ${job} 입니다. 나이는 ${age} 입니다.`);
};

introduceWithJobAge.apply(people, ["작가", 32]); // 애니의 직업은 작가 입니다. 나이는 32 입니다.
// apply.ts

const obj = {
  name: "일번",
  introduce: function (job: string, age?: number) {
    console.log(`${this.name}의 직업은 ${job} 입니다. 나이는 ${age} 입니다.`);
  },
};

obj.introduce("개발자"); // 일번의 직업은 개발자 입니다. 나이는 undefined 입니다.

obj.introduce.apply({ name: "삼번" }, ["디자이너", 33]); // 삼번의 직업은 디자이너 입니다. 나이는 33 입니다.

 

 

bind

apply와 동일하게 첫번째는 함수내부에서 사용할 this 값을 명시적으로 넘긴다.

두번째 인자부터 apply와 동일하게 배열형태로 객체를 넘긴다.

그러나, 두번째 인자부터는 apply처럼 하나의 배열안에 함수의 인자개수 만큼 넣는것이 아니라,

배열타입을 함수의 인자개수 만큼 넣어야한다.

또한 함수를 실행하는게 아니라 함수를 반환하게 된다.

 

apply 예시: fn.apply(this, ["홍길동", "학생"]);

bind 예시: const returnFunc = fn.bind(this, ["홍길동"], ["학생"]);

 

// bind.js

const people = { name: "애니" };

const introduceWithJobAge = function (job, age) {
  console.log(`${this.name}의 직업은 ${job} 입니다. 나이는 ${age} 입니다.`);
};

const bindIntroduceWithJobAge = introduceWithJobAge.bind(people, ["작가"], [32]); // bind를 사용하면 함수를 return 한다.

bindIntroduceWithJobAge(); // 애니의 직업은 작가 입니다. 나이는 32 입니다.

people.name = "민수";

const bindIntroduceWithJobAge2 = introduceWithJobAge.bind(people, ["큐레이터"], [26]); // bind를 사용하면 함수를 return 한다.

bindIntroduceWithJobAge2(); // 민수의 직업은 큐레이터 입니다. 나이는 26 입니다.