9/01/2023

this

this

this 예약어/변수는 사실상 모든 실행 컨텍스트(모든 함수)에 생성되는 특별한 변수로 변수 환경과 스코프 체인과 함께 실행 컨텍스트의 세 가지 구성 요소 중 하나이다. this 예약어는 항상 this 예약어가 사용된 함수의 소유자의 값을 가진다. 즉, 해당 함수의 소유자를 가리킨다고 말한다. this 예약어 값은 정적이지 않으며 항상 같은 값이 아니다. this 예약어 값은 함수가 실제로 호출되는 방식에 따라 달라지며 함수가 실제로 호출될 때에만 할당된다. 함수가 호출되는 네 가지 방법을 통해 이 의미를 알아본다.
  • 메서드: 메서드는 객체에 연결된 함수로 호출 시 this 예약어는 호출한 메서드가 있는 객체를 가리킨다. 즉, 해당 메서드를 호출한 객체를 가리킨다.
  • 함수 호출: 함수를 단순히 일반 함수로 호출하는 경우(즉, 메서드로 호출하지 않고 어떤 객체에 연결되지 않은 경우) this 예약어는 undefined이다. 그러나 이는 strict 모드에만 해당되며 strict 모드가 아닌 경우 this는 전역 객체를 가리키며 브라우저의 경우 window 객체이고 Node.js의 경우 global 객체이다. 이는 큰 문제가 될 수 있으므로 항상 strict 모드를 사용해야 한다.
  • 화살표 함수: 화살표 함수는 함수를 호출하는 방법은 아니지만 중요한데 화살표 함수는 자체 this 예약어를 갖지 않기 때문이다. 화살표 함수에서 this 변수를 사용하면 주변 함수의 this 예약어가 된다. 즉, 부모 함수/스코프의 this 예약어이다. 기술적으로 이를 렉시컬 this 예약어라고 부르는데 외부 렉시컬 범위에서 선택된다는 의미이다. 이러한 특성 때문에 버그가 발생하기도 한다.
  • 이벤트 리스너: 함수가 이벤트 리스너로 호출되는 경우에는 this 예약어는 항상 핸들러 함수가 연결된 DOM 요소를 가리킨다.

중요한 점은 this 예약어는 사용하는 함수 혹은 함수의 변수 환경을 가리키지 않는다는 것이다. 또한, new 예약어나 call, apply 및 bind 메서드를 사용하여 함수를 호출하는 방법 등이 있다.

Exercise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
"use strict";
 
// 전역 window 객체.
console.log(this);
 
// 객체와 관련이 없는 일반 함수(함수 표현식).
const caclBmiExpr = function (weight, height) {
  const bmi = weight / (height * height);
  console.log(this); // strict 모드에서 undefined
 
  return bmi;
};
 
caclBmiExpr(551.55);
 
const caclBmiArrow = (weight, height) => {
  const bmi = weight / (height * height);
  console.log(this); // 화살표 함수는 this가 없기 때문에 렉시컬 this 즉, 부모 함수/스코프의 this 사용한다. 전역 window 객체.
 
  return bmi;
};
 
caclBmiExpr(551.55);
 
// this는 호출하는 객체를 항상 가리킨다
const sunshim = {
  year: 1966,
  calcAge: function () {
    console.log(this); // sunshim 객체.
    console.log(2023 - this.year);
  },
};
 
sunshim.calcAge(); // 57
 
const silvia = {
  year: 1976,
};
 
// 메서드 빌리기
// this는 silvia 객체를 가리킨다.
silvia.calcAge = sunshim.calcAge;
silvia.calcAge(); // 47
 
// foo는 객체와 관련이 없는 일반 함수이기 때문에 this는 undefined 따라서 오류가 발생한다.
const foo = sunshim.calcAge;
foo();
cs


Regular Function vs. Arrow Function

this 예약어뿐만 아니라 arguments 예약어도 일반 함수(함수 표현식, 함수 선언식)에서만 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"use strict";
 
// 객체 리터럴은 스코프가 없다
const sunshim = {
  year: 1966,
  fullName: "박선심",
  job: "경찰관",
 
  calcAge: function () {
    console.log(this); // sunshim 객체
    console.log(2023 - this.year);
  },
 
  // 화살표 함수는 this가 없기 때문에 렉시컬 this 즉, 부모 함수/스코프의 this 사용, 전역 window 객체.
  // 따라서 메서드로 화살표 함수 사용 절대 금지!
  describeJobArrow: () => {
    console.log(this); // undefined.
    console.log(`이름은 ${this.fullName}이고 직업은 ${this.job}입니다.`);
  },
 
  // isOverFifty는 일반 함수이기 때문에 this는 undefined 따라서 오류가 발생한다.
  describeJobDecl: function () {
    console.log(`이름은 ${this.fullName}이고 직업은 ${this.job}입니다.`);
 
    // ES6 이전 해결법.
    // const self = this;
    // const isOverFifty = function () {
    //   console.log(self); // undefined
    //   console.log(2023 - self.year >= 50);
    // };
 
    // ES6 이후 해결법.
    // 화살표 함수는 부모 함수/스코프의 this를 사용한다.
    const isOverFifty = () => {
      console.log(this);
      console.log(2023 - this.year >= 50);
    };
 
    isOverFifty();
  },
};
 
// sunshim.describeJobArrow();
sunshim.describeJobDecl();
 
function mulDecl(n1, n2) {
  console.log(arguments);
 
  return n1 * n2;
}
mulDecl(510);
 
const mulExpr = function (n1, n2) {
  console.log(arguments);
 
  return n1 * n2;
};
mulExpr(51012);
 
// 일반 함수(함수 선언식, 함수 표현식)만 arguments 예약어를 가지기 때문에 오류가 발생한다.
const mulArrow = (n1, n2) => {
  console.log(arguments);
 
  return n1 * n2;
};
mulArrow(510);
 
cs

update: 2023-09-04

댓글 없음:

댓글 쓰기