this에 대하여

Sheryl Yun·2022년 1월 18일
0

Javascript 정복

목록 보기
3/9
post-thumbnail

This란?

출처: [10분 테코톡 - 브콜의 This] https://www.youtube.com/watch?v=7RiMu2DQrb4

일반적으로 객체지향 언어에서의 this
함수가 속해 있는 객체의 자기 자신과 관련이 깊다.

자바스크립트에서는 자기 자신이라는 말이 상당히 모호한데,
그 이유는 자바스크립트의 함수가 '일급 객체'이기 때문이다.

일급 객체란?

  • 변수에 저장될 수 있으며,
  • 함수의 인수로 전달이 가능하고
  • 함수의 반환값으로 사용할 수 있다.

사용 시에는 단독으로 호출되거나, 특정 객체의 '메서드'로,
또는 동일한 메서드를 다른 객체에서 호출하는 것도 가능하다.

이렇게 자바스크립트에서는
함수가 선언된 이후
어떤 환경에서 어떤 객체에 의해 '호출'될지
에 따라 this가 달라진다.

예: 브로콜리가 "내 꺼"라고 외치고 아보카도가 "내 꺼"라고 외쳤을 때
'나'가 가리키는 대상은 각각 다르다.

바인딩(binding)이란?

자바스크립트에서 모든 함수는 this를 가지고 있다.

함수가 호출될 때마다 this가 가리키는 객체가 동적으로 결정되는 것
this가 그 객체에 '바인딩되었다'고 표현한다.

this가 바인딩되는 상황

프로그램이 실행되면

  1. 전역 코드를 평가해서 전역 실행 문맥을 만든다.
  2. 함수가 실행되면
    전역 코드의 실행을 잠깐 멈추고 해당 함수의 실행 문맥을 만든다.
    (이 함수의 실행 문맥에서 this 바인딩 컴포넌트의 값이 결정된다)

This의 바인딩 규칙

this는 기본적으로 4가지 규칙에 의해 바인딩된다.

  1. 기본 바인딩
  2. 암시적 바인딩
  3. 명시적 바인딩
  4. new 바인딩

1. 기본 바인딩

함수를 단독 실행할 때의 규칙이다.
브라우저 환경과 Node 환경의 두 가지 경우로 나뉜다.

브라우저 환경

브라우저 환경에서 기본 바인딩 대상은 window 전역 객체이다.

use strict('엄격 모드')를 사용할 경우
전역 객체가 기본 바인딩 대상에서 제외되어서
this가 바인딩될 객체가 존재하지 않음 => undefined로 대체됨

Node.js 환경

Node.js 의 기본 바인딩 대상은 global 전역 객체이다.

전역 공간에서는 빈 객체(= module.exports)에 바인딩,
함수 내부 코드에서는 global에 바인딩

2. 암시적 바인딩

this를 포함한 함수'객체의 메서드'로 호출이 되는 경우이다.
형태: 호출 시 점(.) 바로 앞에 있는 객체에 this가 바인딩됨

3. 명시적 바인딩

this를 '내가 정한 객체'로 고정하여 바인딩하는 것이다.

암시적 바인딩에서는 '한두 다리만 건너도 this가 소실'되지만 명시적 바인딩에서는 이를 해결한다.

종류에는 call, apply, bind 메서드가 있다.

이미 생성된 클래스에 다른 인수를 넣어 수정해서 사용하고 싶다면
새로운 클래스 객체를 또 만드는 게 아니라 이 메서드들을 사용해서 명시적 바인딩을 하면 된다.

형태적 차이

1) call, apply

2) bind

context 뒤에 오는 요소들은 각 메서드의 앞에 오는 함수의 인수
(context는 필수이고 뒤에 오는 인수들은 option)

코드 살펴보기

1) call, apply

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    info(v, w) {
        console.log(`x: ${this.x}, y: ${this.y}, v: ${v}, w: ${w}`);
    }
}

var point = new Point(10, 20);

point.info(1, 2);

var customPoint = { x: 100, y: 200 };

point.info.call(customPoint, 20, 30);
point.info.apply(customPoint, [2, 3]);

실행 내용

call과 apply는 바인딩을 진행하고 자체적으로 실행까지 한다.

call과 apply 사이의 차이

함수를 실행할 때
call은 인수를 하나씩 넘기고, apply배열로 넘긴다.

2) bind

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    
    info(){
        console.log(`x: ${this.x}, y: ${this.y}`);
    }
}

var point = new Point(10, 20);

point.info();

point.info.bind({ x: 100, y: 200 })(); // 뒤에 소괄호를 붙여 실행!

실행 내용

bind는 바인딩만 진행하고 자체 실행은 하지 않는다.
따라서 반드시 뒤에 소괄호 ( )를 붙여줘야 실행이 된다.
bind의 인자로는 객체{ } 형태로 수정할 인수값들을 넣어준다.

4. new 바인딩

new 연산자로 호출할 때 this가 바인딩되는 규칙이다.

위의 과정에서 this는 1번째 단계인 '새로운 객체 생성' 단계에서 바인딩된다.

아래는 객체 리터럴로 객체를 생성한 경우이다.

위의 func() 함수는 정해진 객체를 반환하는 생성자로서의 역할을 수행하게 된다.

바인딩 우선순위

4가지 규칙 중 여러 개가 동시에 적용되는 상황에서 무엇이 더 우선인지는 다음과 같다.


화살표 함수

ES6 문법부터 새롭게 추가된 화살표 함수는
기존의 함수와 다른 방식으로 this를 바인딩한다.

위의 예제는 비동기 함수 setTimeout에 화살표 함수를 사용하고 있다.

화살표 함수는 선언될 당시의 '상위 실행 문맥(context)을 기억'한다.

이러한 특징 때문에 화살표 함수를 사용하면
점(.)으로 호출되는 암시적 바인딩에서도 this에 바인딩된 내용을 잃어버리지 않는다.

이러한 this를 '어휘적(렉시컬) this'라고 부른다.
(= 정적으로 바인딩된 this = '선언'될 때 자신이 바인딩되었던 대상을 기억)

profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글