[JS] 상황에 따라 달라지는 this

Jay ·2022년 3월 25일
0
post-custom-banner

this는 자바스크립트에서 가장 혼란스러운 개념으로 꼽힌다.
다른 대부분의 객체지향 언어에서 this는 클래스로 생성한 인스턴스 객체를 의미한다.
하지만 자바스크립트에서의 this는 어디서든 사용가능하다.

그렇다면 this의 의의는 무엇에 있을까?

함수와 객체(메서드)의 구분이 느슨한 자바스크립트에서 this는 실질적으로 이 둘을 구분하는 거의 유일한 기능이다.

01 상황에 따라 달라지는 this

this는 기본적으로 실행 컨텍스트가 생성될 때 함께 결정된다.
-> 함수를 호출할 때 결정된다

01-1 전역 공간에서의 this

  • 전역 공간에서의 this는 전역 객체를 가르킨다.
console.log(this); -> // { alert: f(), atob: f(), ~}
console.log(window); -> // { alert: f(), atob: f(), ~}
console.log(this === window); -> // true
  • 전역 변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로도 할당.
var a = 1;
console.log(a); // 1, window. 이 생략되었다고 해석(스코프체인에서 가장 마지막에 도달하는 L.E 즉 전역객체에 프로퍼티 a 발견 및 반환.
console.log(window.a); // 1
console.log(this.a); // 1

Q1. window.a와 this.a가 1인 이유??
-> a가 전역변수로 선언되었기 때문에 전역객체의 프로퍼티로 할당되었다.
-> console.log(a)가 1인 이유? 'window.' 가 생략되어있음.

Q2. 그렇다면 var 변수로 선언하는 대신 window의 프로퍼티에 직접할당해도 var선언과 똑같을까?

var b= 2;
delete b; // false
console.log(b, window.b, this.b) // 2 2 2 -> 삭제가 안됨

window.c = 2;
delete c; // true
console.log(c, window.c, this.c) // Uncaught ReferenceError: c is not defined

-> 대부분의 경우 Yes, but 'delete' 할 경우 NO
-> 전역객체의 프로퍼티로 할당하면 삭제가 가능하고, 전역변수로 선언하면 삭제가 되지 않는다.
-> 사용자가 의도치 않게 삭제하는 것을 방지하는 방어 전략
-> 전역변수를 선언하면 자바스크립트엔진이 이를 자동으로 전역객체의 프로퍼티로 할당하면서 추가적으로 해당 프로퍼티의 configurable 속성을 false로 정의.
-> 결론적으로 var로 선언한 전역변수와 전역객체의 프로퍼티는 호이스팅 여부 및 configurable 여부에서 차이를 보인다.

01-2 메서드로서 호출할때 그 메서드 내부에서의 this

함수 vs 메서드

어떤 함수를 객체의 프로퍼티에 할당한다고 해서 그 자체로서 무조건 메서드가 되는 것이 아니라, 객체의 메서드로서 호출할 경우만 메서드로 동작하고, 그렇지 않으면 함수로 동작한다.

var func = function (x) {
	console.log(this, x);
};
func(1); // Window { ... } 1

var obj = {
	method: func
 };
 obj.method(2); // { method: f } 2

-> . 혹은 []로 호출 했을때만 메소드로 호출된다. 그렇지 않은 경우 모두 함수로 호출한 것.

메서드 내부에서의 this

메서드로 호출하면 호출 주체는 함수명 앞의 객체.
즉 점 표기법의 경우 마지막 점 앞에 명시된 객체가 곧 this다.

01-3 함수로서 호출할 때 그 함수 내부에서의 this

함수로 this를 호출한다면 this가 지정되지 않는다. 메소드 체이닝에 따라서 전역 객체를 가리킨다.
더글라스 크락포드에 따르면 이는 명백한 설계상의 오류.

var Obj = {
  Outer: function () {
  
    var innerFunc1 = function () {
        console.log(self); // Window { ... }
    };
    innerFunc2();
  
  
  	var self = this;
    var innerFunc2 = function () {
        console.log(self); // { outer: f}
    };
    innerFunc2();
  }
}  

Q. 그렇다면 함수로 호출되더라도 자동으로 전역객체를 호출하지않고 호출 당시 주변 환경의 this를 상속받아 사용할 순 없을까?
->

함수 내부에서의 this

1) 바인딩 : 상위 스코프의 this를 self에 저장.
2) 화살표 함수 (ES6)

  • 화살표 함수는 실행컨텍스트 생성시 this 바인딩 과정 자체가 빠져서, 상위 스코프의 this를 그대로 활용한다.

01-4 콜백함수 호출 시 그 함수 내부에서의 this

콜백함수란?
함수 A의 제어권을 다른 함수(또는 메서드) B에게 넘겨주는 경우 함수 A를 콜백 함수라고 한다. 이때 함수 A는 함수 B의 내 부로직에 따라 실행되며, this 역시 함수 b 내부로직에서 정한 규칙에 따라 값이 결정된다.

콜백 함수에서의 this는 '무조건 이것이다'라고 정의할 수 없다. 콜백 함수의 제어권을 가지는 함수(메서드)가 콜백 함수에서의 this를 무엇으로 할지를 결정하며, 특별하게 정의 하지 않는 경우 기본적으로 함수와 동일하게 전역객체를 바라본다.

01-5 생성자 함수 내부에서의 this

var Cat = function(name, age) {
	this.bark = '야옹';
    this.name =  name;
    this.age = age;
};
var choco = new Cat('쵸코', 4);
var nabi = new Cat('나비', 6);
console.log(choco, nabi);

//결과
Cat { bark: '야옹', name: '쵸코', age:4 }
Cat { bark: '야옹', name: '나비', age:5 }
profile
Jay입니다.
post-custom-banner

0개의 댓글