혼자 적어보는 노트

[Javascript] this란 무엇인가? 본문

Javascript

[Javascript] this란 무엇인가?

jinist 2021. 12. 23. 04:26

this란 무엇인가?


자바스크립트를 배우게되면서 this에 대해 많이 접해보았는데
내가 알고있는 개념이 맞는지, 책이나 유튜브 등 여러가지로 알아보게 되었는데
초심자인 내가 이해한 방식으로 적어보겠다.

 

this를 제대로 이해하려면 실행컨텍스트, 스코프, 객체라는개념, 프로퍼티, 프로토타입, 활용된 사례 등
밀접하게 연결되어 있는 부분을 이해해야 하는 듯 하다.

개인적으로 this자체가 어렵다기 보다는 연결된 다른 개념들을 이해해야해서 복잡했던 것 같다.

ES6문법부터 시작해서 그런지 이전의 개념들이 와닿지 않았던 것들도 있었다


자바스크립트에서의 this는 실행컨텍스트가 생성될 때 결정되는 것이다.
즉 함수를 호출할 때 결정이 되며. 호출자가 누구냐에 따라 달라진다.

 

전역공간에서의 this

console.log(this);
// Window

전역공간에서 호출한 this는 전역 객체를 가르킨다.


함수에서 호출 할 때의 this

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

func();
//window

함수에서 호출하는 this는 전역 객체를 가르킨다.

 

함수를 객체의 메서드로써 호출 할 때의 this

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

func(); // window {...}

const obj = {
  hello: func,
};

obj.hello(); // {hello: ƒ}

함수명.프로퍼티 의 구조인 메서드로써 호출된 함수의 this는 해당 객체를 가르킨다.

 

func()를 단독으로 실행할 경우 this는 전역객체를 가르키며
obj.hello()로 객체의 메서드로서 호출 시에는 해당 객체인 obj를 가르킨다.

그럼 함수를 객체안의 객체에서 실행하면 어떻게 될까?

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

const obj = {
  hello: {
    hi: func,
  },
};

obj.hello.hi(); // {hi: ƒ}

hi를 호출한 hello가 this가 되는 것이다.
즉 호출한 프로퍼티의 앞의 객체가 this인 셈이다.


객체의 프로퍼티 내부의 함수 실행 시 this

const obj = {
  first: function () {
    console.log(this); // {first: ƒ}
    const second = function () {
      console.log(this); // Window{...}
    };
    second();
  },
};

obj.first();

위의 코드에는 first를 obj의 메서드로서 실행하여 first에서의 this는 obj으로 나오지만
first안의 내부함수인 second의 this는 window로 출력된다.

이것만 봐도 확실해진다. this는 함수를 호출할 때 결정된다고 했다.
하지만 함수를 그냥 호출하면 this값이 없기 때문에
this는 최상위 스코프인 전역객체를 바라본다.

 

위의 코드와 같이 짧은 코드의 경우 this값을 유추할 수 있겠지만 복잡한 코드에서는
this의 값이 무엇인지 유추하기 힘들 것이다. 함수를 그냥 호출하고있는지,
메서드로서 호출하고있는지 헷갈릴 수 있다.

 

 

화살표 함수의 도입

화살표 함수는 실행컨텍스트에서 this를 바인딩 하지 않아서 this값이 없기때문에
화살표 함수는 this 호출 시 스코프 체인상 가까운 this를 바라보게 된다.

화살표 함수 사용 시 객체의 프로퍼티 내부의 함수의 this는 상위의 this를 가르킨다.

주변환경이 어떠하든 this는 함수가 호출될 때 정해진다고 했다.

하지만 화살표 함수를 이용한다면 주변 환경의 this를 상속 시켜준다.

 

const obj = {
  first: function () {
    console.log(this); // {first: ƒ}
    const second = () => {
      console.log(this); // {first: ƒ}
    };
    second();
  },
};

obj.first();

ES6의 화살표 함수 도입으로 객체 내부에서의 this를 유추하기 쉬워졌다.
물론 ES5에도 this가 바라보는 객체를 우회하거나(that,self 변수)

직접 명시하는 방법(call, apply, bind)이 있긴 하다.

일단 화살표 함수를 사용하면 호출했을 당시의 this값이 아닌 주변 환경의 영향을 받게 된다.

위 코드에서 first를 익명 화살표 함수로 변경한다면?

first의 상위객체는 obj이며 obj의 this는 전역객체이기 때문에
first와 second의 console.log 모두 window로 출력된다.

 

 

ES5환경에서 내부 함수의 this를 사용하는 방법.

var obj = {
  first: function () {
    console.log(this); // {first: ƒ}
    var _this = this;
    var second = function () {
      console.log(_this); // {first: ƒ}
    };
    second();
  },
};

obj.first();

단순한 방법으로 first함수 내부에서 _this라는 변수에 this를 할당하여
second에서 사용할 수 있다. (_this, that, self 등으로 변수에 할당)

실제로 이런 코드를 본적이 있다.

 

 

별도의 대상에 this를 바인딩 하는 방법

 

- call 메서드 사용

첫번째 인자를 this로 바인딩 하고 이후의 인자들을 함수의 매개변수로 사용한다.
매개변수가 없다면 생략 가능

 

const obj = {
  name: "Jay",
  func: function (a, b, c) {
    console.log(this.name, a, b, c);
  },
};
const user2 = {
  name: "Mate",
};

obj.func(160, 40); // Jay 160 40
obj.func.call(user2, 170, 60); //Mate 170 60

call메서드로 this가 바라보는 객체를 명시적으로 지정할 수 있다.

매개변수 없이도 사용 할 수 있다.

 

const user1 = {
  name: "Jay",
};
const user2 = {
  name: "Mate",
};

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

showName.call(user1);
showName.call(user2);

 

- apply 메서드 사용

call메서드와 기능적으로는 동일하나 매개변수를 배열로 받는 것이다.

const obj = {
  name: "Jay",
  func: function (height, weight) {
    console.log(this.name, height, weight);
  },
};
const user = {
  name: "Mate",
};

obj.func(160, 40); // Jay 160 40
obj.func.apply(user, [170, 60]); //Mate 170 60

 

- bind 메서드 사용

call과 apply와 마찬가지로 첫번째 인자를 지정할 this로 받지만
새로운 함수로 반환된다. 첫번 째 인자 뒤의 인자들은 함수의 인수로 전달된다.
해당 this를 미리 지정해놓고 함수를 사용할 수 있다.

 

const jay = {
  name: "Jay",
  age: 28,
};
const mate = {
  name: "Mate",
  age: 20,
};

function showInfo(height, weight) {
  console.log(this.name, height, weight);
}

const onlyJay = showInfo.bind(jay);

onlyJay(160, 40); //Jay 160 40

 

 

생성자 함수에서의 this사용

function User(name, age) {
  this.name = name;
  this.age = age;
}

const jay = new User("Jay", 28);
const mate = new User("Mate", 25);

console.log(jay); //User {name: 'Jay', age: 28}
console.log(mate); //User {name: 'Mate', age: 25}

new와 함께 생성자 함수를 호출하면
만들어놓은 User의 속성을 각각의 jay, mate에 부여하여 새로운 객체를 만들어낸다.

보통 class에서 많이 사용하는 것을 볼 수 있다.

 

 

 

참고 블로그 : https://blueshw.github.io/2018/03/12/this/ 

참고도서 : 코어자바스크립트

Comments