[JS] 자바스크립트에서 this는 어떻게 작동할까?

undefined_potter·2022년 2월 1일
0
post-thumbnail

자바스크립트에서 this는 어떻게 작동할까

누가 나를 불렀느냐! 를 뜻한다.

선언이 아닌, 호출에 따라 달라진다는 뜻!
자바스크립트에서 this는 호출하는 방식에 따라 달라진다.

정리해보자면,

  • this를 호출할때 new 키워드를 사용하는 경우, 함수 내부에 있는 this는 완전히 새로운 객체이다.

  • apply, call, bind 가 함수의 호출, 생성에 사용되는 경우 함수 내부의 this는 인수로 전달된 객체이다.

  • obj.method() 와 같이 함수를 메서드로 호출하는 경우, this는 함수가 프로퍼티인 객체이다.

  • 함수가 자유함수로 호출되는 경우, (위의 조건 없이 호출되는 경우) this 는 전역객체 이다.

  • 위의 규칙 중 다수가 적용되면 더 상위 규칙이 승리하고 this값을 설정한다.

  • 함수가 es5 화살표 함수인 경우, 위 모든 규칙을 무시하고 생성된 시점에서 주변 스코프의 this 값을 받는다.

1. 단독으로 쓴 this

브라우저에서 호출하는 경우 Window 이다.
use strict mode에서도 마찬가지!

2. 함수내부의 this

위 코드에서 this.num의 this는 window객체를 가리킨다.
따라서 전역변수 num을 가리키는 것이다.

그러나 엄격모드에서는 다르다!
undefined을 출력하는 이유는 함수 내의 디폴트 바인딩이 없기 때문이다.

this.num을 호출하면 undefined.num을 호출한것과 마찬가지이기 때문에 에러가 난다.

3.메서드 안에서의 this

그럼 일반함수가 아닌 메서드라면 어떨까?
메서드 호출시 메서드 내부코드에서 사용된 this는 해당 메서드를 호출한 객체로 바인딩된다.

var person = {
  firstName: 'John',
  lastName: 'Doe',
  fullName: function () {
    return this.firstName + ' ' + this.lastName;
  },
};
 
person.fullName(); //"John Doe"
var num = 0;
 
function showNum() {
  console.log(this.num);
}
 
showNum(); //0
 
var obj = {
  num: 200,
  func: showNum,
};
 
obj.func(); //200

4.이벤트핸들러 안에서의 this

이벤트 핸들러에서 this는 이벤트를 받는 HTML 요소를 가리킨다.

var btn = document.querySelector('#btn')
btn.addEventListener('click', function () {
  console.log(this); //#btn
});

5.생성자안에서의 this

생성자 함수가 생성하는 객체로 this가 바인딩된다.

function Person(name) {
  this.name = name;
}
 
var kim = new Person('kim');
var lee = new Person('lee');
 
console.log(kim.name); //kim
console.log(lee.name); //lee

하지만 new 키워드를 빼먹는 순간 일반함수 호출과 같아지기 때문에, 이 경우는 this가 window에 바인딩된다.

var name = 'window';
function Person(name) {
  this.name = name;
}
 
var kim = Person('kim');
 
console.log(window.name); //kim

6.명시적 바인딩을 한 this

function whoisThis() {
  console.log(this);
}
 
whoisThis(); //window
 
var obj = {
  x: 123,
};
 
whoisThis.call(obj); //{x:123}

apply는 두번째 인자로 배열을 받는다.

function Character(name, level) {
  this.name = name;
  this.level = level;
}
 
function Player(name, level, job) {
  Character.apply(this, [name, level]);
  this.job = job;
}
 
var me = new Player('Nana', 10, 'Magician');

call로 바꿔쓴다면

function Character(name, level) {
  this.name = name;
  this.level = level;
}
 
function Player(name, level, job) {
  Character.call(this, name, level);
  this.job = job;
}
 
var me = {};
Player.call(me, 'nana', 10, 'Magician');

7.화살표함수로 쓴 this

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

function Prefixer(prefix) {
	this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function(arr) {
  	// this는 상위 스코프인 prefixArray 메서드 내의 this를 가리킨다.
	return arr.map(x => `${this.prefix} - ${x}`);
};

const pre = new Prefixer('Hi');
console.log(pre.prefixArray['Lee', 'Kim']);	// ['Hi - Lee', 'Hi - Kim']
  • 화살표 함수는 call, apply, bind 메서드를 사용하여 this를 변경 할 수 없다.

window.x = 1;
const normal = function () { return this.x; };
const arrow = () => this.x;

console.log(normal.call({ x: 10 })); // 10
console.log(arrow.call({ x: 10 }));  // 1

0개의 댓글