WeniVooks

검색

JavaScript 에센셜

this

1. this 키워드 이해하기

JavaScript에서 this 키워드는 매우 중요하지만, 처음에는 이해하기 어려울 수 있습니다. this는 함수가 어떻게 호출되었는지에 따라 다르게 동작하기 때문입니다. this를 한 마디로 정의하면 '함수가 호출되는 방식에 따라 달라지는 특수한 키워드' 라고 할 수 있습니다.

다양한 상황을 통해 this가 가리키는 값을 살펴보겠습니다.

this를 알아보기 전에!
위니북스에서는 this가 전역 객체를 가리키지 않습니다. 따라서 호출 방식에 따른 this 값을 확인하기 위해서는 브라우저 콘솔을 사용하여야 합니다.

1.1. 전역 범위 호출

전역 범위, 보통 전역 컨텍스트라고 얘기합니다. 전역 컨텍스트에서 this는 전역 객체를 가리킵니다. 브라우저에서는 window 객체가 전역 객체입니다.

console.log(this); // 브라우저에서는 window 객체
console.log(this); // 브라우저에서는 window 객체

전역 객체
다음 코드는 실행 환경에 따라 결과가 다릅니다. 브라우저에서는 window 객체가 전역 객체이며 Node.js 환경에서는 global 객체가 전역 객체입니다.

console.log(this); // 브라우저에서는 window 객체
console.log(this); // 브라우저에서는 window 객체
1.2. 함수 범위 호출

함수 내부에서 this의 값은 함수를 호출한 방식에 따라 결정됩니다.

1.2.1. 일반 함수 호출

일반 함수 호출에서 this는 전역 객체를 나타냅니다.

function func1() {
  console.log(this);
}
 
func1(); // window 객체 (브라우저에서)
function func1() {
  console.log(this);
}
 
func1(); // window 객체 (브라우저에서)
1.2.2. 메서드 호출

객체의 메서드로 호출된 함수에서 this는 메서드를 호출한 객체를 나타냅니다. 다음 코드에서 this는 메서드를 호출한 obj를 가리킵니다.

const obj = {
  func: function () {
    console.log(this);
  },
};
 
obj.func(); // obj
const obj = {
  func: function () {
    console.log(this);
  },
};
 
obj.func(); // obj

메서드 내부의 함수는 일반 함수로 취급됩니다. 따라서 메서드 내부의 함수에서 this는 전역 객체를 가리킵니다.

const person = {
  name: 'licat',
  age: 25,
  a() {
    console.log(this);
    console.log(this.name);
    function b() {
      console.log(this);
      console.log(this.name);
    }
    b();
  },
};
person.a();
const person = {
  name: 'licat',
  age: 25,
  a() {
    console.log(this);
    console.log(this.name);
    function b() {
      console.log(this);
      console.log(this.name);
    }
    b();
  },
};
person.a();
1.2.3. 화살표 함수 호출

화살표 함수에서 this는 함수가 정의된 위치의 컨텍스트를 유지합니다. 이를 lexical this라고 합니다.

const obj = {
  func1: function () {
    const func2 = () => {
      console.log(this);
    };
    func2();
 
    const func3 = function () {
      console.log(this);
    };
    func3();
  },
};
 
obj.func1();
// Object(obj) (화살표 함수 func2에서의 this)
// Window 객체 (일반 함수 func3에서의 this)
const obj = {
  func1: function () {
    const func2 = () => {
      console.log(this);
    };
    func2();
 
    const func3 = function () {
      console.log(this);
    };
    func3();
  },
};
 
obj.func1();
// Object(obj) (화살표 함수 func2에서의 this)
// Window 객체 (일반 함수 func3에서의 this)

위 코드에서 func2의 this는 lexical this로 obj를 가리킵니다. 반면 func3의 this는 일반 함수 호출로 window 객체를 가리킵니다.

1.2.4. 생성자 함수 호출

new 키워드를 사용하여 생성자 함수를 호출하면, this는 새로 생성된 객체를 나타냅니다. 즉, 생성자 함수로 만들어진 객체인 인스턴스를 가리킵니다.

function Person(name) {
  this.name = name;
  console.log(this);
}
 
const person1 = new Person('licat'); // Person { name: "licat" }
function Person(name) {
  this.name = name;
  console.log(this);
}
 
const person1 = new Person('licat'); // Person { name: "licat" }
1.3. 이벤트 핸들러 내에서 호출

이벤트 핸들러는 사용자나 브라우저의 특정 동작(이벤트)에 반응하여 실행되는 함수입니다. '핸들러 함수' 라고 불립니다. 자주 등장하는 용어이니 용어를 알아두시기 바랍니다.

웹 페이지에서 자주 사용되는 이벤트에는 클릭, 키보드 입력, 마우스 이동 등이 있습니다. 이벤트 핸들러는 주로 addEventListener 메서드를 사용하여 특정 요소에 할당됩니다.

이벤트 핸들러 내에서 this는 이벤트가 발생한 DOM 요소를 가리킵니다. 아래 예제는 직접 html 파일에 작성해보세요.

<button id="btn">Click me!</button>
 
<script>
  const button = document.getElementById('btn');
  button.addEventListener('click', function () {
    console.log(this); // <button id="btn">Click me!</button>
  });
</script>
<button id="btn">Click me!</button>
 
<script>
  const button = document.getElementById('btn');
  button.addEventListener('click', function () {
    console.log(this); // <button id="btn">Click me!</button>
  });
</script>

실무에서는 이벤트 핸들러에서 this를 많이 사용합니다. 이벤트 핸들러에서 this는 이벤트가 발생한 요소를 가리킵니다. 다음은 체크박스를 클릭할 때마다 배경색이 바뀌는 예제입니다. html 파일을 생성하여 아래 예제를 실행해보세요.

<label for="checkbox">
  <input type="checkbox" id="checkbox" />
  체크해보세요.
</label>
 
<script>
  const checkbox = document.getElementById('checkbox');
  checkbox.addEventListener('change', function () {
    if (this.checked) {
      document.body.style.backgroundColor = 'lightblue';
    } else {
      document.body.style.backgroundColor = '';
    }
  });
</script>
<label for="checkbox">
  <input type="checkbox" id="checkbox" />
  체크해보세요.
</label>
 
<script>
  const checkbox = document.getElementById('checkbox');
  checkbox.addEventListener('change', function () {
    if (this.checked) {
      document.body.style.backgroundColor = 'lightblue';
    } else {
      document.body.style.backgroundColor = '';
    }
  });
</script>

2. this 조작하기

이처럼 this는 함수가 호출되는 방식에 따라 달라지는 특수한 키워드입니다. 때로는 this에 값을 지정해야 할 때가 있습니다. 함수에 call(), apply(), bind() 메서드를 이용하여 this를 조작할 수 있습니다. 이를 통해 사용자가 의도하는 값을 this에 바인딩할 수 있게 합니다.

2.1. call()

call() 메서드의 첫 번째 인수로 this로 사용할 값을 사용하여 함수를 호출합니다.

function.call(thisArg, arg1, arg2, ...)
function.call(thisArg, arg1, arg2, ...)
const peter = { name: 'Peter Parker', sayName: function () { console.log(this.name); }, }; const bruce = { name: 'Bruce Wayne', }; peter.sayName.call(bruce); // peter.sayName.call(bruce) 의 결과는 무엇이 될지 생각해 봅시다.

call의 첫번째 인자로 전달된 bruce 객체가 함수 내부의 this로 사용되어 bruce.name을 출력합니다.

2.2. apply()

apply() 메서드는 call()과 유사하지만, 인수를 배열의 형태로 전달합니다. 실행할 메서드에 파라미터가 있다면 배열의 형태로 인자 값을 전달하여 사용합니다.

function.apply(thisArg, [argsArray])
function.apply(thisArg, [argsArray])
const peter = { name: 'Peter Parker', sayName: function (is, is2) { console.log(`${this.name} is ${is} or ${is2}`); }, }; const bruce = { name: 'Bruce Wayne', }; peter.sayName.apply(bruce, ['batman', 'richman']);
2.3. bind()

bind()는 새로운 함수를 생성하며, this를 고정시킵니다. bind() 메서드는 함수를 호출하지 않고 this가 고정된 새로운 함수를 반환합니다.

function.bind(thisArg, arg1, arg2, ...)
 
function.bind(thisArg, arg1, arg2, ...)
 
function sayName() { console.log(this.name); } const bruce = { name: 'bruce', sayName: sayName, }; const peter = { name: 'peter', }; bruce.sayName(); // bruce const sayMyName = sayName.bind(peter);
8장 조금 더 깊이 들여다보기8.2 Map과 Set