Studying/JavaScript & Frameworks

[자바스크립트 떠먹여 주는 남자] Call, Apply, 그리고 Bind (2)

국장 지킴이 앨런 2022. 3. 23. 09:00
반응형
안녕하세요. 원래는 지난 포스트에서 바로 이번 주제를 마무리 지으려고 했으나, 공부를 하는 와중에 this 키워드에 대하여 짚고 넘어가는 것이 좋을 것으로 판단되어 살짝 샛길로 돌았습니다. 하지만 this 는 JS 개발자라면 꼭 알아야 할 필수 개념이기에 꼭 확인해 보시기를 추천 드립니다. 그런 의미에서

확인해 보시기 바랍니다 😉

 

JavaScript Function call(), apply() - advanced

지난 두 찍먹 포스트에서 우리는 어떻게 call 메소드를 사용하는지 코드 예제를 통해서 확인 해 보았습니다. 이번에는 call() 가 this 의 개념을 모두 사용하여 코드 예제를 작성해 보도록 하겠습니다.

const person = {
  firstName: "John",
  lastName: "Doe",
  displayName: function() {
    console.log(`${this.firstName} ${this.lastName}`); // 여기서 this 는 person 객체를 참조
  }
};

const person1 = {
  firstName: "Jane",
  lastName: "Doe"
};

function displayName() {
  console.log(`${this.firstName} ${this.lastName}`); // 함수 안에서 사용 된 this 는 전역 객체를 참조
}

// this.firstName = "Elon"; // line 18
// this.lastName = "Musk"; // line 19

person.displayName.call(person1);
displayName(); // "undefined undefined" if line 18 and 19 are commented out

첫번째 호출문 person.displayName.call(person1); 은 우리가 이미 확인했듯이 'Jane Doe' 가 출력 될 것입니다. 하지만, 두번째 displayName(); 은 어떻게 될까요? 기억하실 지 모르겠지만, 객체 안의 메소드 형태가 아닌 함수의 형태일 때, 그 함수 안의 this 는 전역 객체 (예를 들면 브라우저 window) 를 가리킨다고 지난 포스트에서 공부했습니다.

 

다시 위의 코드를 보면, person 객체 안에 정의 된 firstName 과 lastName 프로퍼티를 제외하면, 그 어디에서도 firstName 과 lastName 을 볼 수 없습니다. 따라서 결과값은 "undefined undefined" 가 될 것입니다. 하지만 만약 우리가 따로 this.firstNamethis.lastName 을 선언 해 준다면, 그 의미는 window 전역 객체 안에 firstName 과 lastName 프로퍼티가 생성 된다는 의미이기에 독립 함수 안에서 this.firstName 과 this.lastName 의 값을 받아올 수 있게 됩니다.

 

또 다른 예제입니다. 이번에는 call() 메소드를 이용하여 독립 선언 되어있는 함수 displayName 에 인자 객체가 출력 되도록 해보겠습니다.

function displayName() {
  console.log(`${this.firstName} ${this.lastName}`);
}

const person = {
  firstName: "Bill",
  lastName: "Gates"
};

displayName.call(person);

/** 출력값
// console.log(this);
{
  firstName: "Bill",
  lastName: "Gates"
}
// console.log(`${this.firstName} ${this.lastName}`);
"Bill Gates"
*/

위의 코드에서 call 메소드에 person 객체를 인자로 보냅니다. 그렇게 되면 this 는 전역 객체 대신 person 객체를 참조하게 됩니다. 이 예제 코드를 통해서 우리는 한 가지 결과를 도출할 수 있습니다.

call() 과 apply() 메소드에서 this 는 첫번째 인자를 참조한다. 인자 타입은 object, string, int 관계가 없다.

 

JavaScript Function bind() - advanced

지난번 찍먹편에서 우리는 bind() 를 한 객체에서 다른 객체의 메소드를 빌려올 때 사용한다는 것을 확인했습니다. 이번 포스트에서는 조금 더 자세하게 알아보도록 하겠습니다.

 

bind() 메소드는 this 를 보존하기 위해서도 사용이 되는데요....

 

 

이게 또 뭔 소린지 코드 예제를 통해 알아보겠습니다. 

// Code from https://www.w3schools.com/js/js_function_bind.asp
const person = {
  firstName:"John",
  lastName: "Doe",
  display: function () {
    let x = document.getElementById("demo");
    x.innerHTML = this.firstName + " " + this.lastName;
  }
}

person.display();

너무 많이 봐서 이젠 나름 익숙해 진 코드입니다. 하지만 마지막으로 한번 더! 말씀 드리자면, person 객체 안의 this 는 person 객체를 참조합니다. 그럼 bind() 메소드가 this 를 보존하기 위해서 사용 된다는 말은 도대체 무엇이냐 하면:

const person = {
  firstName:"John",
  lastName: "Doe",
  display: function () {
    let x = document.getElementById("demo");
    x.innerHTML = this.firstName + " " + this.lastName;
  }
}

setTimeout(person.display, 3000);

위의 코드를 살펴보도록 하겠습니다. 위의 코드는 3초 후에 person 객체의 이름을 디스플레이 하라는 코드입니다. setTimeout 메소드는 첫번째 인자를 콜백 펑션으로 받는데, 위의 코드를 실행시키게 되면, person 객체의 이름 대신 undefined 가 출력됩니다. 그 이유는 함수가 콜백으로 사용될 경우에 this 가 보존 되지 않기 때문입니다.

 

그렇다면 this 를 보존하기 위해서 어떻게 해야 하냐? 예상 가능하시겠지만 바로 bind() 메소드를 사용하는 것입니다.

const display = person.display.bind(person);
setTimeout(display, 3000);

이처럼 bind 메소드를 사용하게 되면 this 가 보존 가능하고 3초 뒤에 person 객체의 이름이 출력 되는 것을 확인하실 수 있습니다.

 

이렇게 call, apply, bind, 그리고 this 에 대하여 야무지게 찍먹 + 부먹 해 보았습니다. 처음 예상했던 것보다 더 오랜 시간이 소요되었지만 그래도 이번 기회에 좀 더 자세히 공부할 수 있었다는 점에 대해 나름 성취감도 느끼고 있습니다. 최대한 쉽게 풀어서 써 보려고 했는데 어떻게 잘 됐는지 모르겠습니다. 혹시 이해가 가지 않는 부분이 있으신 분들은 댓글로 남겨주시면 제가 아는 선에서 최대한 자세하게 알려드리도록 노력해 보겠습니다. 그럼 오늘은 이만 쉬러... 얍!

 

반응형