능히 해낼 수 있다

230820 JavaScript: call, apply, bind 본문

개발🌐/JavaScript

230820 JavaScript: call, apply, bind

roni_eo 2023. 8. 20. 14:50
반응형

✍️✍️✍️ 위 글은 작성자의 지식습득에 따라 추후 퇴고 될 수 있음을 알려드립니다(피드백 환영). + 230820 추가 및 수정


JavaScript에서는 일방적인 방법 외에도 함수 호출하는 방식과 관계없이 call, apply, 그리고 bind 내장메서드를 활용해 this 값을 바꿀 수 있다(this가 무엇인지를 지정할 수 있게된다).

1. call

모든 함수에서 사용할 수 있고 this를 특정값으로 지정이 가능하다. call 메서드는 함수를 호출하는 방법 중 하나로, 첫 번째 인자로 함수 내부에서 사용될 this 값을 설정하고, 그 뒤에는 함수의 매개변수를 전달한다.

const mimi = {
	name: "Mimi"
}

const rosi = {
	name: "Rosi"
}

function showThisName(){
	console.log(this.name);
}

showThisName.call(mimi) // Mimi출력
showThisName.call(rosi) // Rosi출력

update라는 함수를 만들어 객체의 정보를 업데이트 해주는 기능을 구현해보자

const mimi = {
	name: "Mimi"
}

const rosi = {
	name: "Rosi"
}

function showThisName(){
	console.log(this.name);
}

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

update.call(mimi, 1995, "singer");
console.log(mimi); // {name: "Mimi", birthYear: 1995, occupation:"singer"} 출력

update.call(rosi, 1997, "singer");
console.log(rosi);// {name: "Rosi", birthYear: 1997, occupation:"singer"} 출력

console.log의 출력값을 살펴보면 정보가 업데이트 된 것을 확인할 수 있다. 여기서 첫번째 매개변수는 this로 사용될 값이고, 두번째부터는 update함수가 사용할 매개변수들을 순서대로 적었다. 때문에 mimi와 rosi의 데이터가 업데이트 되었다.


2. apply

apply는 함수 매개변수를 처리하는 방법을 제외하면 call과 완전히 같다. call은 일반적인 함수와 마찬가지로 매개변수를 직접 받지만, apply는 매개변수를 "배열"로 받는다는 차이점이 있다. 위 코드를 call에서 apply로 바꿔보자

const mimi = {
	name: "Mimi"
}

const rosi = {
	name: "Rosi"
}

function showThisName(){
	console.log(this.name);
}

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

update.apply(mimi, [1995, "singer"]);
console.log(mimi); 
// {name: "Mimi", birthYear: 1995, occupation:"singer"} call과 동일한 결과 출력

update.apply(rosi, [1997, "singer"]);
console.log(rosi);
// {name: "Rosi", birthYear: 1997, occupation:"singer"} call과 동일한 결과 출력


apply는 배열요소를 함수매개변수로 활용할 때 유용하다. 최소값과 최대값을 구하는 코드를 살펴보자. 여기에 배열을 넣었더니 NaN이 출력된다. 

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

여기에 이 배열을 풀어서 넣기 위해 spread연산자를 활용해보자

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

똑같은 결과가 나온다. 이제 apply로 리팩토링해보자.
apply는 두번째 매개변수로 배열을 전달하면 그 요소들을 차례로 활용한다.

const nums = [3, 10, 1, 6, 4];
const minNum = Math.min.apply(null, nums)
//Math.min.apply(null, [3, 10, 1, 6, 4])
const maxNum = Math.max.apply(null, nums)
//Math.max.call(null, 3, 10, 1, 6, 4)

console.log(minNum) // 1 출력
console.log(maxNum) // 10 출력

보통 null의 자리엔 this값이 들어가야하지만 .min, .max메서드는 딱히 this가 필요하지않기 때문에 null이나 아무값을 넣어도 상관없다. call을 사용하고 싶다면 스프레드 연산자를 활용해주면 된다. 하지만 apply는 배열로 받기 때문에 call과 매개변수를 받는 방법엔 차이가 있다는 점을 인지하자.


3. bind

bind 메서드는 함수를 호출하는 것이 아닌, 함수의 this 값을 영구적으로 바꾸는 새로운 함수를 반환한다.

const mimi = {
	name: "Mimi"
}

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

const updateMimi = update.bind(mimi);
updateMimi(1959, "police");
console.log(mimi); // {name: "Mimi", birthYear: 1959, occupation: "police"} 출력

 

 

여기서 한 뎁스 더 들어가보자. user라는 객체에 이름을 보여주는 함수가 들어가 있다. 객체의 함수를 호출하면 다음과 같이 이름(Mimi)을 보여준다.

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

user.showName(); // hello, Mimi출력

여기서 새로운 변수에 객체의 함수호출을 담아 불러보면 어떤 결과가 나올까

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

user.showName(); // hello, Mimi 출력

let fn = user.showName;
fn(); // hello, 출력

fn을 호출하면 hello, 를 제외한 아무것도 출력되지 않는다. 이유는 fn에 할당 할 때 this를 잃어 버렸기 때문이다. 여기서 call이나 apply를 활용해 리팩토링을 하게되면 다음과 같다.

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

user.showName(); // hello, Mimi 출력

let fn = user.showName;
fn.call(user); // hello, Mimi 출력
fn.apply(user); // hello, Mimi 출력

// .bind활용
let bounFn = fn.bind(user);
boundFn(); // hello, Mimi 출력
반응형