[코어 자바스크립트] 03 this

백은진·2021년 1월 8일
0

03 this

챕터 목표: this가 달라지는 이유를 알고, this가 대상을 바라보는 이유를 효과적으로 추적할 줄 안다.

this: 함수와 메서드의 구분이 느슨한 자바스크립트에서 실질적으로 이 둘을 구분하는 기능. 실행 컨텍스트가 생성될 때 함께 결정된다. 즉, 함수를 호출할 때 결정되는데, 함수를 어떤 방식으로 호출하느냐에 따라 값이 달라진다.


1. 상황에 따라 달라지는 this

1-1. 전역 공간에서의 this

⬇️ 전역 공간에서 this는 전역 객체를 가리킨다. (전역 컨텍스트를 생성하는 주체가 전역 객체이기 때문)

⬇️ 전역 변수를 선언하면, 자바스크립트 엔진은 전역변수를 전역객체의 프로퍼티로도 할당한다. 즉, 전역변수는 변수이면서 객체의 프로퍼티인 것이다.

위와 같이 될 수 있는 이유는 자바스크립트의 모든 변수가 특정 객체(LexicalEnvironment)의 프로퍼티로서 동작하기 때문이다.
실행 컨텍스트는 변수를 수집해서 렉시컬환경의 프로퍼티로 저장한다. 이후 어떤 변수를 호출하면 L.E를 조회해서 일치하는 프로퍼티가 있을 경우 그 값을 반환한다. 전역 컨텍스트의 경우 L.E는 전역객체를 그대로 참조한다.

즉, 전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당한다.

따라서, 코드를 통해 변수 a에 접근하고자 하면 자바스크립트 엔진은 스코프 체인에서 a를 검색하다가 가장 마지막에 도달하는 전역객체(전역 스코프의 L.E)에서 프로퍼티 a를 발견해 값을 반환한다.

1-1-1. 전역공간에서 변수 선언 = window의 프로퍼티로 할당? X

전역공간에서 var로 변수를 선언하는 것과 window의 프로퍼티에 직접 할당하는 것이 똑같이 동작하기도 한다.

그러나 삭제 명령에 대해서는 똑같이 동작하지 않는다.
(이는 사용자가 의도치 않게 삭제하는 것을 방지하는 차원에서 마련한 나름의 방어 전략이라고 해석된다.)
(And the JavaScript delete operator removes a property from an object)

이를 통해 전역변수를 선언하면 자바스크립트 엔진이 이를 자동으로 전역객체의 프로퍼티로 할당하면서 추가적으로 해당 프로퍼티의 configurable(변경 및 삭제 가능성) 속성을 false로 정의한다는 것을 알 수 있다.

1-2. 메서드로서 호출할 때 그 메서드 내부에서의 this

1-2-1. 함수 vs. 메서드

함수와 메서드는 독립성을 기준으로 차이가 있다.
(함수 앞에 객체와 점(.)이 없으면 함수로서 호출, 객체와 점이 있으면 메서드로서 호출이다.)

함수는 그 자체로 독립적인 기능을 수행
메서드는 자신을 호출한 대상 객체에 관한 동작을 수행

자바스크립트는 상황별로 this 키워드에 다른 값을 부여하게 함으로써 이를 구현했다.

아래의 예제를 보면, 익명함수는 그대로이지만 이를 변수에 담아 호출한 경우와 obj 객체의 프로퍼티에 할당해서 호출한 경우 this가 달라지는 것을 볼 수 있다.

1-2-2. 메서드 내부에서의 this

함수를 메서드로서 호출할 때, this는 함수명 앞의 객체이다.

this에는 호출한 주체에 대한 정보가 담긴다. 함수를 메서드로서 호출할 때, 호출 주체는 함수명 앞의 객체이다. 점 표기법의 경우 마지막 점 앞에 명시된 객체가 곧 this가 된다.

1-3. 함수로서 호출할 때 그 함수 내부에서의 this

1-3-1. 함수 내부에서의 this

함수를 함수로서 호출할 때, this는 전역 객체이다.

함수로서 함수를 호출할 때는 this가 지정되지 않는다. 함수로서 호출하는 것은 호출 주체(객체지향 언어에서의 객체)를 명시하지 않고 개발자가 직접 코드에 관여해서 실행한 것이기 때문에 호출 주체의 정보를 알 수 없어서 그렇다.

실행 컨텍스트 활성화 당시에 this가 지정되지 않으면, this는 전역 객체를 바라본다.

1-3-2. 메서드의 내부함수에서의 this

아래의 예제를 보면, 함수를 어떻게 호출했느냐에 따라서 this가 가리키는 객체가 다른 것을 확인할 수 있다.

var obj1 = {
  outer: function () {
    console.log(this);  // obj1.outer(); => obj1
    
    var innerFunc = function () {
      console.log(this);  // innerFunc(); => window  // obj2.innerMethod(); => obj2;
    }
    
    innerFunc(); 
    
    var obj2 = {
      innerMethod: innerFunc
    };
    
    obj2.innerMethod();
  }
};

obj1.outer();  

1-3-3. 메서드의 내부 함수에서 this를 우회하는 방법

함수로서 함수를 호출할 때 전역 객체가 this에 지정되는 방식은 조금 어색하기 때문에 쉽게 이해하기 어렵다.
차라리 전역객체가 아닌 호출 당시 주변 환경의 this를 그대로 상속받는 것이 더 자연스럽고, 스코프 체인과의 일관성도 지키는 설득력 있는 방식이라 생각된다. (변수 검색 시 가장 가까운 스코프의 L.E부터 찾아나가는 것처럼, this도 현 컨텍스트에 바인딩된 대상이 없으면 직전 컨텍스트의 this를 바라보도록.)

그러나 ES5까지는 자체적으로 내부함수에 this를 상속할 방법이 없었기 때문에 변수를 활용해 우회하여 this를 상속하는 방법을 꾀했다.

var obj1 = {
  outer: function () {
    console.log(this);  // obj1.outer(); => obj1
    
    var innerFunc1 = function () {
      console.log(this);  // innerFunc1(); => window
    }
    
    innerFunc1(); 
    
    var self = this;  // 상위 스코프의 this를 저장해서 내부함수(innerFunc2)에서 활용
    
    var innerFunc2 = function () {
      console.log(self);  // obj1.outer(); => obj1
    }
    innerFunc2();
  }
};

obj1.outer();  

1-3-4. this를 바인딩하지 않는 함수

ES6에서는 this를 바인딩하지 않는 arrow function을 도입했다. arrow function은 실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 빠지게 되어, 상위 스코프의 this를 그대로 활용한다.

var obj1 = {
  outer: function () {
    console.log(this);  // obj1.outer(); => obj1
    
    var innerFunc = () => {
      console.log(this);  // innerFunc(); => obj1
    }
    
    innerFunc(); 
  }
};

obj1.outer();  

1-4. 콜백 함수 호출 시 그 함수 내부에서의 this

콜백 함수: 함수 A의 제어권을 다른 함수(혹은 메서드) B에게 넘겨주는 경우, 함수 A가 콜백 함수.

콜백 함수 A는 함수 B의 내부 로직에 따라 실행되며, this 역시 함수 B 내부 로직에서 정한 규칙에 따라 값이 결정된다.
콜백 함수도 함수이기 때문에 기본적으로 this가 전역객체를 참조하나, 제어권을 받은 함수에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조한다.

// 콜백 함수 내부의 this

setTimeout(function () { console.log(this); }, 300);  // 0.3초 뒤 콜백 함수 실행되며 전역객체 출력

[1, 2, 3, 4, 5].forEach(function (x) {
  console.log(this, x);  // 전역객체와 x 5번 출력
});

document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a').addEventListener('click', function (e) {
  console.log(this, e);  // addEventListener 앞의 엘리먼트와 클릭 이벤트에 관한 정보가 담긴 객체 출력
});

setTimeout 함수와 forEach 메서드는 그 내부에서 콜백 함수를 호출할 때 대상이 될 this를 지정하지 않았다. 따라서 콜백 함수 내부에서의 this는 전역 객체를 참조한다.

반면 addEventListener 메서드는 콜백 함수를 호출할 때 자신의 this를 상속하도록 정의되어 있다. 따라서 .addEventListener 앞 부분의 엘리먼트에 대한 정보가 담긴 객체가 this가 되고, 이는 콜백 함수에 상속된다.

예제를 통해 알 수 있듯이 콜백 함수에서의 this는 무조건적으로 정의할 수 없다. 콜백 함수의 제어권을 가지는 함수(혹은 메서드)가 콜백 함수에서의 this를 무엇으로 할지를 결정하며, 특별히 정의하지 않은 경우에는 기본적으로 함수와 마찬가지로 전역객체를 바라본다.

1-5. 생성자 함수 내부에서의 this

생성자 함수: 어떤 공통된 성질을 지니는 객체들을 생성하는 데 사용하는 함수

객체지향 언어에서는 생성자를 class, 클래스를 통해 만든 객체를 instance라고 한다.

프로그래밍적으로 생성자는 구체적인 인스턴스를 만들기 위한 일종의 틀이다.
이 틀에는 해당 클래스의 공통 속성들이 미리 준비돼 있고, 여기에 구체적인 인스턴스의 개성을 더해 개별 인스턴스를 만들 수 있다.

자바스크립트는 함수에 생성자로서의 역할을 함께 부여했다.
new 명령어와 함께 함수를 호출하면 해당 함수가 생성자로서 동작한다.
또한 어떤 함수가 생성자 함수로서 호출된 경우 내부에서의 this는 곧 새로 만들 구체적인 인스턴스 자신이다.

  1. 생성자 함수를 호출하면
  2. 생성자의 prototype 프로퍼티를 참조하는 __proto__라는 프로퍼티가 있는 객체(인스턴스)를 만들고
  3. 미리 준비된 공통 속성 및 개성을 해당 객체(this)에 부여한다.

    => 이런 단계를 통해 구체적인 인스턴스가 생성된다.

예제)

  1. Cat이란 변수에 익명 함수를 할당했다.
  2. 이 함수 내부에서는 this에 접근해서 bark, name, age 프로퍼티에 각각 값을 대입한다.
  3. new 명령어와 함께 Cat 생성자 함수를 호출한다.
  4. 그렇게 함수를 호출하여 변수 choco, nabi를 각각 할당한다.
  5. 출력된 log를 보니, 각각 Cat 클래스의 인스턴스 객체가 출력된다.

    => choco에 할당된 생성자 함수 내부에서의 this는 > choco 인스턴스를 가리킨다.
    => nabi에 할당된 생성자 함수 내부에서의 this는 > nabi 인스턴스를 가리킨다.

2. 명시적으로 this를 바인딩하는 방법

상황별로 어떤 값이 this에 바인딩되는 규칙을 깨고, this에 별도의 대상을 바인딩하는 방법을 소개하고자 한다.

2-1. call 메서드

Function.prototype.call(thisArg[, arg1])

call 메서드는 메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령이다. call 메서드의 첫 번째 인자를 this로 바인딩하고, 이후의 인자들을 호출할 함수의 매개변수로 한다.
함수를 그냥 실행하면 this는 전역객체를 참조하지만 call 메서드를 이용하면 임의의 객체를 this로 지정할 수 있다.

예제 1 )

만약 함수를 그냥 호출하면서 this를 지정해주려고 하면, 지정한 객체는 그냥 함수의 첫 번째 인자로서 작동한다.

예제 2 )

2-2. apply 메서드

Function.prototype.apply(thisArg[, argsArray])

apply 메서드와 call는 기능적으로 완전히 동일하다.

차이가 있다면 call 메서드는 첫 번째 인자를 제외한 나머지 모든 인자들을 호출할 함수의 매개변수로 지정하는 반면, apply 메서드는 두 번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개변수로 지정한다.

2-3. call & apply 메서드의 활용

2-3-1. 유사배열객체(array-like object)에 배열 메서드 적용

예제 1 ) 유사배열객체에 배열 메서드 적용

객체에는 배열 메서드를 직접 적용할 수 없다. 그러나 유사배열객체(key가 0 또는 양의 정수인 프로퍼티가 존재, length 프로퍼티의 값이 0 또는 양의 정수인 객체)인 경우, call이나 apply 메서드를 통해 배열 메서드를 차용할 수 있다.

위 예제의 경우 배열 메서드인 push를 객체 obj에 적용해 프로퍼티 3에 'd'를 추가했다.
또한 slice 메서드를 적용해 객체를 배열로 전환하기도 했다.

slice 메서드 예제 )

slice 메서드는 매개변수를 아무것도 받지 않을 경우, 원본 배열의 얕은 복사본을 반환한다.
이를 이용하여 call 메서드를 통해 원본인 유사배열객체의 얕은 복사를 수행하고, slice가 배열 메서드인 만큼 복사본은 배열로 반환되었다.

위 예제에서 call 메서드를 호출하지 않은 경우, 이와 같이 배열의 변수이름을 인자로 넣어도 빈 배열이 반환되는 것을 볼 수 있다. (얕은 복사를 수행할 명령이 없었기 때문이다.)

이러한 활용은 함수 내부에서 접근할 수 있는 arguments 유사배열객체나, querySelectorAll, getElementsByClassName 등의 Node 선택자로 선택한 결과인 NodeList에도 적용할 수 있다.

예제 2 ) arguments, NodeList에 배열 메서드 적용

이 밖에도 유사배열객체는 call, apply 메서드를 통해 모든 배열 메서드를 적용할 수 있다. 배열처럼 인덱스와 length 프로퍼티를 지니는 문자열에 대해서도 마찬가지이다.
(단, 문자열의 경우 length 프로퍼티가 읽기 전용이기 때문에 원본 문자열에 변경을 가하는 메서드는 에러를 반환한다. 또한, concat처럼 대상이 반드시 배열이어야 하는 경우는 에러를 반환받지 않더라도 제대로 된 결과를 얻을 수 없다.)

예제 3 ) 문자열에 배열 메서드 적용

var str = 'abc def';  

Array.prototype.push.call(str, ', pushed string');  // TypeError: Cannot assign to read only property 'length' of object '[object String]'

Array.prototype.concat.call(str, 'string');
/*
[
  String {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    '3': ' ',
    '4': 'd',
    '5': 'e',
    '6': 'f',
    length: 7,
    __proto__: String { ... }
  },
  'string'
]
*/

Array.prototype.every.call(str, function(char) { return char !== ''; });  // false

Array.prototype.some.call(str, function(char) { return char === ''; });  // true

var newArr = Array.prototype.map.call(str, function(char) { return char + '!'; });
console.log(newArr);  // [ 'a!', 'b!', 'c!', ' !', 'd!', 'e!', 'f!' ]

var newStr = Array.prototype.reduce.apply(str, [
  function(string, char, i) { return string + char + i; }, ''
]);
console.log(newStr);  // 'a0b1c2 3d4e5f6'

위와 같이 call, apply 메서드를 이용해 형변화를 하는 것은 'this를 원하는 값으로 지정하여 호출한다'는 본래 의도를 벗어나는 활용법이긴 하다. 특히나 slice 메서드는 오직 배열 형태로 복사하기 위해 차용된 메서드이니, 이 의도를 알고 있지 않은 개발자가 코드를 봤을 때 파악이 어려울 가능성이 있다.
이에 ES6에서는 유사배열객체 또는 순회 가능한 모든 종류의 데이터 타입을 배열로 전환하는 Array.from 메서드를 새로 도입했다.

예제 4 ) ES6의 Array.from 메서드

2-3-2. 생성자 내부에서 다른 생성자를 호출

생성자 내부에 다른 생성자와 공통된 내용이 있을 경우, call 또는 apply를 이용해 다른 생성자를 호출하면 간단하게 반복을 줄일 수 있다.

예제 1 ) Strudent, Employee 생성자 함수 내부에서 Person 생성자 함수를 호출하여 인스턴스의 속성을 정의하도록 구현함

2-3-3. 여러 인수를 묶어 하나의 배열로 전달하고 싶을 때 - apply 활용

여러 개의 인수를 받는 메서드에게 하나의 배열로 인수들을 전달하고 싶을 때 apply 메서드를 사용하면 편리하다.

예제 1 ) 배열에서 최대/최솟값을 구해야 할 경우

// 코드 직접 구현

var numbers = [10, 20, 3, 16, 45];

var max = min = numbers[0];
numbers.forEach(function(number) {
  if (number > max) max = number;
  if (number < min) min = number;
});

console.log(max, min);  // 45 3

⬇️⬇️⬇️

// 여러 인수를 받는 메서드(Math.max/Math.min)에 apply 적용

var numbers = [10, 20, 3, 16, 45];

var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);

console.log(max, min);  // 45 3

⬇️⬇️⬇️

// 여러 인수를 받는 메서드(Math.max/Math.min)에 spread operator 적용

var numbers = [10, 20, 3, 16, 45];

var max = Math.max(...numbers);
var min = Math.min(...numbers);

console.log(max, min);  // 45 3

call과 apply 메서드는 명시적으로 별도의 this를 바인딩하면서 함수 또는 메서드를 실행하는 훌륭한 방법이지만, 오히려 this를 예측하기 어렵게 만들어 코드 해석을 방해한다는 단점이 있다.
그럼에도 불구하고 ES5 이하의 환경에서는 마땅한 대안이 없어 실무에서 매우 광범위하게 활용되고 있다.

2-4. bind 메서드

Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]])

bind 메서드는 ES5에서 추가된 기능으로, "call과 비슷하지만 즉시 호출하지는 않고, 넘겨받은 this 및 인수들을 바탕으로 새로운 함수를 반환하기만 하는 메서드"이다.
다시 새로운 함수를 호출할 때 인수를 넘기면, 그 인수들은 기존 bind 메서드를 호출할 때 전달했던 인수들의 뒤에 이어서 등록된다. 즉 bind 메서드함수에 this를 미리 적용하는 것부분 적용 함수를 구현하는 두 가지 목적을 모두 지닌다.

예제 1 )

var func = function (a, b, c, d) {
  console.log(this, a, b, c, d);
};

func(1, 2, 3, 4);  // window{ ... } 1 2 3 4

var bindFunc1 = func.bind({ x: 1 });  // this만 지정
bindFunc1(5, 6, 7, 8);  // { x: 1 } 5 6 7 8

var bindFunc2 = func.bind({ x: 1 }, 4, 5);  // this 지정 및 부분 적용 함수 구현
bindFunc2(6);  // { x: 1 } 4 5 6 undefined
bindFunc2(6, 7);  // { x: 1 } 4 5 6 7
bindFunc2(8, 9);  // { x: 1 } 4 5 8 9

2-4-1. name 프로퍼티

bind 메서드를 적용해 새로 만든 함수는 "name 프로퍼티에 동사 bind의 수동태인 bound라는 접두어가 붙는" 독특한 성질이 있다.

어떤 함수의 name 프로퍼티가 bound xxx라면 이는 곧 '함수명이 xxx인 원본 함수에 bind 메서드를 적용한 새로운 함수'라는 뜻이므로 call, apply 메서드보다 코드 추적이 더 수월하다.

var func = function (a, b, c, d) {
  console.log(this, a, b, c, d);
};

var bindFunc = func.bind({ x: 1 }, 4, 5);

console.log(func.name);  // 'func'
console.log(bindFunc.name);  // 'bound func'

2-4-2. 상위 컨텍스트의 this를 내부함수나 콜백 함수에 전달하기

call, apply, bind 메서드를 이용하면 self 등의 변수를 이용했을 때보다 더 간단하게 this를 상속할 수 있다.

예제 1 ) call vs. bind

// call

var obj = {
  outer: function () {
    console.log(this);  // obj.outer(); => { outer: ƒ outer() }
    
    var innerFunc = function () {
      console.log(this);  //     innerFunc.call(this); => { outer: ƒ outer() }
    };
    
    innerFunc.call(this);
  }
};

obj.outer();
// bind

var obj = {
  outer: function () {
    console.log(this);  // obj.outer(); => { outer: ƒ outer() }
    
    var innerFunc = function () {
      console.log(this);  //     innerFunc(); => { outer: ƒ outer() }
    }.bind(this);
    
    innerFunc();
  }
};

obj.outer();

위의 방법에 더불어, 콜백 함수를 인자로 받는 함수(메서드) 중에서 기본적으로 콜백 함수 내에서의 this에 관여하는 함수(메서드)에 대해서도 bind 메서드를 이용하면 this 값을 명시적으로 지정할 수 있다.

예제 2 ) bind 메서드를 이용하여 내부함수에 this 전달

var obj = {
  logThis: function () {
    console.log(this);
  },
  logThisLater1: function () {
    setTimeout(this.logThis, 500);
  },
  logThisLater2: function () {
    setTimeout(this.logThis.bind(this), 1000);
  }
};

obj.logThisLater1();  // Window { ... }
obj.logThisLater2();  // obj { logThis: ƒ logThis(), ... }

2-5. arrow function의 예외사항

ES6에서 새롭게 도입된 화살표 함수는 실행 컨텍스트 생성 시 this를 바인딩하는 과정이 제외되었다.
즉 이 함수 내부에는 this가 아예 없고, 접근하고자 하면 스코프 체인상 가장 가까운 this에 접근하게 된다.

예제 1 ) 화살표 함수 내부에서의 this

var obj = {
  outer: function () {
    console.log(this);  // { outer: ƒ outer() }
    
    var innerFunc = () => {  // 화살표 함수는 this를 바인딩하지 않기 때문에 this가 없다. 따라서 가장 가까운 this인 obj에 접근하게 된다.
      console.log(this);  // { outer: ƒ outer() } 
    };
    
    innerFunc();
  }
};

obj.outer();

이렇게 하면 별도의 변수로 this를 우회하거나 call, apply, bind를 적용할 필요가 없어 더욱 간결하고 편리하다.

2-6. 별도의 인자로 this를 받는 경우 (콜백 함수 내에서의 this)

콜백 함수를 인자로 받는 메서드 중 일부는 this로 지정할 객체(thisArg)를 인자로 지정할 수 있다.
이런 메서드의 thisArg 값을 지정하면, 콜백 함수 내부에서 this 값을 명시적으로 변경할 수 있다.

이런 형태는 내부 요소들에 대해 같은 동작을 반복 수행해야 하는 배열 메서드에 주로 있으며, 같은 이유로 ES6에서 새로 등장한 Set, Map 등의 메서드에도 일부 존재한다. 그중 대표적인 배열 메서드인 forEach의 예를 살펴보자.

forEach:

arr.forEach(callback(currentValue[, index[, array]]) {
  // execute something
}[, thisArg]);
var report = {
  sum: 0, 
  count: 0,
  add: function () {
    var args = Array.prototype.slice.call(arguments);
    args.forEach(function (entry) {
      this.sum += entry;
      ++this.count;
    }, this);  // thisArg 위치에 this로 지정할 객체를 지정했다.
  },
  average: function () {
    return this.sum / this.count;
  }
};

report.add(60, 85, 95);
console.log(report.sum, report.count, report.average());  // 240 3 80

콜백 함수와 함께 thisArg를 인자로 받는 메서드:
forEach, map, filter, some, every, find, findIndex, flatMap, from, Set.prototype.forEach, Map.prototype.forEach

3. 정리

명시적 this 바인딩이 없을 때의 규칙

  • 전역공간에서의 this는 전연객체를 참조한다.
  • 어떤 함수를 메서드로서 호출한 경우 this는 메서드 호출 주체를 참조한다.
  • 어떤 함수를 함수로서 호출한 경우 this는 전역객체를 참조한다. (메서드의 내부함수에서도 같다.)
  • 콜백 함수 내부에서의 this는 해당 콜백 함수의 제어권을 넘겨받은 함수가 정의한 바에 따르며, 정의하지 않은 경우에는 전역객체를 참조한다.
  • 생성자 함수에서의 this는 생성될 인스턴스를 참조한다.

명시적 this 바인딩

  • call, apply 메서드는 this를 명시적으로 지정하면서 함수 혹은 메서드를 호출한다.
  • bind 메서드는 this와 함수에 넘길 인수를 일부 지정하여 새로운 함수를 만든다.
  • 요소를 순회하면서 콜백 함수를 반복 호출하는 내용의 일부 메서드는 별도의 인자로 this를 받기도 한다.

this를 바인딩하지 않는 arrow function

  • arrow function을 통해 함수를 선언하면 this가 바인딩되지 않기 때문에 this가 없다. 이때 this를 사용하고자 하면 가장 가까운 scope부터 차례대로 this를 찾아, 가장 가까운 this를 참조한다.
profile
💡 Software Engineer - F.E

0개의 댓글