본문 바로가기
경일/Javascript

[Javascript] this 동적 바인딩

by dev_kong 2022. 1. 4.
728x90
728x90

0.목차

1. 개요

2. 메소드 생성

3. 메소드 호출

4. this 바인딩

1. 개요

수업에서 객체를 다뤘다.

혼자 객체도 만들어보고 메소드도 만들어보고

메소드로 property 참조하고 이것저것 해보다가,

어느 순간 깨달음이 와버렸다.

까먹기 전에 정리를 해보자.

 

2. 메소드 정의

const obj = {
  a: 1,

  print() {
    console.log('print');
  },
};

 

obj라는 객체를 하나 만들고,

프로퍼티 하나

메소드 하나씩 만들어줬다.

 

메소드는 익명함수 안쓰고

스마-트 하게 method shorthand 써서 만들었다.

es6에서 추가된 기능이다.

기존(es6 이전)에 어떤 형식으로 만들어졌는지 모른다면 문제가 되겠지만,

아니까 걍 쓰겠다.

3. 메소드 호출

const obj = {
  a: 1,

  print() {
    console.log('print');
  },
};
//메소드 호출
obj.print(); // print

 

객체 내부에 정의 되어 있는 메소드를 호출 할때는

object.method()

이렇게 사용한다.

4. this 바인딩

위 3.메소드 호출에서는 string을 출력했지만 이번에는

변수를 참조해보겠다.

 

const obj = {
  a: 1,

  print() {
    console.log(a);
  },
};
//메소드 호출
obj.print(); // ReferenceError: a is not defined

1이 출력되지 않고, 참조에러가 발생한다.

에러 내용을 보면 a 가 선언 되지 않았다고 나온다.

당연하다.

변수 a는 선언 된적이 없다.

obj 내부에 있는 a는

obj가 갖고 있는 프로퍼티의 key 일뿐이지 변수가 아니다.

 

 

const obj = {
  a: 1,

  print() {
    console.log(obj.a);
  },
};
//메소드 호출
obj.print(); // 1

 

이렇게 해줘야 obj 프로퍼티에 접근할 수 있다.

그런데,

let obj = {
  a: 1,

  check() {
    console.log(obj.a);
  },
};

const obj2 = obj;
obj = null;

obj2.check(); // TypeError: Cannot read properties of null (reading 'a')

이런 경우에는 에러가 발생한다.

 

하지만 여기서 this를 사용하면,

let obj = {
  a: 1,

  check() {
    console.log(this.a);
  },
};

const obj2 = obj;
obj = null;

obj2.check(); //1

내가 원하는 대로 1이 출력되는걸 확인할 수 있다.

 

4-1. this

그래서 this가 뭘까.

내가 공부했던 책에서는 this를

"자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(self-reference variable)이다"

라고 정의한다.

이걸 보고 아항 그렇구나 라고 하는 사람이면, 천재가 아닐까..

나도 이제는 어느 정도 이해하고 있다고 생각하는데,

저 문장을 보면 머리가 아득해진다.

왜 어떤 용어를 정의하는 문장은 항상 어려울까..

하나 하나 톺아보면 이해가 될지도.

 

일단 자기 참조 변수라는 말에 집중해보자.

영어로 self-reference variable

나는 한국말 보다 영어가 더 직관적인것같아서 용어들은 영어로 외우는 편이다.

스스로를 참조하는 변수다. 변수.

그렇다면 여기서 스스로는 어디의 누구를 지칭하는 걸까.

그부분은 문장의 앞쪽에 나와있다.

자신이 속한 객체 or 자신이 생성할 인스턴스 객체(생성자함수 또는 class를 이용하여)를 가리킨다고 되어있다.

그럼 얼추 이해가 된다.

객체 내부에서의 this 는 자신이 속한 객체를

생성자함수 또는 클래스 내부의 this는 인스턴스 객체를 가리킨다.

가리킨 다를 조금 있어보이게 표현하면 binding 이라고 한다.

있어 보이는 걸 좋아하는 사람이라 앞으론 binding 이라 표기하겠음.

 

4-2. this의 binding 대상 결정 방식

this 의 바인딩은 함수스코프와 달리 동적으로 결정된다.

즉 함수가 호출되는 방식에 따라 this가 어디에 binding 될지 결정된다.

코드로 확인을 해보자.

 

const obj = {
  check() {
    console.log(this);
  },
};

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

//class생성자 함수
class Test {
  constructor(num) {
    this.num = num;
  }

  check3() {
    console.log(this);
  }
}

//인스턴스 객체 생성
const obj2 = new Test(1);

// 메소드로 호출
obj.check(); //{check: ƒ}

//일반 함수로 호출
check2(); // Window

//인스턴스 객체의 메소드로 호출
obj2.check3(); //Test{num: 1}

console.log(obj2); // Test{num: 1}

일반 객체의 메소드로 호출 됐을 때는 호출된 메소드를 포함하고 있는 객체에 binding 되었고,

일반함수로 호출 됐을 때는 전역 객체인 window( node.js 환경에서는 global)에 binding 되었고,

class 함수 내부에 있는 this는 인스턴스 객체에 바인딩 된다.   

이처럼 함수가 호출되는 방식에 따라 this 의 binding 이 동적으로 결정된다.

4-2. 객체에서의 this 사용

아까의 예시 코드를 다시 보자

let obj = {
  a: 1,

  check() {
    console.log(this.a);
  },
};

const obj2 = obj;
obj = null;

obj2.check(); //1

내가 원했던 대로 1이 출력된다.

함수가 obj2의 메서드로 호출 되었기 때문에

this 는 obj2에 바인딩 되었다.

 

console.log를 이용해서 this 를 출력해보면 더욱 명확하게 알 수 있다.

 

let obj = {
  a: 1,

  check() {
    console.log(this.a);
    console.log(this);
  },
};

const obj2 = obj;
obj = null;

obj2.check(); 
// 1
// { a: 1, check: [Function: check] }

this를 출력하면 obj2객체가 출력되는걸 확인 할 수 있다.

 

4-3. class  함수/생성자함수 내부에서의  this 사용

this의 진가는 class 함수나 생성자 함수를 이용해 인스턴스 객체를 만들 때 발휘된다고 생각한다.

class Obj {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHi() {
    console.log(`My name is ${this.name}, and I'm ${this.age}`);
  }
}

const obj1 = new Obj('mark', 25);
const obj2 = new Obj('jhon', 23);

console.log(obj1); //Obj { name: 'mark', age: 25 }
console.log(obj2); //Obj { name: 'jhon', age: 23 }

obj1.sayHi(); //My name is mark, and I'm 25
obj2.sayHi(); //My name is jhon, and I'm 23

class 함수 내부에서 사용된 this 는

new 키워드를 통해 생성될 인스턴스 객체에 바인딩 되기 때문에,

obj1 과 obj2 가 서로다른 프로퍼티를 가진 인스턴스 객체로 만들어 질 수 있었고,

메서드 역시 의도대로 출력이 된다.

 

 

수업 도중 내가 이해했던 내용이 틀렸음을 알게됐다.

(왜 맞다 해주셨지.. 불쌍해 뵀나...)

아마 블로그에 정리를 하지 않았다면

잘못된 채로 이해하고 있었을 지도 모른다.

 

this 바인딩이 동적으로 결정된다는 말을 이해하기 전에도 

class 함수는 사용했었고, this 역시 사용을 했었다.

그런데 this 바인딩에 대해 어느정도 이해를 하고 나니

같은 코드를 봐도 느낌이 생경하다.

이전에는 그저 텍스트로 보일 뿐이었는데,

지금은 코드로 보인다고 해야되나..

무튼 기분이 좋다..

 

 

 

728x90
728x90

댓글