[JS] this

jiseong·2021년 8월 13일
0

T I Learned

목록 보기
30/291
post-thumbnail

this

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');

apply/call/bind 호출

this에 바인딩 될 객체는 함수 호출 패턴에 의해 결정된다. 하지만 this를 특정 객체에 명시적으로 바인딩하는 방법도 제공한다.

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

//해당 this를 person2에 바인딩
person1.displayName.apply(person2);  // Paul Adams
/* 
or
person1.displayName.call(person2); // Paul Adams
*/

apply( )와 call( )은 위와 같이 명시적으로 this를 바인딩할 수 있게 해준다.
여기서는 person1의 this를 person2에 바인딩하는 역할을 한다.

❓ 참조
차이점이 있다면,
apply() : 두번째 파라미터가 파라미터들의 배열로 전달.
call() : 파라미터들이 각 각 전달됨.

bind

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를 가리키기 때문이다.


Reference

0개의 댓글