대부분의 객체지향 언어에서 this는 클래스로 생성한 인스턴스 객체를 의미한다. 클래스에서만 사용할 수 있기 때문에 혼란의 여지가 없거나 많지 않은데, 자바스크립트에서의 this는 어디서든 사용할 수 있다(혼란의 여지가 많다는 뜻)상황에 다라 this가 바라보는 대상이 달라지는데, 어떠한 이유로 그렇게 되는지를 파악하기 힘든 경우도 있고 예상과 다르게 엉뚱한 대상을 바라보는 경우도 있다. 따라서 정확한 작동방식을 이해하지 못하면 원인을 파악해서 해결할 수 없다.
함수와 객체(메소드)의 구분이 느슨해진 자바스크립트에서 this는 실질적으로 이 둘을 구분하는 거의 유일한 기능이다.
상황에 따라 달라지는 This
자바스크립트에서 this는 기본적으로 실행 컨텍스트가 생성될 때 함께 결정된다 (ThisBinding)
실행 컨텍스트는 함수를 호출할 때 생성되므로, 바꿔 말하면 this는 함수를 호출할 때 결정된다고 할 수 있다. 즉 함수를 어떤 방식으로 호출하느냐에 따라 this 값이 달라지는 것이다
전역 공간에서의 This
브라우저 환경에서 전역객체는 window, NodeJs 환경에서는 global 이다.
전역공간에서 발생하는 특인한 성질하나가 있는데, ‘전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로도 할당을 한다’
var a = 1;console.log(a); // 1console.log(window.a); // 1
자바스크립트의 모든 변수는 실은 특정 객체의 프로퍼티로서 동작하기 때문에 가능한 상황이다. 사용자가 var 연산자를 이용해 변수를 선언하더라도 실제 자바스크립트 엔진은 어떤 특정 객체의 프로퍼티로 인식하는 것이고, 그 특정 객체는 이전에 배운 LexicalEnvironment(이하 L.E) 이다. 따라서 실행 컨텍스트는 변수를 수집해서 L.E의 프로퍼티로 저장하고, 변수가 호출되면 L.E를 조회해서 일치하는 프로퍼티가 있을 경우 그 값을 반환한다.
앞에서 ‘전역변수를 선언하면 자동으로 전역 객체의 프로퍼티로도 할당한다’ 라고 했는데 이 문장에서 ‘로도’ 라는 말이 틀렸다는 것을 이해 할거다. 정확히 표현하면 ‘전역변수를 선언하면 자바스크립트는 이를 전역객체의 프로퍼티로 할당한다’ 가 되겠다
그러면 이러한 의문이 들수도 있다. var 로 값을 할당하나 global의 프로퍼티로 값을 할당하나 똑같은거 아니야??
결론부터 말하면 비슷하지만 다르다,
할당하는 과정 자체는 거의 일치하지만 값을 삭제하는 경우에 둘이 다르다.
var a = 1;delete window.a; // falseconsole.log(a, window.a, this.a); // 1 1 1
global.b = 2;delete window.b; // trueconsole.log(b, window.b, this.b); // Uncaught RefernceError: b is not defined
var을 사용하는 것은 해당 변수를 전역객체의 프로퍼티로 할당하면서 추가적으로 해당 프로퍼티의 configurable 속성(변경 및 삭제 가능성)을 false로 정의하는 것이다
이처럼 var로 선언한 전역변수와 전역객체의 프로퍼치는 호이스팅 여부 및 configurable여부에서 차이를 보인다.
책에서의 NodeJs와 다른점
추가로 NodeJs환경에서의 결과는 책의 내용과 사뭇 다르다 (브라우저 환경은 책과 동일)
책에서는 Nodejs환경에서 console.log(this)를 하면 global객체가 출력된다 했는데, 실제로 해보니 {}와 같은 빈 객체가 나왔다.
이유는 다음과 같다
Node 에서 실행되는 js 파일은 하나의 모듈(Module) 이다
실제로 node 명령어를 통해 js 파일 하나를 실행하면, 파일의 전체 script가 하나의 함수 안에 들어가게 된다.
Node 엔진은 해당 함수를 실행함으로써 사용자가 작성한 코드의 결과를 출력하는 것이다.
결과적으로, js파일에서 작성하는 코드 전체는 하나의 함수 내부에 들어가게 되는 것이므로, 지역 scope를 가지게 된다
따라서 자바스크립트 엔진에서 함수선언문으로 함수를 실행할 시 this가 전역객체를 참조하는다는 점을 이용하여 우리가 원하는 결과를 출력할 수 있다.
function a() { console.log(this); // global console.log(this === global); // true;}a();
메소드로서 호출할 때 그 메소드 내부에서의 This
어떤 함수를 실행하는 방법은 여러가지 방법이 있는데, 가장 일반적인 방법 두가지는 함수로서 호출하는 경우와 메소드로서 호출하는 경우이다.
이 둘을 구분하는 유일한 차이는 독립성에 있는데, 함수는 그 자체로 독립적인 기능을 수행하는 반면, 메소드는 자신을 호출한 대상 객체에 관한 동작을 수행한다