Javascript - this

2024. 2. 4. 12:37개인노트-개인공부

목차

- this

    - 예시

        - 일반 함수안에서 this 호출

        - 화살표 함수안에서 this 호출

    - call()

    - 예시 2

 

# this

  • 일반함수와 화살표 함수에서 각각 다른 방식으로 해석이 됩니다.
  • 일반 함수의 this는 호출 위치에서 정의.
  • 화살표 함수의 this는 자신이 선언된 함수(렉시컬) 범위에서 정의.

렉시컬(Lexical)이란 함수가 동작할 수 있는 유효한 범위를 의미합니다.

## 예시

### 일반 함수안에서 this 호출

this 키워드를 사용.

// 일반 함수의 this는 호출 위치에서 정의.

const user = {
  firstName: 'first',
  lastName: 'last',
  age: 85,
  getFullName: function () {
    this.firstName;
    this.lastName;
    return `${this.firstName} ${this.lastName}`;
  }
}

console.log(user.getFullName()); // first last

 

this 대신 user 객체로 수정.

// 일반 함수의 this는 호출 위치에서 정의.

const user = {
  firstName: 'first',
  lastName: 'last',
  age: 85,
  getFullName: function () {
    return `${user.firstName} ${user.lastName}`;
  }
}

console.log(user.getFullName()); // first last

 

  • 위 코드에서 일반함수안에서 this를 사용한 것과 user를 사용한 것과 결과 값은 같습니다.
  • 즉, this는 user 객체를 가리킵니다.
  • '일반 함수의 this는 호출 위치에서 정의.' 된다는 것은 getFullName 함수가 호출되는 곳은 user.getFullName() 이므로 getFullName()을 호출을 시도한 대상인 user객체 를 가리킵니다.

### 화살표 함수안에서 this 호출

this 키워드를 사용.

// 화살표 함수의 this는 자신이 선언된 함수(렉시컬) 범위에서 정의.

const user = {
  firstName: 'first',
  lastName: 'last',
  age: 85,
  getFullName: () => {
    return `${this.firstName} ${this.lastName}`;
  }
}

console.log(user.getFullName()); // undefined undefined
  • 자신이 선언된 함수(레시컬) 범위 -> 여기서 '자신'은 getFullName함수를 가리킵니다.
  • 즉, 화살표 함수 안의 this는 그 화살표 함수가 선언된 감싸는 외부 함수 범위 안에서 정의됩니다. 
  • 하지만, 위 예제에서는 this가 선언된 화살표 함수를 감싸는 외부 함수가 없습니다. 그래서 결과는 undefined가 출력되었습니다.

 

그럼 이번에는 this가 사용된 화살표 함수를 감싸는 외부 함수를 만들어보겠습니다.

// 화살표 함수의 this는 자신이 선언된 함수(렉시컬) 범위에서 정의.

function user() = {
  this.firstName = 'first2'; // 출력됨
  this.lastName = 'last2'; // 출력됨
  
  return {
    firstName: 'first',
    lastName: 'last',
    age: 85,
    getFullName: () => {
      return `${this.firstName} ${this.lastName}`;
    }
  }
}

const u = user();
console.log(u.getFullName()); // first2 last2
  • 화살표 함수 안의 this는 그 화살표 함수를 감싸는 외부 함수 범위 안에서 정의되므로,
  • 외부 함수에 정의한 this.firstName인 first2와 this.lastName인 last2가 출력되었습니다.

 

만약, getFullName의 함수를 다시 일반 함수로 변경한다면?

// 일반 함수의 this는 호출 위치에서 정의.

function user() = {
  this.firstName = 'first2';
  this.lastName = 'last2';
  
  return {
    firstName: 'first', // 출력됨
    lastName: 'last', // 출력됨
    age: 85,
    getFullName: function () {
      return `${this.firstName} ${this.lastName}`;
    }
  }
}

const u = user();
console.log(u.getFullName()); // first last
  • getFullName()이 '호출된 곳' 기준이기 때문에 변수'u'에서 반환된 객체의 firstName인 first와 lastName인 last가 출력됩니다.

## call()

call()를 사용하면 객체가 다른 객체에 속한 메서드를 사용할 수 있습니다.
사전 정의된 JavaScript 메서드입니다.

 

이렇게 일반 함수에서의 this는 호출 위치에서 정의되기 때문에 또 다른 방법으로 접근해서 이름을 출력할 수 있습니다.

function user() = {
  this.firstName = 'first2';
  this.lastName = 'last2';
  
  return {
    firstName: 'first',
    lastName: 'last',
    age: 85,
    getFullName: function () {
      return `${this.firstName} ${this.lastName}`;
    }
  }
}

const GilDong = {
    firstName: 'GilDong',
    lastName: 'Hong',
}

const u = user();
console.log(u.getFullName()); // first last
console.log(u.getFullName.call(GilDong)); // GilDong Hong
  • 특정한 객체에서 다른 객체가 가지고 있는 메소드를 빌려와서 사용할 수 있습니다.
  • GilDong 변수는 getFullName이라는 메소드를 가지고 있지 않은 상태입니다.
  • call을 사용하면 getFullName이 호출되는 대상은 이제 'u' 객체가 아니라 'GilDong' 객체가 됩니다.

이처럼 일반함수에서의 this 키워드는 호출위치에서 정의되기 때문에 함수를 다른 객체에 붙여서 사용하는 것도 가능합니다.

 

## 예시 2

const timer = {
  title: 'TIMER!',
  timeout() {
    console.log(this.title);
  }
}

timer.timeout(); // TIMER!
  • 배운대로 일반함수에서의 this는 호출위치에서 정의되기 때문에 호출위치는 timeout함수가 호출된 timer.timeout() 이므로 this는 timer 객체가 되고 객체 안의 title을 출력하게 됩니다.

 

setTimeout을 추가하면..

const timer = {
  title: 'TIMER!',
  timeout() {
    console.log(this.title); // TIMER!
    setTimeout(function () {
      console.log(this.title); // undefined
    }, 1000);
  }
}

timer.timeout(); // TIMER!
  • setTimeout함수의 콜백으로 넣은 함수는 setTimeout 함수 내부 어딘가에서 호출이 됩니다.
  • 일반함수에서의 this는 호출위치에서 정의되기 때문에 this는 setTimeout 함수 내부 어딘가에서 호출된 곳에서 정의됩니다. 
  • 참고로 우리는 setTimeout 함수의 내부 구조는 모르기 때문에 당연히 콜백으로 넣은 함수 this가 무엇을 가르키는지는 모릅니다. 그렇게 무엇인지 모르는 객체에서 title을 조회했기 때문에 'TIMER!' 가 출력될 수 없습니다.

 

이렇게 함수안에 또다른 함수가 있는 구조이고 this 키워드를 자주 사용한다면, 일반 함수 보다는 화살표 함수를 사용하는 것이 훨씬 더 적합합니다.

 

setTimeout 콜백 함수를 일반 함수에서 화살표 함수로 바꾸준다면..

const timer = {
  title: 'TIMER!',
  timeout() {
    console.log(this.title); // TIMER!
    setTimeout(() => {
      console.log(this.title); // TIMER!
    }, 1000);
  }
}

timer.timeout(); // TIMER!

 

  • 배운대로 화살표 함수의 this는 자신이 선언된 함수(렉시컬) 범위에서 정의됩니다.
  • 콜백 함수를 감싸고 있는 외부(상위) 범위는 timeout함수가 감싸고 있으므로 timeout이 됩니다.
  • 이 때, timeout함수가 가지고 있는 this 키워드는 timer.timeout()에서 호출시점에 timer객체로 정의 되었으므로, 콜백으로 사용된 화살표 함수 안의 this는 timeout함수의 this 즉, timer 객체를 가리킵니다.

## 정리

  • this 키워드는 일반함수에서 화살표 함수에서 해석하는 방법이 다릅니다.
  • 일반 함수의 this는 호출 위치에서 정의.
  • 화살표 함수의 this는 자신이 선언된 함수(렉시컬) 범위에서 정의.

 

 

 

참고

'개인노트-개인공부' 카테고리의 다른 글

html 문서 로드와 이벤트  (1) 2024.05.12
JavaScript - 함수 (복습)  (1) 2024.03.10
Node vs Element  (2) 2024.01.28
javascript - 클로저  (1) 2024.01.21
JavaScript - Events  (1) 2024.01.07