JS this (Feat. new 생성자)

조 은길·2022년 1월 7일
0

Javascript 정리

목록 보기
20/48
post-thumbnail

이번 시간에는 면접 단골 질문 중에 하나인 this에 대해서 알아보자!!

this를 출력해보자


console.log(this); // window 

function 함수() {
  console.log(this); // window 
}

자바스크립트 strict mode

"use strict";

console.log(this); // window 

function 함수() {
  console.log(this); // undefined
}

=> 크게 중요하지는 않지만, 그냥 알아만 두자!

window 객체

window는 JS의 기본 함수들이다.

좀 더 정확하게 말하자면,
window는 모든 전역변수, 함수, DOM을 보관하고 관리하는 전역객체이다.

  • 전역변수??
    코드 내 모든 곳에서 참조해서 쓸 수 있는 범용적인, 범위가 넓은 변수입니다. 그냥 script태그 내에 쌩으로 var 변수 하나 만들면 그건 자연스레 전역변수가 됩니다.


this의 필요성

let kim = {
  name: "kim",
  first: 10,
  second: 20,
  sum: function () {
    // kim.first로 해도 돌아가지만, 객체 이름은 k로 바꾸면 코드는 동작하지 않는다.
    // return kim.first + kim.second;

    // 그리고 논리적으로 생각해봐도 
    // 상위 함수가 어떤 이름을 갖고 있을지 알아내는 것은 모든 상황에서 가능한 일은 아니다.
    return this.first + this.second;
    // this는 자신이 속해있는 객체를 가리킨다.
  },
};


console.log(kim.sum()); // 30

kim이라는 객체에서 first와 second 값을 더해주는 sum 메소드를 만들어준다면, 어떤 식으로 반환 값을 작성해야 할까??

가장 직관적인 방법은 위의 코드처럼 하는 방법이다.

그러나, kim이라는 객체 이름이 cho로 바뀐다면, 해당 return 값은 작동하지 않는다.
또한, 논리적으로 생각해봐도 상위 함수가 어떤 이름을 갖고 있을지 알아내는 것은 모든 상황에서 가능한 일은 아니다.

  • sum()return 코드의 문제점
    • 객체의 이름이 바뀔 때마다, 코드를 변경해줘야 한다.
    • 상위 함수가 어떤 이름을 갖고 있을지 알아내는 것은 모든 상황에서 가능한 일은 아니다.

이러한, 번거로움을 해결하기 위해서 나온 문법이 this이다.

let kim = {
  name: "kim",
  first: 10,
  second: 20,
  sum: function () {
    return this.first + this.second;
    // this는 자신이 속해있는 객체를 가리킨다.
  },
};

console.log(kim.sum()); // 30

this는 자신이 속해있는 객체를 가리킨다. 이렇게 바꿔주면, kim의 이름이 어떻게 바뀌어도 sum()은 코드 변경 없이 잘 작동한다.

this 덕분에 그 객체가 내부적으로 가지고 있는 상태를 함수에서 참조할 수있게 됐다.

  • 지금부터 특정 상황에서 this는 어떤 어떤 의미를 가리키는지 세분화해서 알아보자!!

함수와 this

this는 함수 내에서 함수 호출 맥락(context)를 의미한다. 맥락이라는 것은 상황에 따라서 달라진다는 의미인데 즉 함수를 어떻게 호출하느냐에 따라서 this가 가리키는 대상이 달라진다는 뜻이다. 함수와 객체의 관계가 느슨한 자바스크립트에서 this는 이 둘을 연결시켜주는 실질적인 연결점의 역할을 한다.

function func() {
  if (globalThis === this) {
    // console.log(this);
    return globalThis === this;
  }
}

console.log(func()); // true

여기서 func라는 함수는 globalThis라는 전역 객체의 메소드라고 볼 수있다.
그래서, 우리는 이런 결론을 내릴 수있다.
객체의 소속인 메소드의 this는 그 객체를 가르킨다.


메소드와 this

이번에는 메소드를 호출했을 때, This 값을 살펴보자.

메소드 : 객체의 속성 값으로 담긴 함수를 특별하게 부르는 말

이 객체를 담고 있는 변수 test와 이 메소드 안에 담겨 있는 this의 값이 같은지 확인해보자.

let test = {
  func: function () {
    if (test === this) {
      // return console.log(this);
      return test === this;
    }
  },
};

console.log(test.func()); // true

객체의 소속인 메소드의 this는 그 객체를 가르킨다.


생성자와 this

아직 JS 생성자에 대해서 익숙하지 않다면, JS 생성자와 new 키워드편을 먼저 보고 오시길 바랍니다.

// ex 1 => Func()를 함수로 활용할 때,

function Func() {
  // let이나 var로 할당 되지 않았기 때문에
  // funcThis는 전역변수이다.
  funcThis = this;
}
let o1 = Func();

if (funcThis === globalThis) {
  console.log("funcThis는 전역변수이다."); // 콘솔 값이 출력 됨!!
}
// 현재까지 funcThis는 전역 변수이다.

// ex 2 => Func()를 생성자로 활용할 때,
let o2 = new Func();

if (funcThis === o2) {
  console.log("o2 와 funcThis는 같다"); // 콘솔 값이 출력 됨!!
}

위의 예제 코드를 통해, 우리가 알 수 있는 사실은

Func()가 생성자로써 사용되면,

// function Func() {
//   funcThis = this;
//   return funcThis;
// }

Func() 내부의 this 값은 생성될 객체를 가리킨다.
하지만, Func() 를 함수로 호출하면, 이 함수 안에서 this의 값은 window를 가리킨다.
즉, 생성자 안의 this는 그 생성자가 만든 객체를 가리킨다.


객체로서 함수

전통적으로 메소드는 해당 객체에 종속되있다.
그러나, 함수의 메소드인 apply, call을 이용하면 this의 값을 제어할 수 있다.
다시 말해, 메소드가 아닌 외부함수를 메소드처럼 사용할 수있게 된다. 즉, 함수의 재사용성이 높아진다.

let o = {}
let p = {}
function func(){
    switch(this){
        case o:
            console.log('o');
            break;
        case p:
            console.log('p');
            break;
        case globalThis:
            console.log('window');
            break;          
    }
}
func(); // window
func.apply(o); // o
func.apply(p); // p


객체 내의 함수 선언법

객체 안에 있는 함수를 "메소드"라고 한다.
그리고 신문법이 등장하면서 이 메소드를 넣을 수 있는 방법이 좀 더 간단해졌는데, 이 부분에 대해서 알아보자!

// 전통적인 방법
let obj = {
  함수 : function(){
    console.log("it works");
  }
}

obj.함수(); // 'it works'


// 신문법
//  중간에 function 생략 가능
let newObj = {
  함수(){
    console.log("it works");
  }
}

newObj.함수(); // 'it works'

새로운 방법은 이렇게 중간에 function을 생략할 수있다.


이해도 테스트

밑의 예제의 this는 무슨 값이 출력될까요?


var 오브젝트2 = {
  data : {
    간지함수 : function(){ console.log(this) }
  }
}
오브젝트2.data.간지함수();
  • 정답
    간지함수()를 담고있는 주인님인 오브젝트2.data
    => 별거없고 오브젝트의 메소드안에서 썼을 때 this는 메소드를 담고있는 주인님을 뜻하기 때문에

코드(1) 코드(2) 둘다 자바스크립트 입장에서 보면 똑같다

<script>

  (1)
  function 간지나는함수(){
    console.log(this)
  }

  (2)
  window.간지나는함수 = function(){ console.log() };
  
</script>

(2)문법은 window라는 오브젝트에 함수 자료를 추가하는 문법일 뿐입니다. 어려운거 없습니다.

아무튼 결론은 전역함수 만들거나 전역변수 만드시면 저렇게 window {오브젝트} 안에 담긴다는 소리입니다.

우리가 일부러 하지 않아도 변수나 함수 쌩으로 만들면 자바스크립트가 자동으로 알아서 window안에 담습니다.

그럼 이제 function 문법의 동작원리 하나를 알았으니 다시 한번 this를 여기서 출력해봅시다.

<script>

  function 간지나는함수(){
    console.log(this)
  }
</script>

여기서 this는 무슨 값이 나올까요?

this는 아까 2번에 의하면 내 메소드를 포함하고 있는 주인님 오브젝트를 출력시켜준댔죠?

간지나는함수()를 포함하고 있는 주인님 오브젝트가 무엇입니까?

=> window

  • 콜백 함수도 근본 없는 일반 함수이다.

  • 화살표 함수의 경우는 좀 다르다


자료출처 및 참고 자료

오늘 TIL은 코드스테이츠에서 학습한 내용과 아래의 출처에서 학습한 내용을 바탕으로 작성됐다.

profile
좋은 길로만 가는 "조은길"입니다😁

0개의 댓글