함수 호출 방식과 관계 없이 this를 지정할 수 있는 방법 : call, apply, bind

나는야 토마토·2022년 4월 6일
0

JavaScript💛

목록 보기
15/15
post-thumbnail

자바스크립트에서는 일반적인 방법 외에도 함수를 어디서 어떻게 호출했느냐에 관계 없이 this가 무엇인지 지정할 수 있다.

그럼 여기서 this는 정확히 뭔데? 라고 의문이 들 것이다.

this

this는 자바스크립트에서 다른 언어와 비교했을 때 조금 다르게 동작한다. 대부분의 경우, this의 값은 함수를 호출하는 방법에 의해 결정이 되어진다. 자바스크립트에서는 선언하면서 결정되는 것이 있고, 호출할 때 결정되는 게 있다. 선언할 때 결정되는 것은 클로저가 있다. 선언된 위치에 따라 달라진다. this의 핵심은 호출하는 방법에 의해서 결정된다!!

const someone = {
	name: 'yeji',
    whoAmI: function(){
    	console.log(this);
    }
};
someone.whoAmI(); // {name: "yeji", whoAmI: f}

const myWhoAmI = someone.whoAmI;
myWhoAmI(); // Window {postMessage: f, blur: f, ...}

// someone.whoAmI()와 myWhoAmI()는 서로 같은 function을 의미하지만 식을 출력해보면 값이 달라지는 것을 알 수 있다. 호출하는 방법이 달라졌기 때문이다. this를 알기 위해서는 호출을 무엇이 했는지 알아야한다. 즉, 직접 호출하는 그 코드를 살펴보아야 한다.
첫번째 호출하는 someone.whoAmI();의 호출하는 직접적인 부분은 someone인 것이다. myWhoAmI();는 자바스크립트 코드를 실행하는 자체 글로벌에 있고, 글로벌은 window이기 때문에 window가 호출하는 셈인 것이다.
즉, 자바스크립트의 this는 this === 호출한 객체이다!!!

call : this를 특정 값으로 지정

call() 메소드는 모든 함수에서 사용할 수 있으며, this를 특정값으로 지정할 수 있다.

const mike = {
	name: "Mike",
}
const tom = {
	name: "Tom",
}
function showThisName(){
	console.log(this.name);
}

showThisName(); // 아무런 값이 뜨지 않음
showThisName().call(mike); // "Mike"

mike와 tom 객체가 있고, showThisName()이라는 함수가 있다. 이 함수는 this.name을 보여준다. showThisName();을 호출하면 아무런 값이 뜨지 않는다. 왜냐하면 여기서 this는 window를 가르키기 때문에 window.name은 "" 빈 문자열 이어서 아무런 값이 뜨지 않는다.
이 때 showThisName().call();을 해주고 mike를 전달해준다면 Mike가 나오게 된다. 함수를 호출하면서 call을 사용하고 this로 사용할 객체를 넘기면 해당 함수가 주어진 객체의 메소드 인 것처럼 사용할 수 있다.

const mike = {
	name: "Mike",
}
const tom = {
	name: "Tom",
}
function showThisName(){
	console.log(this.name);
}

function update(birthYear, occupation){
	this.birthYear = birthYear;
    this.occupation = occupation;
}

update.call(mike, 1999, "singer");
console.log(mike);
// {name: "mike", birthYear: 1999, occupation: "singer"}
update.call(tom, 2002, "teacher");
console.log(tom);
// {name: "tom", birthYear: 2002, occupation: "teacher"}

call의 첫번째 매개변수는 this로 사용할 값이고, 매개변수가 더 있으면 그 매개변수라는 함수로 전달되어진다.

apply : call과 유사, 매개변수를 배열로 받음

const mike = {
	name: "Mike",
}
const tom = {
	name: "Tom",
}
function showThisName(){
	console.log(this.name);
}

function update(birthYear, occupation){
	this.birthYear = birthYear;
    this.occupation = occupation;
}

update.apply(mike, [1999, "singer"]);
console.log(mike);
// {name: "mike", birthYear: 1999, occupation: "singer"}
update.apply(tom, [2002, "teacher"]);
console.log(tom);
// {name: "tom", birthYear: 2002, occupation: "teacher"}

apply는 함수 매개변수를 처리하는 방법을 제외하면 call과 완전히 같다. call은 일반적인 함수와 마찬가지로 매개변수를 직접 받지만, apply는 매개변수를 배열로 받는다. [] 배열로 묶어주기만 하면call()과 동일한 결과값을 반환한다.

const minNum = Math.min(3, 10, 1, 6, 4);
const maxNum = Math.max(3, 10, 1, 6, 4);

console.log(minNum); // 1
console.log(maxNum); // 10

const nums = [3, 10, 1, 6, 4];
console.log(Math.min(nums)); // NaN
console.log(Math.max(nums)); // NaN

const minNum = Math.min.apply(null, nums);
const maxNum = Math.max.apply(null, nums);
console.log(minNum) // 1
console.log(maxNum) // 10

apply는 배열요소를 함수 매개변수로 사용할 때 유용하다. 최댓값과 최솟값을 구하는 코드가 있다고 하면 배열로 넣었을 시에 NaN이 나오게 된다.
apply()는 두 번째 매개변수로 배열을 전달하게 되면 그 요소들을 차례대로 인수로 사용한다. 그러니깐 (null, nums)사용하면 결과값이 동일하다.

bind : 함수의 this값을 영구히 바꿈

const mike = {
	name: "Mike",
}

function update(birthYear, occupation){
	this.birthYear = birthYear;
    this.occupation = occupation;
}

const updateMike = update.bind(mike);
updateMike(1980, 'police');
console.log(mike);
// {name: "Mike", birthYear: "1980", occupation: "police"}

어떻게 호출되었는지 개의치 않고 설정할 수 있는 것이 bind메소드 이다. 즉, this를 고정시킨다는 의미이다. update함수를 이리저리 옮기면서 호출하면 this값을 "Mike"로 나오게 하려면 bind를 사용하며 된다. const updateMike = update.bind(mike); 이 bind는 새로 바인딩할 함수를 만든다. 이 함수는 항상 mike를 this로 받는다.

const user = {
  name: "Mike",
  showName function(){
  	console.log("hello", ${this.name});
  },
}

user.showName(); // hello, Mike

let fn = user.showName; 
fn(); // hello, -> 아무값도 나오지 않음
fn.call(user); // hello, Mike
fn.apply(user); // hello, Mike

const boundFn = fn.bind(user);
boundFn(); // hello, Mike

fn();을 호출하면 아무값도 나오지 않는다. fn();을 할당할 때 this를 잃어버리게 되는 것이다. 메소드는 .앞에 있는 게 this이다. 호출할 때 fn()만 호출하니깐 this가 없는 것이다. 이럴 때에는 call을 사용하면 fn.call(user); this로 사용할 값 user를 넣어주면 된다.

정리
this는 호출하는 방법에 의해서 결정되어진다. 이는 굉장히 헷갈릴 수 있기 때문에 이와 관계없이 this를 지정하기 위해서는 call, apply, bind를 사용할 수 있다!


참조)

profile
토마토마토

0개의 댓글