this
란 함수가 호출될 때, 즉 실행 컨텍스트가 생성될 때 가리키는 대상 (혹은 값)이다.console.log(this); // Window {...} console.log(this === window); // true
전역에서 this
가 가리키는 대상은 Window
라는 전역 객체이다.
브라우저에서는 Window
, Node.js에서는 global
객체를 가리킨다.
var a = 1; console.log(a); // 1 console.log(window.a); // 1 // let b = 2; console.log(b); // 2 console.log(window.b); // undefined // const c = 3; console.log(c); // 3 console.log(window.c); // undefined // function print2() { console.log("hello"); } // print2(); // "hello" window.print2(); // "hello"
전역 객체와 전역 변수의 관계를 잠시 짚고 넘어가자면, var
를 사용하여 변수를 선언 및 할당하게 될 시 window
전역 객체의 프로퍼티로 지정이 된다. (함수 선언문 또한 전역 객체의 프로퍼티로 지정된다.)
var
와 다르게, let
과 const
의 경우 window
객체의 프로퍼티로 접근할 수 없다.
const printName = function () { console.log(this); }; printName(); // Window {...} // const yongmin = { name: "yongmin", method: printName }; // yongmin.method(); // { name: 'yongmin', method: ƒ printName() }
함수를 실행하는 방법은, 독립적으로 함수를 호출하는 방법과 객체의 메서드로서 호출하는 방법이 있다.
함수의 호출 방법 구분은 함수 앞의 .
이다.
특정 함수를 함수로서 호출할 경우 this
가 지정되지 않는다.(호출 주체가 없다) 또한 이러할 경우 this는 전역 객체를 바라보게 된다. (자동으로 전역객체가 바인딩이 된다.)
메서드로서 호출할 경우, 호출 주체는 .
앞의 객체이며 이때 this
가 가리키는 대상이 호출 주체인 객체가 된다.
const obj = { outer: function () { console.log(this); // { outer: ƒ outer() } var inner = function () { console.log(this); // Window {...} }; inner(); // 함수로서 호출 }, }; obj.outer(); // 메서드로서 호출
this
가 가리키는 대상이 전역객체임을 알 수 있다.const obj = { outer: function () { console.log(this); // { outer: ƒ outer() } const target = this; var inner = function () { console.log(target); // { outer: ƒ outer() } }; inner(); // 함수로서 호출 }, }; obj.outer(); // 메서드로서 호출
this
가 가리키는 객체가 전역 객체가 아닌 메서드가 속한 객체를 가리키게 하고자 할 경우, this
를 특정 변수에 할당하여 우회하는 방법이 있다.const obj = { outer: function () { console.log(this); // { outer: ƒ outer() } var inner = () => { console.log(this); }; inner(); // 함수로서 호출 }, }; obj.outer(); // 메서드로서 호출
ES6에서 도입한 화살표 함수의 경우, 함수로서 호출을 할 때 자동으로 전역 객체를 바인딩하지 않는다.
화살표 함수에서의 this
는 따로 가지고 있지 않고 스코프 체인상 가장 가까운 상위 객체가 된다. (이를 lexical this
라고 한다.) 이러한 arrow function의 도입으로, 기존에 this
를 변수에 선언했던 우회방법은 불필요해졌다.
[1, 2, 3, 4, 5].forEach(function () { console.log(this); // Window {...} * 5 }); // const target = document.getElementById("hello"); target.addEventListener("click", () => { console.log(this); // id가 `hello`인 대상 });
일반적으로 콜백 함수도 메소드로서 호출된 것이 아니며, 특정 객체에 바인딩이 안됐기 때문에 this
는 전역객체를 바라보게 된다.
예외적으로 addEventListener
의 경우는, 자기 자신의 this
를 가리키도록 지정되어있다.
const Person = function (name) { this.name = name; }; // const yongmin = new Person("yongmin"); console.log(yongmin); // Person { // name: 'yongmin', // __proto__: { constructor: ƒ Person() } // } Person.prototype.printName = function () { console.log(this.name); }; // yongmin.printName(); // 'yongmin'
생성자 함수는, ES6 클래스가 도입이 되기 전까지 객체를 생성하는데 사용한 함수이다.
생성자 함수 내부에서의 this
는, 생성된 객체(인스턴스) 자신을 가리키게 된다.
const callMethod = function (a, b, c) { console.log(this, this.x, a, b, c); { x: 1 } 1 2 3 4 }; // callMethod.call({ x: 1 }, 2, 3, 4); // // const applyMethod = function (a, b, c) { console.log(this, this.x, a, b, c); // { x: 5 } 5 6 7 8 }; // applyMethod.apply({ x: 5 }, [6, 7, 8]);
선언과 동시에 함수가 호출이 되며, call
과 apply
메서드를 사용하면 특정 객체를 this
가 가리키는 대상으로 지정할 수 있다.
첫 번째 인자는 this
가 가리키는 객체이며, 두 번째 인자의 경우call
은 개별 형태로, apply
는 배열 형태로 인자를 받게 된다.
const bindMethod = function (a, b, c, d) { console.log(this, a, b, c, d); // { x: 1 } 10 1 2 3 }; // const result = bindMethod.bind({ x: 1 }, 10); result(1, 2, 3, 4);
call
과 apply
와 다르게, 함수 선언과 동시에 호출이 되지 않는다.
bind
는 함수를 호출할 때 this
의 대상이 되는 객체, 혹은 인수들을 먼저 인자로 전달한다.
다시 새로운 함수에 인자를 전달할 경우, 기존에 전달했던 인자들의 뒤에 이어서 등록된다.
코어 자바스크립트 책 - This
👍👍👍👍👍