[TIL] this

krkorklo·2022년 9월 12일
0

TIL

목록 보기
23/29
post-thumbnail

this

  • JavaScript에서 this는 자신이 속한 객체나 자신이 생성할 인스턴스를 가리키는 참조 변수
  • JavaScript의 함수가 호출될 때 매개변수로 전달되는 값 외에 this를 암묵적으로 전달받는다

this 바인딩

  • 함수 호출 방식에 따라 this에 바인딩할 객체가 동적으로 결정된다

1. 함수 호출

  • 일반적인 함수 실행 방식으로 함수를 실행했을 때 thisGlobal Object를 가리킨다
  • 브라우저 상에서 Global Objectwindow 객체, 서버 상에서 Global Objectglobal 객체
function func() {
  console.log(this); 
}

func(); // window
  • func() 방식으로 함수 호출하는 방식이 일반적인 함수 호출 방식
const name = "jhj";

function func() {
  console.log(this.name); 
}

func(); // jhj
  • 전역변수 nameGlobal Object인 window의 속성으로 추가된다 → window.name 생성
  • console.log(this.name) == console.log(window.name)

Strict mode의 함수 호출

  • Strict mode는 엄격한 규칙을 적용해 비엄격 모드에서 일어나는 오류를 감소
'use strict';

const name = "jhj";

function func() {
  console.log(this.name); 
}

func(); // error
  • strict mode에서 this는 window를 가리키지 않는다
  • this가 실수로 window 객체로 인식되어 발생하는 오류를 줄일 수 있다

2. 메소드 호출

  • 함수가 객체의 property면 메소드로 호출
const obj1 = {
  name: "jhj",
  getName: function() {
    console.log(this.name);
  }
}

const obj2 = {
  name: "krkorklo"
}

obj2.getName = obj1.getName;

obj1.getName(); // jhj
obj2.getName(); // krkorklo
  • 메소드 내부의 this는 해당 메소드를 소유한 객체에 바인딩

3. 생성자 함수 호출

  • 객체를 생성하는 함수
  • 기존 함수에 new 연산자를 붙여 호출하면 생성자 함수로 동작

생성자 함수 동작 방식

  1. 빈 객체 생성 및 this 바인딩
  • 생성자 함수가 빈 객체를 생성하고 생성자 함수 내에서 this는 해당 객체를 가리킴
  1. this를 사용해 property 생성
  • 빈 객체를 가리키는 this를 사용해 프로퍼티나 메소드 추가
  1. 생성된 객체 반환
  • 리턴문이 없으면 this에 바인딩된 객체가 반환
  • this가 아닌 다른 객체를 명시적으로 리턴하는 경우 명시적으로 선언된 객체가 리턴 (생성자 함수의 역할을 하지 못함)

생성자 함수 호출

function Person(name) {
  this.name = name;
}

const person = new Person("jhj");
console.log(person); // jhj
  • new 연산자와 함께 생성자 함수를 호출하면 Person.prototype을 프로토타입 객체로 가지는 객체가 생성

new 연산자를 붙이지 않는 경우

  • new 연산자를 붙이지 않으면 일반 함수로서 호출된다
function Person(name) {
  this.name = name;
}

const person = Person("jhj");

console.log(person); // undefined
console.log(window.name); // jhj
  • new 없이 생성자 함수를 호출하면 this를 암묵적으로 반환하지 않아 undefined가 반환
  • new 없이 생성자 함수를 호출한 경우 Persom 내부의 this는 전역 객체를 가리키게 되어 전역 변수에 바인딩

4. apply/call/bind 호출

  • this에 바인딩될 객체는 함수 호출 패턴에 따라 JavaScript 엔진이 동적으로 바인딩
  • 명시적으로 바인딩하기 위해 Function.prototype 객체의 메소드인 apply, call, bind 사용

1) Function.prototype.apply

  • this를 특정 객체에 바인딩
  • 함수 내부의 this에 바인딩할 객체와 함수에 전달할 arguments의 배열을 인자로 호출
const Person = function (name) {
  this.name = name;
}

const per = {};

Person.apply(per, ['jhj']);
console.log(per); // { name : 'jhj' }
  • Person 함수의 this가 per 객체가 된다
  • this(per)에 name property가 없으므로 name이 동적으로 추가되고 값이 할당

2) Function.prototype.call

  • apply와 기능은 같지만 배열 형태로 arguments를 넘기는 것이 아니라 하나씩 인자로 전달
Person.call(per, 'jhj');

3) Function.prototype.bind

  • 함수에 인자로 전달한 this가 바인딩된 새로운 함수를 리턴
  • call, apply와 달리 함수를 실행하는 것이 아니라 연결만 하는 것
const Person = function (name) {
  this.name = name;
  console.log(this);
};

const per = { age: 23 };

const newPer = Person.bind(per, "jhj");
newPer();

화살표 함수의 this 바인딩

화살표 함수

  • ES6 후 등장한 문법으로 function 키워드 없이 => 화살표 표시로 함수를 선언
const func = () => console.log("function");

this 바인딩

  • 화살표 함수에는 this가 존재하지 않기 때문에 상위 환경의 this를 참조한다
  • 일반적인 함수는 메소드로 호출하느냐, 함수로 호출하는냐에 따라 this가 동적으로 바인딩되지만 화살표 함수에서는 선언될 시점의 상위 스코프this로 정적 바인딩
function Person(name) {
  this.name = name;
}

Person.prototype.console = function (arr) {
  // this는 상위 스코프인 Person 메소드 내의 this를 가리킨다
  return arr.map(x => `${this.name}  ${x}`);
};

const person = new Person('krkorklo');
console.log(person.console(['hi', 'hello']));
  • 화살표 함수는 apply, call, bind를 사용해 this를 변경할 수 없다

화살표 함수를 사용하면 안되는 경우

1) 메소드 정의

const person = {
  name: "jhj",
  console: () => console.log(`hi ${this.name}`)
}

person.console(); // hi undefined
  • 화살표 함수로 메소드를 정의하는 경우 this가 상위 컨텍스트의 전역 객체(window)를 가리키게 된다

2) prototype 할당

const person = {
  name: "jhj"
}

Object.prototype.getName = () => console.log(`hi ${this.name}`);

person.getName(); // hi undefined
  • prototype으로 할당하는 경우에도 this가 상위 컨텍스트의 전역 객체를 가리키게 되므로 일반 함수를 사용해야한다

3) 생성자 함수

  • 생성자 함수는 prototype property를 가져 prototype property가 가리키는 프로토타입 객체의 constructor를 사용해서 객체 생성
  • 화살표함수는 prototype property를 가지지 않으므로 화살표함수를 사용하면 안된다
const Person = () => {};

const person = new Person(); // Person is not a constructor

4) addEventListener의 콜백 함수

  • addEventListener의 콜백 함수를 화살표 함수로 정의하면 this의 상위 컨텍스트인 전역 객체(window)를 가리킨다
let button = document.getElementById('button');

button.addEventListener('click', () => {
  console.log(this === window); // true
});

button.addEventListener('click', function() {
  console.log(this === button); // true
});
  • 일반 함수를 사용해야 이벤트 리스너에 바인딩된 target을 가리킨다

참고자료
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this
https://poiemaweb.com/js-this
https://poiemaweb.com/es6-arrow-function

0개의 댓글