특별히 this를 지정하지 않으면 this는 전역객체를 가리킨다. (브라우저 환경에선 window, Node.js 환경에서는 global)
자바스크립트의 모든 변수는 특정 객체의 프로퍼티가 된다.
vara=1;
console.log(window.a);// 1
console.log(this.a);// 1
실행 컨텍스트가 식별자(변수)들을 수집해서 LexicalEnvironment의 프로퍼티로 저장하기 때문이다.
따라서 사실상 var a 와 window.a 는 동일하다고 할 수 있는데, 다른 점은 delete 명령에서이다. window.a = 1 로 선언한 변수는 delete 명령으로 제거할 수 있지만 var a = 1 로 선언한 변수는 delete 명령으로 제거할 수 없다. 이 차이는 일종의 사용자의 실수를 막기 위한 방어전략인데, 자바스크립트 엔진은 var 로 선언된 변수는 프로퍼티로 저장할 때 configurable 속성을 false로 설정해서 삭제가 불가능하도록 한다.
메서드가 아닌 일반 함수로 호출하면 호출 주체가 명시되지 않는다. this가 명시적으로 지정되지 않은 경우에는 기본적으로 전역 객체를 this로 지정한다고 했다. 따라서 일반 함수의 this는 전역객체가 된다.
더글라스 크락포드 피셜 이 부분은 설계상의 오류라고 한다. (자세한 이유는 아래에...)
this가 명시적으로 지정되지 않은 경우에는 기본적으로 전역객체를 this로 지정하는 것 때문에 같은 함수여도 어떻게 호출하느냐에 따라서 this가 달라지게 되었다. 그냥 무작정 전역객체를 this로 설정하기보다는 호출 당시 주변의 this를 상속받았다면 더 좋았을 것이다. (스코프 체인의 개념과도 어울린다.)
호출 당시 주변의 this를 사용하는 방법은 2가지가 있다.
(ES5 이전) 변수에 this를 저장해서 활용하기.
단순하게 함수 선언 전에 this를 _this나 self 같은 변수에 저장해두고 함수 내에서 활용하는 방식이다.
(ES6 이후) 화살표 함수 활용하기
화살표 함수는 this 바인딩 과정 자체가 없기 때문에 상위 this를 그대로 상속받는다.
콜백 함수는 메서드를 전달하든 일반 함수로 전달하든 함수로서 호출된다. 그래서 기본적으로 this가 전역객체가 된다. 하지만 addEventListener 같은 함수는 this로 자신을 호출한 element를 this로 갖는데 그건 addEventListener에서 그렇게 설정했기 때문이다. 콜백 함수를 호출하는 측은 this에 대한 제어권도 넘겨받는다. 따라서 제어권을 갖는 코드가 this를 결정하고, 만약 특별히 결정하지 않는다면 전역객체가 this로 설정된다.