this

2023. 12. 27. 21:23Study/JavaScript

this

자바스크립트에서 this는 조금 특별하다.

자바스크립트는 Lexical Scope를 사용하기 때문에 함수의 상위 스코프가 정의 시점에 평가된다.

하지만 this 키워드는 바인딩이 객체가 생성되는 시점에 결정된다.

 

this 키워드

  1. 일반 함수 호출할 땐 this가 최상위 객체 (global 또는 window)를 가리킨다.
  2. 메서드로 호출할 땐 호출된 객체를 가리킨다.
  3. new 키워드를 사용해서 객체를 생성했을 땐 객체를 가리킨다.

 


 

일반 함수에서의 this

일반 함수는 함수를 실행했을 때 this 키워드가 global object에 매핑이 된다.

global object는 web에서는 window 객체다.

const testFunction = function(){
  return this;
}


console.log(testFunction());
/*
<ref *1> Object [global] {
  global: [Circular *1],
  queueMicrotask: [Function: queueMicrotask], ...
*/
// global object와 맵핑이 된 것을 확인할 수 있다.


console.log(testFunction() === gloabl);
// true
// testFunction()이 global과 같다

 

 

객체에서의 this

객체에서의 this는 현재 객체를 의미한다.

const yuJin = {
  name: '안유진',
  year: 2003,
  sayHello: function(){
    return `안녕하세요 저는 ${this.name}입니다.`;
  },
}
// 객체에서 this는 현재 객체를 의미한다.


console.log(yuJin.sayHello());
// 안녕하세요 저는 안유진입니다.

 

 

생성자 함수에서의 this

생성자 함수에서 this는 생성된 인스턴스를 가리킨다.

function Person(name, year){
  this.name = name;
  this.year = year;
  
  this.sayHello = function(){
    return `안녕하세요 저는 ${this.name}입니다.`;
  }
}
// 생성자 함수에서 this는 생성된 인스턴스를 가리킨다.


const yuJin2 = new Person('안유진', 2003);
console.log(yuJin2.sayHello());
// 안녕하세요 저는 안유진입니다.

 

프로토타입에 this 키워드를 사용하면?

prototype에 this 키워드를 사용해도 생성된 인스턴스에 맵핑된다.

Person.prototype.dance = function(){
  return `${this.name}이 춤을 춥니다.`;
}
// prototype에 this를 사용해도 생성된 인스턴스에 맵핑된다.


console.log(yuJin2.dance());
// 안유진이 춤을 춥니다.

 

 

그런데, 만약 prototype.dance 안에 함수를 생성해서 사용한다면 this는 어디에 맵핑될까?

객체의 메서드로 가장 상위 레벨에 함수를 선언하면 자동으로 인스턴스에 맵핑되지만,

그 외의 위치에다가 함수를 선언하게 되면 함수의 this는 무조건 global object에 맵핑된다.

 

dance2() 함수는 상위레벨 함수가 아니므로 this키워드는 global object를 가리키고, global object에는 name이 없기 때문에 undefined가 출력된다.

Person.prototype.dance = function(){
  function dance2(){
    return `${this.name}이 춤을 춥니다.`;
  }
  
  return this.dance2();
}
// dance2() 함수의 this는 global object에 맵핑된다.


console.log(yuJin2.dance());
// undefined이 춤을 춥니다.

 

 


 

this 매핑하기 - apply, call, bind

우리가 예상하거나 원하는 this 값으로 this를 맵핑하는 방법으로는 세가지가 있다. apply(), call(), bind()

returnName()의 this 키워드가 yuJin3에 맵핑되게 하려면 어떻게 해야 할까?

 

call(), apply(), bind() 모두 원하는 함수에다가 원하는 객체를 바인딩 할 수 있는 방법이다.

this 키워드를 지정해줄 수 있다.

function returnName(){
  return this.name;
}


console.log(returnName());
// undefined
// gloabl object에 맵핑되어있기 때문에 undefined 출력

 

 

call(), apply()

returnName.call(yuJin3)

returnName()을 yuJin3에 바인딩해서 call() 하겠다는 의미이다.

const yuJin3 = {
  name: '안유진',
}


// call()
console.log(returnName.call(yuJin3));
// 안유진
// this 키워드가 yuJin3에 바인딩 되었다.
// returnName을 yuJin3에 바인딩해서 call() 하겠다는 의미.



// apply()
console.log(returnName.apply(yuJin3));
// 안유진
// this 키워드가 yuJin3에 바인딩 되었다.
// returnName을 yuJin3에 바인딩해서 apply() 하겠다는 의미.

 

call()과 apply()의 다른 점

  • call() - 컴마를 기반으로 아규먼트를 순서대로 넘겨준다.
  • apply() - 아규먼트를 리스트로 입력해야 한다.
function multiply(x, y, z){
  return `${this.name} / 결과값 : ${x * y * z}`;
}


// call()
console.log(multiply.call(yuJin3, 3, 4, 5));
// 안유진 / 결과값 : 60


// apply()
console.log(multiply.apply(yuJin3, [3, 4, 5]));
// 안유진 / 결과값 : 60

 

 

bind()

returnName.bind(yuJin3)

bind()는 apply(), call()과 다르게 this를 바인딩만 해 놓고 나중에 실행할 수 있다.

// 바인드 함수는 apply()랑 call()과 다르게
// this를 바인딩만 해놓고 나중에 실행할 수 있다.

const laterFunc = multiply.bind(yuJin3, 3, 4, 5);


console.log(laterFunc);
// [Function bound multiply]
// laterFunc는 multiply라는 함수인 것을 볼 수 있다.


// 함수이기 때문에 실행할 수 있다.
console.log(laterFunc());
// 안유진 / 결과값 : 60

 

 

 

'Study > JavaScript' 카테고리의 다른 글

Closure  (0) 2024.01.02
Execution Context  (1) 2023.12.27
Scope  (0) 2023.12.26
Prototype, Prototype Chain  (0) 2023.12.23
Constructor Function 생성자 함수  (1) 2023.12.23