this는 함수가 어떻게 호출되었는지
에 따라 바인딩할 객체를 동적으로 결정
한다.
그렇다면 각 케이스별로 this가 어디에 바인딩되는지 살펴보자.
기본적으로 this
는 전역 객체 즉, 브라우저에서는 window
, Node에서는 global
를 바인딩한다. 함수 호출
도 이 전역 객체
를 가리킨다.
console.log(this); // window
function foo() {
console.log(this); // window
function bar() {
console.log(this); // window
}
bar();
}
foo();
//IIFE
(function(){
console.log(this); // window
})();
위의 코드의 결과를 보면 전역함수
뿐만 아니라 즉시실행함수
, 전역함수의 내부 함수
에서도 this는 전역객체에 바인딩
된다.
객체의 메소드로 호출
시 this는 호출된 메소드의 객체
를 바인딩한다.
function foo () {
console.log(this);
}
let user = {
name: 'jiseong',
foo: foo,
foo1: function() {
console.log(this);
}
}
user.foo(); // user
user.foo1() // user
let fun1 = user.foo1;
fun1(); // window
foo
와 foo1
는 해당 객체의 메소드로 호출하였기 때문에 user객체에 바인딩
되었지만, fun1
은 일반 함수의 형태로 호출하였기 때문에 전역객체에 바인딩
된 것이다.
그렇다면 한가지 예를 더 들어보자.
아래와 같은 코드가 있을 때 this가 참조하는 객체는 어떤 객체일까?
let user = {
name: 'jiseong',
foo: function() {
console.log(this) // user
function bar() {
console.log(this); // ?
}
bar(); /* 일반 함수호출 형태 */
}
}
user.foo();
bar
도 결국 일반 함수 형태로 호출하였기 때문에 this는 전역객체에 바인딩
된다.
그렇기 때문에
함수가 어떻게 호출되었는지?
가 가장 중요한 포인트이다.
new 키워드로 호출되었을 때, 그 함수를 흔히 생성자 함수라고 부르고 새로운 인스턴스를 반환한다. 이 경우에는 this는 생성된 인스턴스를 바인딩
한다.
function user(name) {
this.name = name;
console.log(this); // user
}
let me = new user('jiseong');
this에 바인딩 될 객체는 함수 호출 패턴에 의해 결정된다. 하지만 this를 특정 객체에 명시적으로 바인딩하는 방법도 제공한다.
function Person(fn, ln) {
this.first_name = fn;
this.last_name = ln;
this.displayName = function() {
console.log(`Name: ${this.first_name} ${this.last_name}`);
}
}
let person1 = new Person("John", "Reed");
person1.displayName(); // John Reed
let person2 = new Person("Paul", "Adams");
person2.displayName(); // Paul Adams
//해당 this를 person2에 바인딩
person1.displayName.apply(person2); // Paul Adams
/*
or
person1.displayName.call(person2); // Paul Adams
*/
apply( )와 call( )은 위와 같이 명시적으로 this를 바인딩할 수 있게 해준다.
여기서는 person1의 this를 person2에 바인딩
하는 역할을 한다.
❓ 참조
차이점이 있다면,
apply()
: 두번째 파라미터가 파라미터들의 배열로 전달.
call()
: 파라미터들이 각 각 전달됨.
function Person(fn, ln) {
this.first_name = fn;
this.last_name = ln;
this.displayName = function() {
console.log(`Name: ${this.first_name} ${this.last_name}`);
}
}
let person1 = new Person("John", "Reed");
person1.displayName(); // John Reed
let person2 = new Person("Paul", "Adams");
person2.displayName(); // Paul Adams
let person2Display = person1.displayName.bind(person2);
person2Display(); // Paul Adams
bind( )는 전달된 첫번째 파라미터를 참조하여 this를 바꾸지만 호출되지는 않는다. 따라서 변수를 할당하여 호출하는 형태로 사용해야 한다.
[ES6] Arrow function의 this
화살표 함수는 함수를
호출할 때가 아닌 선언할 때
this에 바인딩할 객체가 정적으로 결정된다.
화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다. 이를Lexical this
라고 한다.let user = { name: 'jiseong', foo1: function() { console.log(this); }, foo2: () => { console.log(this); } } user.foo1(); // user user.foo2(); // Window
위의 코드에서
메소드 foo2로 호출
하여도this가 window
로 출력되는 것을 볼 수 있다. 이는arrow function의 this
는선언할 때의 기준으로 상위 스코프 this
를 가리키기 때문이다.