본문 바로가기
기술 개발/Javascript

this 가 동작하는 원리와 용법

by 쪼짱 2023. 3. 31.
728x90
반응형
SMALL

This

JavaScript에서 this는 실행 중인 함수의 컨텍스트를 참조하는데 사용되는 특수한 키워드다.

function 키워드로 생성한 일반 함수화살표 함수의 가장 큰 차이점은 this이다.


일반 함수의 this

자바스크립트의 경우, 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정된다. 즉, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 값이 달라진다는 것이다.

 

함수의 호출하는 방식

  1. 함수 호출
  2. 메소드 호출
  3. 생성자 함수 호출
  4. apply/call/bind 호출
var foo = function () {
  console.dir(this);
};

// 1. 함수 호출
foo(); // window
// window.foo();

// 2. 메소드 호출
var obj = { foo: foo };
obj.foo(); // obj

// 3. 생성자 함수 호출
var instance = new foo(); // instance

// 4. apply/call/bind 호출
var bar = { name: 'bar' };
foo.apply(bar);  // bar
foo.call(bar);   // bar
foo.bind(bar)(); // bar

 

1. 함수 호출

기본적으로 this는 전역객체(Global object)에 바인딩된다. 전역함수, 내부함수, 메소드의 내부함수, 콜백함수의 경우도 this는 전역객체에 바인딩된다.

전역객체(Global Object)는 모든 객체의 유일한 최상위 객체를 의미하며 일반적으로 Browser-side에서는 window, Server-side(Node.js)에서는 global 객체를 의미한다.

전역객체는 전역 스코프(Global Scope)를 갖는 전역변수(Global variable)를 프로퍼티로 소유한다. 글로벌 영역에 선언한 함수는 전역객체의 프로퍼티로 접근할 수 있는 전역 변수의 메소드이다.

console.log(this === window); // true

function myFunction() {
  console.log(this === window); // true
}

myFunction();

 

2. 메소드 호출

함수가 객체의 프로퍼티 값이면 메소드로서 호출된다. 이때 메소드 내부의 this는 해당 메소드를 소유한 객체, 즉 해당 메소드를 호출한 객체에 바인딩된다.

프로토타입 객체도 메소드를 가질 수 있다. 프로토타입 객체 메소드 내부에서 사용된 this도 일반 메소드 방식과 마찬가지로 해당 메소드를 호출한 객체에 바인딩된다.

const myObject = {
  name: 'sujeong',
  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
};

myObject.greet(); // "Hello, my name is sujeong"

 

3. 생성자 함수 호출

자바스크립트의 생성자 함수는 말 그대로 객체를 생성하는 역할을 한다. 하지만 자바와 같은 객체지향 언어의 생성자 함수와는 다르게 그 형식이 정해져 있는 것이 아니라 기존 함수에 new 연산자를 붙여서 호출하면 해당 함수는 생성자 함수로 동작한다.

이는 반대로 생각하면 생성자 함수가 아닌 일반 함수에 new 연산자를 붙여 호출하면 생성자 함수처럼 동작할 수 있다. 따라서 일반적으로 생성자 함수명은 첫문자를 대문자로 기술하여 혼란을 방지하려는 노력을 한다.

new 연산자와 함께 생성자 함수를 호출하면 this 바인딩이 메소드나 함수 호출 때와는 다르게 동작한다.

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

const sujeong = new Person('sujeong', 26);
console.log(sujeong.name); // "sujeong"
console.log(sujeong.age); // 26

 

4. apply/call/bind 호출

this를 명시적으로 바인딩할 수 있는 방법이 있는데, 바로 apply, call, bind 메소드를 사용하는 것이다.

이 메소드들은 모든 함수 객체의 프로토타입 객체인 Function.prototype 객체의 메소드이다.

apply()메서드는 주어진 this값과 배열 (또는 유사 배열 객체) 로 제공되는 arguments로 함수를 호출한다.

call()메소드는 주어진 this값 및 각각 전달된 인수와 함께 함수를 호출한다.

bind()메소드가 호출되면 새로운 함수를 생성한다. 받게되는 첫 인자의 value로는 this  키워드를 설정하고, 이어지는 인자들은 바인드된 함수의 인수에 제공된다.

apply, call, bind에서 첫 번째 인자로 다른 것을 넣어주는 게 this를 바꾸는 방법 중 하나다.

func.apply(thisArg, [argsArray])
func.call(thisArg[, arg1[, arg2[, ...]]])
func.bind(thisArg[, arg1[, arg2[, ...]]])
// call 예시
function myFunction() {
  console.log(`Hello, my name is ${this.name}`);
}

const myObject = { name: 'sujeong' };

myFunction.call(myObject); // "Hello, my name is sujeong"
// bind 예시
const myObject = { name: 'sujeong' };

function myFunction() {
  console.log(`Hello, my name is ${this.name}`);
}

const myBoundFunction = myFunction.bind(myObject);
myBoundFunction(); // "Hello, my name is sujeong"

화살표 함수의 this

일반 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다고 하였다.

화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다. 동적으로 결정되는 일반 함수와는 달리 화살표 함수의 this 언제나 상위 스코프의 this를 가리킨다. 이를 Lexical this라 한다.

화살표 함수는 call, apply, bind 메소드를 사용하여 this를 변경할 수 없다.

 

화살표 함수를 사용해서는 안되는 경우

화살표 함수는 Lexical this를 지원하므로 콜백 함수로 사용하기 편리하다. 하지만 화살표 함수를 사용하는 것이 오히려 혼란을 불러오는 경우도 있으므로 주의하여야 한다.

1. 메소드

화살표 함수로 메소드를 정의하는 것은 피해야 한다. 메소드를 위한 단축 표기법인 ES6의 축약 메소드 표현을 사용하는 것이 좋다.

2. prototype

화살표 함수로 정의된 메소드를 prototype에 할당하는 경우도 동일한 문제가 발생한다. 따라서 prototype에 메소드를 할당하는 경우, 일반 함수를 할당한다.

3. 생성자 함수

화살표 함수는 생성자 함수로 사용할 수 없다. 생성자 함수는 prototype 프로퍼티를 가지며 prototype 프로퍼티가 가리키는 프로토타입 객체의 constructor를 사용한다. 하지만 화살표 함수는 prototype 프로퍼티를 가지고 있지 않다.

4. addEventListener 함수의 콜백 함수

addEventListener 함수의 콜백 함수를 화살표 함수로 정의하면 this가 상위 컨택스트인 전역 객체 window를 가리킨다. 따라서 addEventListener 함수의 콜백 함수 내에서 this를 사용하는 경우, function 키워드로 정의한 일반 함수를 사용하여야 한다. 일반 함수로 정의된 addEventListener 함수의 콜백 함수 내부의 this는 이벤트 리스너에 바인딩된 요소(currentTarget)를 가리킨다.

 


출처

https://poiemaweb.com/js-this

https://poiemaweb.com/es6-arrow-function

https://www.zerocho.com/category/JavaScript/post/57433645a48729787807c3fd

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/call

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

 

 

728x90
반응형
LIST

'기술 개발 > Javascript' 카테고리의 다른 글

const - 요소나 속성을 추가할 수 있는 이유  (0) 2023.04.03
require vs import  (0) 2023.04.03
parameter와 argument의 차이  (0) 2023.03.28
정규표현식(Regex)  (0) 2023.02.08
얕은 복사 vs 깊은 복사  (1) 2023.01.12