[Javascript] this 바인딩

Isabel·2023년 8월 11일
0

CS 및 기술 정리

목록 보기
3/5

💡 객체지향언어에서의 this?

일반적으로 객체 지향 언어에서의 this는 함수가 속해있는 객체의 자기자신을 가리킴
하지만 Javascript에서의 this는 다름 !!

Javascript에서의 this

💡 Object를 참조하는 keyword

Javascript의 함수 → 일급 객체

함수를 …

  1. 변수나 데이터에 할당할 수 있음
  2. 다른 함수의 인자로 사용할 수 있음
  3. 다른 함수의 반환값, return 값으로 사용될 수 있음

→ 이렇게 다양한 환경에서 함수가 호출될 수 있기 때문에, this의 의미도 함수가 호출되는 상황(함수가 호출되는 방식)에 따라 가리키는 객체가 달라짐

Javascript 실행과정

  1. 자바스크립트 엔진 실행
  2. 실행 가능한 코드 분석
    • 전역 코드, 함수 코드, eval 코드, 블록문
  3. 실행 컨텍스트 생성
    • 변수 환경, 렉시컬 환경, this

this binding Rules

1. 기본 바인딩

1-1. 브라우저

함수를 단독으로 호출할 경우, 전역 객체 에 바인딩됨 → 브라우저에서 실행하면, 전역 객체인 window 가 바인딩 됨

function foo() {
  const a = 10;
  console.log(this.a);
}

foo(); // undefined

※ use strict 모드를 사용하면, 전역 객체를 this 바인딩 대상에서 제외시킴 → undefined 가 바인딩 됨

function showThis(){
	console.log(this);
}

function showThisinStrictMode(){
	'use strict'
	console.log(this);
}

showThis(); // window
showThisinStrictMode(); //undefined

1-2. Node

함수를 단독으로 호출한 경우, 동일하게 전역 객체 에 바인딩 됨 → Node에서는 global 에 바인딩 됨

※ 함수 호출이 아니라, 그냥 전역에서 this를 호출한다면?

function showThis(){
	console.log(this);
}

showThis(); // object[global]
console.log(this); // { }

→ 빈 객체 { } 가 출력되는데, 이는 node에서의 module.exports 와 동일하다.

module.exports : 파일을 모듈로 사용할 수 있게 해주는 객체

2. 암시적 바인딩

객체의 메서드로 호출되는 경우, Object.function();
→ 호출된 객체 Object 에 바인딩 됨

const obj = {
	name : "isabel",
	getName(){
		return this.name;
	}
}

console.log(obj.getName());

※ 참조 타입 Reference Type

const obj = {
	name : "isabel",
	getName(){
		return this.name;
	}
}

function showReturnValue(cb){
	console.log(cb());
}

showReturnValue(obj.getName); // undefined

자바스크립트에서 객체를 할당한 변수는 그 객체를 참조하는 값을 저장함
→ obj.getName에는 getName에 대한 참조값이 들어있는 것

참조값을 함수의 인자로 넘기게 되면, 그 참조값을 복제하여 사용
→ showReturnValue에서는 같은 getName의 참조값을 복제하여 cb에 저장하는 것이고, 이는 같은 것을 참조하는 또 다른 객체가 생성되는 것

💡 근데 같은 함수를 복제해서 쓰는데 showReturnValue에서는 왜 바인딩이 안 됨?

. 연산과 [] 연산을 통해서 객체의 property에 접근을 하면 참조 타입이라는 타입을 반환해줌

참조 타입?

  • Javascript 내부에서, 명세서 에서만 사용되는 타입(specification type)
    • (base, name, strict)
    • base : 해당 객체
    • name : 프로퍼티 이름
    • strict : strict mode 여부
obj.getName : (obj, getName, false)

위 함수를 호출하면 → 위의 obj에 this가 바인딩 됨

하지만 . 연산자와 { } 연산자를 제외한 다른 연산자들은 참조타입이 아닌 해당 프로퍼티의 값만을 전달함
→ 다른 함수로 인자로 넘기는 경우에도 참조 타입이 아닌 프로퍼티의 값만 전달되므로, 해당 값에는 base, 즉 원래 가지고 있던 객체는 전달되지 않음

이러한 문제를 해결하고 싶다면?!

3. 명시적 바인딩

3-1. call

call(context, arg1, arg2, ... )

3-2. apply

apply(context, args)

call, apply → this를 바인딩할 객체를 지정한 상태로 함수를 호출할 수 있음

const foo = {
  a: 20,
}

function bar() {
  console.log(this.a);
}
bar.call(foo); // 20
bar.apply(foo); // 20

3-3. bind

func.bind(context, arg1, arg2, ... )

this가 바인딩하는 객체를 고정시켜주는 함수로, this가 바인딩된 함수를 반환함

const foo = {
  a: 20,
}

function bar() {
  console.log(this.a);
}

const bound = bar.bind(foo)

bound(); // 20

a.k.a. hard binding

4. new 바인딩

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

const isabel = new Person("isabel"); //Person { name: 'isabel' }
console.log(isabel.name); // isabel

new func() → 생성자 함수로서의 기능을 수행할 수 있게 됨

  1. 새로운 객체를 내부에서 생성 ← this는 이 객체에 바인딩됨
  2. 함수의 코드 실행
  3. 새로 생성한 객체를 반환하여 변수에 할당

5. 바인딩 종류에 따른 우선순위

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

화살표 함수의 this 바인딩

const obj = {
	name : "isabel",
	showNameInSec(sec){
		setTimeout(() => {
			console.log(this.name);
		}, sec);
	}
}

obj.showNameInSec(1500); // isabel
  • 렉시컬 스코프와 상관없이 호출 당시에 의존하는 기존의 바인딩 방식과 달리, 화살표 함수에서는 선언될 당시의 상위의 실행 컨텍스트 의 this 바인딩 객체를 참조함
  • 선언할 때 정적으로 결정
  • Lexical this라고도 함
  • 위 코드의 경우, this.name의 this는 상위 스코프의 실행 컨텍스트에 있는 this, 즉 showNameInSec의 this를 가리키기 때문에, isabel을 정상적으로 출력할 수 있게 됨

참고
[JS] 알쏭달쏭 자바스크립트 this 바인딩
[10분 테코톡] 🥦 브콜의 This
[JS] 상황에 따른 this 바인딩
참조 타입

0개의 댓글