this

Khan·2022년 8월 5일
0

TIL

목록 보기
9/19
post-thumbnail

this

this 란

  • 객체의 메서드는 자신이 속한 객체의 property를 참조하고 수정할 수 있어야 합니다. 그러려면 자신이 속한 객체의 식별자를 참조할 수 있어야 합니다. 이 때 this가 유용하게 쓰이게 됩니다.
  • 또한 생성자 함수 내부에서 프로퍼티나 메서드를 추가하려면 자신이 생성할 인스턴스를 참조해야 합니다. 생성자 함수를 정의하는 시점에는 아직 인스턴스를 생성하기 전이기 때문에 인스턴스를 가리키는 식별자를 알 수 없습니다. 이럴 때 자신이 생성할 인스턴스를 가리키는 특수한 식별자인 this가 유용하게 사용됩니다.

this binding 이란

  • binding이란 식별자와 값을 묶는 것을 말합니다. 예를 들어 변수 선언도 binding이라고 할 수 있는데 왜냐면 변수 이름과 확보된 메모리의 공간의 주소를 묶는 것이기 때문입니다. this는 키워드로 분류되지만 식별자이기도 합니다. 그래서 이 this라는 식별자와 this가 가리킬 객체를 묶는 것을 this binding 이라고 합니다.

상황에 따라 달라지는 this

Global Context

전역공간에서 this를 사용하면 전역객체를 가르킨다.
ex) web = window, node.js = global

console.log(this === window); // true

a = 37;
console.log(window.a); // 37

window 와 global 은 ECMAScript 에서 정의 한 객체가 아니라 ECMAScript가 전역 객체는 이러이러해야 한다 라고 정의 해둔 내용에 따라서 런타임 에사 제공하는 구현체 이다.

Object method Context

메소드로 호출 했을 때의 this는 메소드를 호출한 주체, 메소드를 누가 호출 했는냐, 메소드 명의 '점' 바로 앞에 있는 애가 this 가 된다.

const a = {
  b: function () {
    console.log(this); // {b: ƒ}
  },
};
a.b();

/*
b라고 하는 함수는 a의 프로퍼티이다 즉 프로퍼티에 함수를 할당한 것이다. 
그런데 그 함수를, b함수를 a 객체의 메소드로써 호출했다 라는 말이된다.
그러니까 앞에 점이있으면 (=== a.b) 그 앞에 객체의 메서드로써 이 b를 호출했다 라는 말이 된다.
클래스와 상관없이 객체와 관련된 동작만 하면 메소드 라는 것이다.
b는 원래 함수인데 어떤 객체와 관련된 동작을 하면 그때는 메소드로 부르겠다 라는 말이다.
이때 '어떤객체'가 바로 점 앞에 있는 것이다. (=== a)
*/
const i = {
  j: 10,
  k: function () {
    console.log(this.j); // 10

    const l = () => {
      console.log(this.j); // 10
    };
    l();
  },
};
i.k();

// this를 바인딩 하지 않으므로 상위에 있는 this를 그대로 사용한다.
// 그래서 위 값과 똑같은 결과 값을 가르킨다.

Function Context

  1. 그냥 함수 실행
function a() {
  console.log(this); // window
}
a();
  • 함수를 호출하는 순간에 얘를 호출하는 주체에 따라서 this는 바뀐다. 여기서는 전역공간에서 호출 했으니 호출한 대상은 전역 객체가 되는것이다.
  1. 함수 안에 함수 실행
function b() {
  function c() {
     console.log(this); // window
  }
  c();
}
b();
  • 1번에 코멘트에 따라서 this === b를 가르켜야 하는데 window를 가르킨다. 이건 버그 또는 js 특성 이라고 많이 한다. 이것에 해결방법은 arrow function (3번)을 사용하는 것이다.
  1. 화살표 함수 안에 화살표 함수
const d = () => {
  const f = () => {
    console.log(this); // d
  };
  f();
};
d();
  • d 함수와 f 함수 둘 다 화살표 함수로 바꿔주었다. 결과는 {}(빈객체) 나왔다. this가 window를 가르키지 않고 d를 가르키게 성공하였다. 하지만 값이 없으니 {}(빈객체)로 나오는 것이다.
  1. 메서드 안에 함수
const g = {
  h: function () {
    function i() {
       console.log(this); // window
    }
    i();
  },
};
g.h();
  • 여기서 i를 보면 함수로써 호출을 했다. 그렇게 되면 무조건 전역객체를 가르킨다. 함수의 특성상 this가 누굴 가르키는지 쉽게 알기 위해서는 어떻게 호출 했는지 확인하면 된다.

Callback Function Context

  1. 기본적으로는 함수의 this와 같다.
    • (전역객체를 가르킨다)
const callback = function () {
  console.log(this); // window
};

const obj = {
  a: 1,
  b: function (callback) {
    callback();
  },
};
obj.b(callback);
  • 함수로써 callback 함수를 호출 했으므로 this = window
  1. 제어권을 가진 함수가 콜백의 this를 지정해둔 경우도 있다.
    • (지정해둔 this를 가르킨다)
const callback1 = function () {
  console.log(this); // {a1: 1, b1: ƒ}
};

const obj1 = {
  a1: 1,
  b1: function (callback1) {
    const c1 = callback1.bind(this);
    c1(); 
  },
};
obj1.b1(callback1);
  • callback1() 내부에서의 this는 콜백함수 자체가 뭘 어떻게 할 수있는게 아니고, 매개변수로 넘겨받는 이 callback1()를 어떤식으로 처리 하냐에 따라서 달라진다.
  1. this를 바인딩해서 콜백함수에 넘기면 this는 전역객체를 가르키지 않는다.
const callback2 = function () {
  console.log(this);
};
const obj2 = {
  a2: 1,
};
setTimeout(callback2.bind(obj2), 1000); //{ a2: 1 }
  • bind()를 사용하지 않으면 this는 window를 가르키게 된다. setTimeout이 콜백을 처리하는 방식을 임의로 바꿀 수 없으니 원하는 값으로 만들고 싶으면 bind()를 사용한다.

Constructor Function Context

function PeoPle(name, age) {
  this.name = name;
  this.age = age;
}

const a = PeoPle('SC', 23);
console.log(window.name, window.age); // SC, 23

일반적으로 new 연산자 없이 그냥 people 함수를 호출할 경우에는 a에는 아무것도 담기지 않게 되고 함수로써 호출한 것이기 때문에 window.name을 해주면 값을 얻을 수 있다.

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}
const b = new Person('RM', 24);
const c = new Person('V', 25);

console.log(b); // Person { name: 'RM', age: 24 }
console.log(c); //Person { name: 'V', age: 25 }

생성자 함수로써 호출 한 것이니 b와c에 즉 새로 생설될 person의 인스턴스 객체 자신이 곧 this가 된다. 그리고 객체가 새로 생성 되면서 name프로퍼티, age프로퍼티가 각각 생성된다.

참조

코어 자바스크립트
인프런 - 정재남님 강의

0개의 댓글