Javascript

this? 이것?

아가프린 2024. 4. 15. 21:07

this는 영어로 이것이라는 의미입니다. JavasScript에서 사용되는 this는 어떤 의미를 뜻할까요?

 

this

this는 실행 중인 코드에서 사용되는 객체를 참조하는데 사용되는 키워드입니다.

this의 값은 함수의 호출 방식에 따라 변합니다.

 

Global

전역에서 this를 사용했을 때는 전역 객체를 가리킵니다. 브라우저상에서는 window가 전역 객체입니다.

console.log(this); // window

 

만약 아무런 것으로도 감싸지 않고 전역에서 사용됐을 때 위 로그는 window를 찍습니다.

 

전역 객체인 window가 잘 감이 안 올 수 있는데 아래 예시를 봐보겠습니다.

let globalValue = 10;
console.log(this.globalValue); // 10
console.log(window.globalValue); // 10

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

ex(); // window

 

말 그대로 전역에서 선언한 것은 모두 window나 this 자체만 사용한다면 불러올 수 있습니다.

this를 전역이 아닌 일반 함수에서 사용해도 단일로 사용한다면 window 객체를 가리킵니다.

 

단일 this는 전역 객체를 가리킨다고 했습니다. 하지만 엄격 모드 strict mode에서는 window가 아닌 undefined를 값으로 갖습니다.

"use strict";
console.log(this); // undefined

 

Local

일반 함수말고 객체에서는 어떨까요?

const obj = {
  name: "example",
  ex: function() { console.log(this); },
};

obj.ex(); // { name: "example", ex: f }

let ex2 = obj.ex;
console.log(ex2()); // window


객체의 메서드를 호출할 때 this를 내부적으로 바꾸기 때문에 단순히 함수를 호출할 때는 자신의 객체를 가리키고

만약 이 함수를 할당한다면 이젠 obj의 함수가 아니고 일반 함수로 취급되기 때문에 window 전역 객체를 가리킵니다.

 

 

객체에 함수가 프로퍼티로 있다면 메서드로 호출됩니다. 이때 이 메서드를 호출할 때 this는 메서드를 소유한 객체에 바인딩 됩니다.

const obj = {
  name: 'woonrin',
  printName: function() {
    console.log(this.name);
  },
};

const obj2 = {
  name: 'Mike',
};

obj2.printName = obj.printName;

obj.printName(); // woonrin
obj2.printName(); // woonrin

 

이처럼 this는 호출 방법에 따라 값이 바뀌기 때문에 호출하는 함수가 객체의 메서드인지 그저 일반 함수인지를 잘 살펴봐야 합니다.

 

객체에서 그저 메서드의 내부함수에서 this를 사용하면 자신을 감싸는 객체가 아니라 전역 객체를 가리키게 됩니다.

const value = 1;

const obj = {
  value: 100,
  foo: function() {
    console.log("foo's this: ",  this);  // obj
    console.log("foo's this.value: ",  this.value); // 100
    function bar() {
      console.log("bar's this: ",  this); // window
      console.log("bar's this.value: ", this.value); // 1
    }
    bar();
  }
};

obj.foo();

위 코드에서 내부함수는 bar입니다. 그저 메서드에서 this를 호출하면 자신을 감싸고 있는 객체를 가리킵니다.

만약 내부 함수에서도 this를 전역 객체를 가리키지 않도록 하려면 어떻게 해야될까요?

 

크게 3가지 방법이 있습니다.

 

Closure

익숙한 단어죠? 내부함수에서 외부함수의 스코프에 접근할 수 있는 것을 의미합니다. 위 코드에서 bar는 내부함수이기 때문에

foo 함수 스코프에 접근할 수 있습니다. foo에서 this는 obj를 가리키기 때문에 변수로 할당할 수 있습니다.

const value = 1;

const obj = {
  value: 100,
  foo: function() {
    var that = this; // obj
	
    console.log(this);  // obj
    console.log(this.value); // 100
    function bar() {
      console.log(that); // obj
      console.log(that.value); // 100
    }
    bar();
  }
};

obj.foo();

 

또는 화살표 함수로 bar를 정의하면 this는 자신을 감싸는 가장 가까운 일반 함수의 this 값을 가집니다.

그래서 bar를 화살표 함수로 정의하는 것도 하나의 방법입니다.

 

apply, call, bind

apply와 call을 아시나요? js에서 함수를 호출할 때 사용하는 메서드입니다.

두 메서드 모두 첫 번째 인자로 this, null, 객체 등을 받을 수 있습니다. 만약 apply와 call을 실행한 함수에서

this를 사용한다면 어떤 일이 벌어질까요?

const ex = 'Global';
const obj = { ex: 'Local' };

function whatsThis() {
  console.log(this.ex);
}

whatsThis(); // Global
whatsThis.call(obj); // Local
whatsThis.apply(obj); // Local

 

만약 일반적인 상황에서 this.ex는 전역에 있는 ex를 가리킵니다. 하지만 apply나 call을 사용했을 때는

전달한 객체에 this가 묶이게 되기 때문에 2, 3번째 실행문은 Local을 출력하게 됩니다.

 

상황에 따라 다르게 변하니 사용한다면 조심해서 사용해야 될 것 같습니다.

 

apply와 call 말고 ES5에서 bind도 도입 됐습니다. 함수.bind(obj)를 호출하면 함수와 같은 범위를 가지게 되지만

this는 원본 함수를 가진 새로운 함수를 만들어냅니다. 그래서 함수.bind(obj)를 할당한 새로운 함수는 다시 bind 하게 되면
bind를 호출한 함수와 같은 값을 가지게 됩니다.

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

const firstBind = ex.bind({ a: 'first' });
firstBind(); // first

const secondBind = firstBind.bind({ a: 'second' });
secondBind(); // first

const obj = { a: 'third', ex: ex, firstBind: firstBind, secondBind: secondBind };

console.log(obj.a); // third
console.log(obj.ex()); // third
console.log(firstBind()); // first
console.log(secondBind()); // first

 

📚 정리

this는 기본적으로 window입니다.

특히, 내부함수 어디에서든 단일 this를 사용하면 그 this는 window를 가리키게 됩니다.

하지만 함수를 어떻게 호출하냐에 따라 this의 값이 바뀔 수 있습니다.

apply, call, bind 등으로 this 값을 변경 시킬 수 있습니다.

 

코드 실행중에 사용되는 객체를 참조한다고 했으니 당연히 런타임에 this 값이 결정됩니다.

일반 함수는 어떻게 호출되냐에 따라 this의 값이변하고 화살표 함수는 자신을 감싸는 가장 가까운 스코프의

this와 같은 값을 가집니다.