JavaScript에서 this 키워드란?🤔

Harimad·2022년 8월 10일
0

js

목록 보기
3/14
post-thumbnail

들어가며

이번 글에서는 자바스크립트에서 헷갈리는 개념 중에 하나인 this 키워드에 대해서 알아보겠습니다.


0. this란?

  • 자바스크립트에서 this 키워드는 개체를 나타냅니다.
  • this의 값은 함수를 호출하는 방법에 의해 결정됩니다. 실행중에는 할당으로 설정할 수 없고 함수를 호출할 때 마다 다를 수 있습니다. - MDN Docs
  • this 키워드는 사용 방법에 따라 다른 개체를 참조합니다.
    1. 객체 메서드에서는, this가 객체를 참조합니다.
    2. 단독으로 쓰일 땐, this가 전역 객체를 나타냅니다.
    3. 함수에서는, this가 전역 객체를 나타냅니다.
    4. 함수에서 엄격 모드('strict mode')일 땐, this가 undefined를 나타냅니다.
    5. 이벤트에서는, this가 이벤트를 발생시킨 요소를 나타냅니다.
    6. call(), apply(), bind() 메서드에서는 this가 모든 객체를 참조할 수 있습니다.

1. 기본 바인딩

1-1. 메서드에서 this

  • 객체 메서드에서 사용될 때, this는 해당 객체를 참조 합니다.
  • 아래의 예시에서 this는 person 객체를 나타냅니다.
  • 왜냐하면 fullName 메서드는 person 객체의 메서드이기 때문입니다.
const person = {
  firstName: "John",
  lastName : "Doe",
  fullName : function() {
    return this.firstName + " " + this.lastName;
  }
};

console.log(person.fullName()); // John Doe

1-2. 메서드 안의 함수에서 this

  • 일반 함수는 this를 새로 바인딩 합니다.
  • 예를 들어서, 다음에서 this는 arr 객체가 아니라 window를 가리킵니다.
const arr = {
  numbers : [1, 2, 3, 4, 5],
  print: function(delay=1000) {
    setTimeout(function() {
      console.log(this.numbers.join(',')) // Uncaught TypeError: Cannot read properties of undefined (reading 'join')
      console.log(this) // Window
    }, delay)
  }
}

arr.print()
  • 이 문제를 해결하기 위해서, 화살표 함수를 사용하면 this의 영역이 원하는 대로 유지됩니다.
const arr2 = {
  numbers : [1, 2, 3, 4, 5],
  print: function(delay=1000) {
    setTimeout(() => {
      console.log(this.numbers.join(',')) // 1,2,3,4,5
      console.log(this) // {numbers: Array(5), print: ƒ}
    }, delay)
  }
}
arr2.print()
  • print 프로퍼티를 화살표 함수로 바꾸면 this가 window 객체가 됩니다.
const arr3 = {
  numbers : [1, 2, 3, 4, 5],
  print: (delay=1000) => {
    setTimeout(() => {
      console.log(this.numbers.join(',')) // Uncaught TypeError: Cannot read properties of undefined (reading 'join')
      console.log(this) // Window 
    }, delay)
  }
}

arr3.print()

🍖 결론 - 메서드 안의 함수에서 this가 객체를 가리키려면?
객체 안의 메서드를 일반 함수로 만들고, 그 안에 화살표 함수를 만들어서 this를 사용합니다.
그러면 이 this가 해당 객체를 가리키기 때문에 혼동할일 없이 사용할 수 있습니다.

1-3. 단독 this

  • 혼자서 쓰일 땐, this가 전역 객체를 나타냅니다.
  • 왜냐하면 this가 전역 스코프에서 실행되기 때문입니다.
console.log(this); // Window
  • 엄격 모드에서 단독으로 쓰일 때도 전역 객체를 나타냅니다.
"use strict";
console.log(this); // Window

1-4. 함수에서 this

  • 함수에서 this에 대한 기본 바인딩은 '전역 객체' 입니다.
function 함수() {
  return this;
}

console.log(함수()); // Window

1-5. 엄격모드인 함수에서 this

  • 자바스크립트에서 엄격 모드는 기본 바인딩을 제공하지 않습니다.
  • 그래서 함수에서 this를 사용 할 때 엄격모드를 적용하면 this가 undefined를 나타냅니다.
'use strict';
function 함수() {
  return this;
}

console.log(함수()); // undefined

1-6. 이벤트 핸들러에서 this

  • HTML 이벤트 핸들러에서 this는 이벤트를 수신한 HTML 요소를 나타냅니다.
<button onclick="this.style.color='red'">
  클릭하면 빨간색으로 변경!
</button>

2. 암시적 바인딩

  • 자바스크립트 바인딩 규칙에 따라서, 함수는 해당 객체의 호출 지점에서 바인딩된 경우에만 해당 객체를 컨텍스트로 사용할 수 있습니다.

아래의 예시를 보면서 이해해 보겠습니다.

function show() { 
  console.log(this.height + ' cm'); 
}

const obj = {
  height: 200,
  show: show
}

obj.show() // 200 cm
  • 간단하게 말해서, 점 표기법(.)을 사용해서 함수를 호출하면, this가 암시적으로 함수가 호출되는 객체에 암시적으로 바인딩 됩니다.
  • 여기서는 show() 함수의 this가 obj 객체에서 호출 되기 때문에 obj를 나타냅니다.

다른 예시를 보겠습니다.

function show() { 
  console.log(this.height + ' cm'); 
}

const obj = {
  height: 200,
  show: show,
  안쪽obj: {
    height: 220,
    show: show
  }
}

obj.안쪽obj.show(); // 220 cm

obj.show(); // 200 cm
  • 여기서는 궁극적으로 '안쪽obj'객체에서 show() 메서드가 호출 됩니다.
  • 그래서 this는 암시적으로 'obj'대신 '안쪽obj'를 바인딩 하게 됩니다.

3. 명시적 바인딩

3-1. 명시적 함수 바인딩

  • call()과 apply() 메서드는 미리 정의된 자바스크립트 메서드들 입니다.
  • 둘 다 다른 객체를 인자로 사용하여 어떠한 객체 메서드를 호출 하는 데 사용할 수 있습니다.
  • 아래 예시는 student2를 인자로 사용해서 student1.fullName 메서드를 호출합니다. fullName이 student1객체의 메서드 일지라도, 여기서 this는 student2 객체를 나타냅니다.
const student1 = {
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}

const student2 = {
  firstName:"John",
  lastName: "Doe",
}

student1.fullName.call(student2); // "John Doe"

3-2. 함수 빌리기

  • bind() 메서드를 사용하면, 한 객체가 다른 객체안에 있는 메서드를 빌릴 수 있습니다.
  • 아래 예시는 2개의 객체가 있습니다 (person과 student)
  • student 객체가 person 객체안에 있는 fullName 메서드를 빌려 씁니다.
const person = {
  firstName:"John",
  lastName: "Doe",
  fullName: function () {
    return this.firstName + " " + this.lastName;
  }
}
//메서드에서 this => 해당 객체
console.log(person.fullName()); // 'John Doe'

const student = {
  firstName:"Heung Min",
  lastName: "Son",
}

let fullName = person.fullName.bind(student);

//함수 빌리기
console.log(fullName()); // 'Heung Min Son'

4. 생성자 호출 바인딩

  • 함수가 앞에 new 키워드를 사용하여 호출되면(이를 생성자 호출 이라고 부릅니다), 다음과 같은 일이 일어납니다.
    1. 완전히 새로운 객체가 생성됩니다.
    2. 새로 생성된 객체는 생성한 함수에 [[Prototype]]링크되어 있습니다.
    3. 새로 생성된 객체는 해당 함수 호출에 대한 this 바인딩으로 설정됩니다.

예시를 보겠습니다.

function person(age) { 
  this.age = age;
} 

const bar = new person(17); 
console.log(bar.age); // 17
  • new 키워드를 붙여서 person(...) 함수를 호출하여 새로운 객체를 구성했습니다.
  • person 함수에서 this.age의 this가 new 키워드를 호출한 bar를 바인딩 하게 됩니다.

정리

  • this 키워드는 작성 시점이 아니라 런타임 시점에 바인딩 되며, 함수를 호출하는 상황에 따라서 콘텍스트가 결정됩니다.
  • 바인딩은 기본 바인딩, 암시적 바인딩, 명시적 바인딩, 생성자 호출 바인딩이 있습니다.
  • new로 호출하면, this는 새로 생성된 객체로 바인딩 됩니다.
  • call(), apply(), bind()로 호출하면, this는 주어진 객체로 바인딩 됩니다.
  • 호출의 주체인 콘텍스트로 호출하면, this는 이 콘텍스트 객체로 바인딩 됩니다.
  • 기본 바인딩에서 this는 전역 객체로 바인딩되고, 엄격 모드에서는 undefined로 바인딩 됩니다.

참고

profile
Here and Now. 🧗‍♂️

0개의 댓글