22. this

1. this 키워드

  • 메서드가 자신이 속한 객체의 프로퍼티를 참조하려면 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 한다.
  • 객체 리터럴 방식의 경우 메서드 내부에서 식별자를 재귀적으로 참조할 수 있다.
  • 생성자 함수 방식의 경우 생성자 함수를 정의하는 시점에서는 아직 인스턴스를 생성하기 전이므로 인스턴스를 가리키는 식별자를 알 수 없다.

this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기참조변수다.

⇒ this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다.

  • 함수를 호출하면 arguments 객체와 this가 암묵적으로 함수 내부에 전달된다.
  • 단, this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.

** 바인딩? 식별자와 값을 연결하는 과정

2. 함수 호출방식과 this 바인딩

자바스크립트에서 this 바인딩은 함수의 호출 시점에 따라 동적으로 결정된다

  • 1. 일반함수 호출
    • 일반함수로 호출된 모든 함수(중첩함수, 콜백함수 포함) 내부의 this에는 전역 객체(window)가 바인딩된다.
    • strict 모드가 적용된 일반 함수 내부의 this에는 undefined가 바인딩된다
    • 하지만, 메서드 내의 중첩함수 또는 콜백함수의 this가 외부함수의 this와 일치하지 않는 것은 헬퍼함수로서 동작을 어렵게 한다.
      • Function.prototype.apply Function.prototype.call Function.prototype.bind 로 명시적으로 this를 일치시킬 수 있다
      • 화살표 함수를 사용해서 this를 일치시킬 수 있다
      • ( 화살표 함수는 자신만의 this를 갖지 않기 때문에 lexical scope를 갖게 된다. 그래서, 화살표 함수 내부의 this는 상위 스코프의 this를 가리킨다 )
  • 2. 메서드 호출
    • 점 연산자를 통해 객체의 메서드로서 호출되는 함수의 내부에서 this는 점 연산자(.) 앞에 있는 객체에 바인딩된다.
    • 이를 암묵적 바인딩이라고 부른다.
    • const person = { name: 'Lee', getName() { return this.name; } } console.log(person.getName()); //Lee
    • getName 메서드는 person 객체에 포함된 것이 아니라 독립적으로 존재하는 별도의 객체다.
      (새롭게 알게 됨!! 흥미돋!!)
      그저 getName 프로퍼티가 함수 객체를 가리키고 있을 뿐이다. ⇒ 그렇기 때문에 this는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩되는 것인가??
    • 그래서 getName 프로퍼티가 가리키는 함수객체, 즉 getName 메서드는 다른 객체의 메서드도 될 수 있고, 일반 변수에 할당해서 일반함수로 호출될 수 있다.
    • const anoterPerson = { name: "kim" } anotherPerson.getName = person.getName // this는 anotherPerson const getName = person.getName // this는 window
    • 프로토타입 메서드 내부에서 사용되는 this도 일반 메서드와 마찬가지로 호출한 객체에 바인딩된다.
  • 3. 생성자 함수 호출
    • new 연산자와 함께 호출되는 경우 함수는 생성자로써 호출된다
    • 생성자 함수 내부에서 this는 생성할 객체를 의미한다.
    • // 생성자 함수 function Person(name) { this.name = name; } var me = new Person('Lee'); console.log(me); // Person {name: "Lee"} // new 연산자와 함께 생성자 함수를 호출하지 않으면 생성자 함수로 동작하지 않는다. var you = Person('Kim'); console.log(you); // undefined
  • 4. Function.prototype~ 객체의 메서드에 의한 간접호출
    • Function~~ 객체는 this를 명시적으로 바인딩할 수 있는 메서드를 제공한다.
    • apply, call
      • this로 사용할 객체와 인수 리스트를 인수로 전달받아 함수를 호출한다
      • 본질적인 기능은 함수를 호출하는 것이다. 함수를 호출하면서 첫 번째 인수로 전달한 특정 객체를 호출한 함수의 this에 바인딩한다.
      • 대표적인 용도는 arguments 객체와 같은 유사배열객체에 Array.prototype.slice 같은 배열 메서드를 사용하는 경우다.
      • function convertArgsToArray() { console.log(arguments); // arguments 객체를 배열로 변환 // slice: 배열의 특정 부분에 대한 복사본을 생성한다. var arr = Array.prototype.slice.apply(arguments); // arguments.slice // var arr = [].slice.apply(arguments); console.log(arr); return arr; } convertArgsToArray(1, 2, 3); // [1,2,3]
    • bind
      • this로 사용할 객체로 this 바인딩이 교체된 함수를 새롭게 생성해 반환한다.
      • apply와 call 과 달리 함수를 호출하지 않으므로 명시적으로 호출해야 한다.
      • const person = { name: "Lee", foo(callback) { setTimeout(callback.bind(this), 100); }, }; person.foo(function () { console.log(`Hi! my name is ${this.name}`); }); // Hi! my name is Lee

정리

함수호출방식 this 바인딩
일반함수 호출 전역 객체
메서드 호출 메서드를 호출한 객체
생성자 함수 호출 생성자 함수가 (미래에) 생성할 인스턴스
Function.prototype.apply Function.prototype.call Function.prototype.bind 메서드에 의한 간접 호출 Function.prototype.apply Function.prototype.call Function.prototype.bind 메서드에 첫번째 인수로 전달한 객체

추가1 : this 바인딩 우선순위

new 연산자에 의한 바인딩 > 명시적 바인딩 > 암시적 바인딩 > 일반함수 호출에 의한 바인딩

  • bind 메서드에 의한 바인딩이 apply, call에 의한 바인딩보다 우선순위가 높다
  • apply, call, bind 실행 시 이를 호출한 함수가 화살표 함수면 첫번째 인자인 thisArg가 무시된다. (화살표 함수는 자신만의 this, argument가 없기 때문에 자신의 lexical scope인 window가 this가 된다. )
const person = {
  name: "Lee",
  foo(callback) {
    setTimeout(callback.bind(this), 100);
  },
};

person.foo(() => {
  console.log(`Hi! my name is ${this.name}`);
});

// window.name은 빌트인 프로퍼티로 ""이다.
// Hi! my name is

'엘리스 ai 트랙 > FE' 카테고리의 다른 글

Javascript - ES11 ( ES2020 )의 특징들  (0) 2022.04.04
CI와 CD  (0) 2022.03.31
http 1.1 과 http 2 의 차이점  (0) 2022.03.31
HTTP  (0) 2022.03.13
기본값+rest+spread  (0) 2022.03.07

+ Recent posts