[ JS ] 자바스크립트 this 키워드 정복하기

2024. 10. 9. 11:49·Language/JavaScript

this 작동 범위

let audio = {
  title: 'a',

  title2 : this.title,
  play() {
    console.log('play this: ', this.title);
  }
};

console.log(audio.title2); //undefined
audio.play(); // play this: a

 

위 코드에서 함수 블록 스코프 내에 선언되지 않은 this는 undefined가 되어 제대로 작동하지 않는다.

 

따라서 this는 반드시 함수 블록 스코프 내에서 선언되어야 올바르게 작동한다.

 


 

함수 호출 방식과 this 바인딩

자바스크립트에서는 함수 호출 방식에 따라 this가 어떤 객체에 바인딩될지 동적으로 결정된다.
 
즉, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니라, 함수를 호출할 때 this가 어떻게 호출되었는지에 따라 바인딩될 객체가 결정된다.

 


 

메소드에서 this 사용

// Method => object
const audio = {
    title: 'a',
    play() {
        console.log('play this', this);
    }
}

audio.play();

// play this   {title: 'a', play: ƒ}
//             play: ƒ play()
//             title: "a"
//             [[Prototype]]: Object

 

메소드 내부의 this는 해당 메소드를 호출한 객체를 가리킨다.

 

var obj1 = {
  name: 'Lee',
  sayName: function() {
    console.log(this.name);
  }
}

var obj2 = {
  name: 'Kim'
}

obj2.sayName = obj1.sayName;

obj1.sayName(); // Lee
obj2.sayName(); // Kim

 

obj2가 sayName 메소드를 obj1에서 가져왔으므로, sayName이 여전히 obj1에 바인딩된 상태에서 실행된다고 생각해서 obj2.sayName()의 결과가 Lee로 출력될 것이라고 착각할 수 있다.

 

하지만 자바스크립트에서 this는 함수가 선언될 때가 아니라, 함수가 호출될 때 결정된다. 즉, sayName 메소드를 호출한 객체가 obj2이기 때문에, this는 obj2를 참조하게 되어 Kim이 출력된다.

 

 

함수에서 this 사용

Function => Window Object
function playAudio() {
    console.log(this); //window
}

playAudio();
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}

 

기본적으로 this는 전역 객체(Global object)를 가리키는데, 함수 어디에서 선언되었든 상관없이 함수에서의 this는 전역 객체를 가리킨다.

 

const audio = {
    title: 'audio',
    categories: ['rock', 'pop', 'hiphop', 'jazz'],
    displayCategories() {
        this.categories.forEach(function (category) {
            console.log(`title: ${this.title}, category: ${category}`);
        });
    }
}

audio.displayCategories();

 

조금 더 깊이 들어가보자.

 

this.categories.forEach(function (category) {

 

여기에서의 this는 displayCategories 메소드에서 사용되고 있다. 그럼 이 메소드를 호출한 객체는 audio이므로 문제없이 categories를 가리키게 된다.

 

console.log(`title: ${this.title}, category: ${category}`);

 

문제는 여기에서의 this이다. 이 this 또한 displayCategories 메소드에서 사용되고 있기 때문에 제대로 audio 객체의 title을 가리킨다고 생각할 수 있다.

 

하지만 코드를 잘보면 this.title은 메서드에 있는 게 아닌 보통 함수 안에 있는 것이기 때문에 audio 객체를 가리키는 게 아닌 window 객체를 가리키게 된다.

 

따라서 실행해보면 this.title이 undefined로 출력되는 것을 확인할 수 있다.

title: undefined, category: rock
title: undefined, category: pop
title: undefined, category: hiphop
title: undefined, category: jazz

 

하지만 우리는 audio의 title을 가져와야하는 상황이다. 그럼 어떻게 해야할까? 두 가지의 방법이 있다.

 

forEach의 두 번째 매개변수 : thisArg

const audio = {
  title: "audio",
  categories: ["rock", "pop", "hiphop", "jazz"],
  displayCategories() {
    this.categories.forEach(function (category) {
      console.log(`title: ${this.title}, category: ${category}`);
    }, this);
  },
};

audio.displayCategories();

// title: audio, category: rock
// title: audio, category: pop
// title: audio, category: hiphop
// title: audio, category: jazz

 

forEach의 첫 번째 매개변수는 콜백 함수이고, 두 번째 매개변수인 thisArg는 콜백 함수 내에서 this로 참조할 객체를 지정하는 용도로 사용된다. 즉, thisArg에 전달된 객체를 콜백 함수 내에서 this로 사용할 수 있게 된다.

 

this.categories.forEach(function (category) {
  console.log(`title: ${this.title}, category: ${category}`);
}, this);

 

따라서 두 번째 인자로 audio를 가리키는 this를 넘겨주어, 콜백 함수 내에서 this가 audio를 올바르게 참조하도록 한다.

 

화살표 함수 사용하기

const audio = {
    title: 'audio',
    categories: ['rock', 'pop', 'hiphop', 'jazz'],
    displayCategories() {
        this.categories.forEach((category) => {
            console.log(this);
        });
    }
}

audio.displayCategories();

// {title: 'audio', categories: Array(4), displayCategories: ƒ}

 

화살표 함수 안에 있는 this는 항상 상위 스코프의 this를 가리킨다. 이것을 Lexical this라고 부르는데, 이 덕분에 콜백함수 내에서도 this가 audio를 참조하도록 할 수 있다.

 

 

생성자 함수에서 this 사용

// Constructor Function => {}
function Audio(title) {
    this.title = title;
    console.log(this);
}

const audio = new Audio('a');

// Audio
//   title: "a"

 

생성자 함수에서의 this는 빈 객체를 가리킨다.

 

💡 Tip
자바스크립트의 생성자 함수

자바와 같은 객체지향 언어의 생성자 함수와 달리, 자바스크립트에서는 특별한 형식이 정해져 있지 않다. 단순히 기존 함수에 new 연산자를 붙여 호출하면 해당 함수가 생성자 함수로 동작하게 된다.

즉, 일반 함수도 new 연산자를 붙여 호출하면 생성자 함수처럼 동작할 수 있다. 이러한 혼동을 방지하기 위해, 생성자 함수의 이름은 보통 첫 글자를 대문자로 작성하는 것이 관례다.

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

[ JS ] Call & Bind & Apply 완벽 정리  (0) 2024.10.10
[ JS ] 자바스크립트 타입 총정리  (1) 2024.10.09
[ JS ] var, let, const ( + 변수 호이스팅 )  (2) 2024.09.19
[ JS ] 이벤트 흐름을 이해해보자 ( Event Bubbling & Capturing )  (0) 2024.08.29
'Language/JavaScript' 카테고리의 다른 글
  • [ JS ] Call & Bind & Apply 완벽 정리
  • [ JS ] 자바스크립트 타입 총정리
  • [ JS ] var, let, const ( + 변수 호이스팅 )
  • [ JS ] 이벤트 흐름을 이해해보자 ( Event Bubbling & Capturing )
seio924
seio924
seio924 님의 블로그 입니다.
  • seio924
    seio924 님의 블로그
    seio924
  • 전체
    오늘
    어제
    • ROOT (51)
      • Mark Up (1)
      • Style Sheet (1)
      • Language (5)
        • JavaScript (5)
      • CS (0)
      • 알고리즘 (26)
      • 디자인 패턴 (1)
      • Develop (8)
      • 디자인 툴 (1)
      • COCOMU (8)
      • FRIENDY (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    cogroom
    완전탐색
    프로그래머스
    CloudFront
    그리디
    백준
    DP
    storybook
    이분탐색
    figma
    llm
    코코무
    html
    s3
    BFS
    spa fallback
    react
    알고리즘
    특수문자 코드
    DFS
    Git
    GPT
    Pretendard
    디스코드 봇 제작
    배포
    cocomu
    gpt-error-analyzer
    라이브러리 제작
    merge
    javascript
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
seio924
[ JS ] 자바스크립트 this 키워드 정복하기
상단으로

티스토리툴바