TIL 51 | This

ym j·2021년 7월 18일
0

JavaScript

목록 보기
7/7
post-thumbnail

This

This란?

  • this란 함수가 호출될 때, 즉 실행 컨텍스트가 생성될 때 가리키는 대상 (혹은 값)이다.
  • 함수를 어떻게 호출하느냐에 따라서 가리키는 대상이 동적으로 달라진다.


전역 공간에서의 this

console.log(this); // Window {...}
console.log(this === window); // true
  • 전역에서 this가 가리키는 대상은 Window라는 전역 객체이다.

  • 브라우저에서는 Window, Node.js에서는 global 객체를 가리킨다.


+ 전역 변수와 전역 객체

var a = 1;
console.log(a); // 1
console.log(window.a); // 1
//
let b = 2;
console.log(b); // 2
console.log(window.b); // undefined
//
const c = 3;
console.log(c); // 3
console.log(window.c); // undefined
//
function print2() {
  console.log("hello");
}
//
print2(); // "hello"
window.print2(); // "hello"
  • 전역 객체와 전역 변수의 관계를 잠시 짚고 넘어가자면, var를 사용하여 변수를 선언 및 할당하게 될 시 window 전역 객체의 프로퍼티로 지정이 된다. (함수 선언문 또한 전역 객체의 프로퍼티로 지정된다.)

  • var와 다르게, letconst의 경우 window 객체의 프로퍼티로 접근할 수 없다.



함수로 호출할 때 vs 메서드로 호출할 때 가리키는 this

방식 비교 (함수 vs 메서드)

const printName = function () {
  console.log(this);
};
printName(); // Window {...}
//
const yongmin = { name: "yongmin", method: printName };
//
yongmin.method(); // { name: 'yongmin', method: ƒ printName() }
  • 함수를 실행하는 방법은, 독립적으로 함수를 호출하는 방법과 객체의 메서드로서 호출하는 방법이 있다.

  • 함수의 호출 방법 구분은 함수 앞의 .이다.

  • 특정 함수를 함수로서 호출할 경우 this가 지정되지 않는다.(호출 주체가 없다) 또한 이러할 경우 this는 전역 객체를 바라보게 된다. (자동으로 전역객체가 바인딩이 된다.)

  • 메서드로서 호출할 경우, 호출 주체는 .앞의 객체이며 이때 this가 가리키는 대상이 호출 주체인 객체가 된다.

메서드 안의 내부함수에서의 this

const obj = {
  outer: function () {
    console.log(this); // { outer: ƒ outer() }
    var inner = function () {
      console.log(this); // Window {...}
    };
    inner(); // 함수로서 호출
  },
};
obj.outer(); // 메서드로서 호출
  • 추가로 메서드 안의 내부함수 또한 함수로서 호출할 경우 this가 가리키는 대상이 전역객체임을 알 수 있다.

메서드 안의 내부함수에서의 this 우회하기

const obj = {
  outer: function () {
    console.log(this); // { outer: ƒ outer() }
    const target = this;
    var inner = function () {
      console.log(target); // { outer: ƒ outer() }
    };
    inner(); // 함수로서 호출
  },
};
obj.outer(); // 메서드로서 호출
  • 만일 메서드 안의 내부함수에서 this가 가리키는 객체가 전역 객체가 아닌 메서드가 속한 객체를 가리키게 하고자 할 경우, this를 특정 변수에 할당하여 우회하는 방법이 있다.

Arrow function

const obj = {
  outer: function () {
    console.log(this); // { outer: ƒ outer() }
    var inner = () => {
      console.log(this);
    };
    inner(); // 함수로서 호출
  },
};
obj.outer(); // 메서드로서 호출
  • ES6에서 도입한 화살표 함수의 경우, 함수로서 호출을 할 때 자동으로 전역 객체를 바인딩하지 않는다.

  • 화살표 함수에서의 this는 따로 가지고 있지 않고 스코프 체인상 가장 가까운 상위 객체가 된다. (이를 lexical this라고 한다.) 이러한 arrow function의 도입으로, 기존에 this를 변수에 선언했던 우회방법은 불필요해졌다.



콜백 함수 호출 시 그 함수 내부에서의 this

[1, 2, 3, 4, 5].forEach(function () {
  console.log(this); // Window {...} * 5
});
//
const target = document.getElementById("hello");
target.addEventListener("click", () => {
  console.log(this); // id가 `hello`인 대상
});
  • 일반적으로 콜백 함수도 메소드로서 호출된 것이 아니며, 특정 객체에 바인딩이 안됐기 때문에 this는 전역객체를 바라보게 된다.

  • 예외적으로 addEventListener의 경우는, 자기 자신의 this를 가리키도록 지정되어있다.



생성자 함수 내부에서의 this

const Person = function (name) {
  this.name = name;
};
//
const yongmin = new Person("yongmin");
console.log(yongmin);
// Person {
//   name: 'yongmin',
//   __proto__: { constructor: ƒ Person() }
// }
Person.prototype.printName = function () {
  console.log(this.name);
};
//
yongmin.printName(); // 'yongmin'
  • 생성자 함수는, ES6 클래스가 도입이 되기 전까지 객체를 생성하는데 사용한 함수이다.

  • 생성자 함수 내부에서의 this는, 생성된 객체(인스턴스) 자신을 가리키게 된다.



명시적으로 this 바인딩하기

call, apply

const callMethod = function (a, b, c) {
  console.log(this, this.x, a, b, c); { x: 1 } 1 2 3 4
};
//
callMethod.call({ x: 1 }, 2, 3, 4); // 
//
const applyMethod = function (a, b, c) {
  console.log(this, this.x, a, b, c);  // { x: 5 } 5 6 7 8
};
//
applyMethod.apply({ x: 5 }, [6, 7, 8]); 
  • 선언과 동시에 함수가 호출이 되며, callapply 메서드를 사용하면 특정 객체를 this가 가리키는 대상으로 지정할 수 있다.

  • 첫 번째 인자는 this가 가리키는 객체이며, 두 번째 인자의 경우call은 개별 형태로, apply는 배열 형태로 인자를 받게 된다.


bind

const bindMethod = function (a, b, c, d) {
  console.log(this, a, b, c, d); // { x: 1 } 10 1 2 3
};
//
const result = bindMethod.bind({ x: 1 }, 10);
result(1, 2, 3, 4); 
  • callapply와 다르게, 함수 선언과 동시에 호출이 되지 않는다.

  • bind는 함수를 호출할 때 this의 대상이 되는 객체, 혹은 인수들을 먼저 인자로 전달한다.

  • 다시 새로운 함수에 인자를 전달할 경우, 기존에 전달했던 인자들의 뒤에 이어서 등록된다.



Reference

profile
블로그를 이전하였습니다 => "https://jymini.tistory.com"

2개의 댓글

comment-user-thumbnail
2021년 7월 20일

👍👍👍👍👍

1개의 답글