본문 바로가기
Web/Java Script

this에 대한 이해

by snfjddl 2021. 5. 22.
더보기

이 포스팅은 this에 대해 공부하면서 참고한 블로그를 번역한 글입니다.

글 마지막에 원문 링크 첨부하였습니다.

 

자바스크립트에서 this 키워드에 대해 알아보고, 여러 상황에서 this에 어떻게 값이 할당되는지 알아보자.

이 글을 따라오는 가장 좋은 방법은 아래에 제시되는 code snippet을 직접 브라우저 콘솔 창을 열어서 실행해보는 것입니다.

 

  • 새로운 크롬 탭을 열고
  • F12를 눌러 DevTools를 오픈
  • console 탭 클릭

 

객체는 자바스크립트의 기본 구성 요소입니다.

this는 자바스크립트에서 특별한 객체입니다.

this 키워드는 거의 모든 자바스크립트 코드에서 볼 수 있고, this의 값은 코드가 어떻게 동작하는지에 따라 결정됩니다.

 

this에 대해 자세히 알아보기 전, 먼저 자바스크립트 런타임 환경과 자바스크립트 코드 실행방식에 대해 알 필요가 있습니다.

 


 

Execution Context

자바스크립트에서 라인이 실행되는 환경은 execution context로 알려져있습니다.

자바스크립트 런타임은 execution context stack을 유지하며, 가장 최근에 실행된 것이 stack의 top에 위치합니다.

this 객체는 execution context이 변경될 때마다 참조하여 변경됩니다.

 


 

“this” Refers to a Global Object

기본적으로 실행에 대한 execution context는 전역적입니다.

이는 간단한 메서드 호출의 일부로 코드가 실행되면, this는 전역 객체를 참조합니다.

 

window 객체는 브라우저에서 전역 객체입니다.

그리고 NodeJS 환경에서 global이라 불리는 특별한 객체가 this의 값이 됩니다.

 

For Example:
function foo () {
	console.log("Simple function call");
	console.log(this === window); 
}

foo();	//prints true on console
console.log(this === window) //Prints true on console.

 


Immediately Invoked Function Expression (즉시 호출 함수 표현식)

(function(){
	console.log("Anonymous function invocation");
	console.log(this === window);
})();
// Prints true on console

 

strict mode에서는 this 객체의 값은 undefined를 나타낼 것입니다.

전역 객체가 window 객체 대신에 undefined를 참조하기 때문입니다.

 

For Example:
function foo () {
	'use strict';
	console.log("Simple function call")
	console.log(this === window); 
}

foo();	//prints false on console as in “strict mode” value of “this” in global execution context is undefined.

 


 

“this” Refers to a New Instance

메서드가 new 키워드와 함께 호출되면 해당 메소드는 생성자로 인식되며 새로운 인스턴스를 반환합니다.

이런 경우, this는 새로이 생성된 인스턴스를 참조합니다.

 

For Example:
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 person = new Person("John", "Reed");
person.displayName();  // Prints Name: John Reed
let person2 = new Person("Paul", "Adams");
person2.displayName();  // Prints Name: Paul Adams

이 경우 person 객체의 this는 person의 John, Reed를 참조하고

person2 객체의 this는 person2의 Paul, Adams를 참조합니다.

 


 

“this” Refers to an Invoker Object (Parent Object)

자바스크립트에서 객체의 속성으로 변수와 메소드가 올 수 있습니다.

객체의 메소드가 호출될 때 this는 호출된 메서드를 포함하고 있는 객체를 참조합니다.

 

For Example:
function foo () {
	'use strict';
	console.log("Simple function call")
	console.log(this === window); 
}

let user = {
	count: 10,
	foo: foo,
	foo1: function() {
		console.log(this === window);
	}
}

user.foo()  // Prints false because now “this” refers to user object instead of global object.
let fun1 = user.foo1;
fun1() // Prints true as this method is invoked as a simple function.
user.foo1()  // Prints false on console as foo1 is invoked as a object’s method

user.foo()는 false를 출력합니다.

this가 global 객체가 아닌 user 객체를 참조하기 때문입니다.

 

위 예시를 통해, this의 값이 몇몇 케이스에서 혼란스러워질 수 있다는 것이 확실해졌습니다.

user 객체 안의 foo1과 fun1 메서드의 정의는 같습니다. 하지만 fun1이 호출될 때 this는 global 객체를 참조합니다.

같은 함수인 user.foo1() 호출 시에는 this가 부모 객체(user)를 참조합니다.

따라서 this의 값은 메서드의 호출 방식에 의존적이라고 할 수 있습니다.

 


 

“this” With the Call and Apply Methods

자바스크립트의 모든 함수 또한 특별한 객체 타입입니다.

모든 함수는 call, bind, apply 메서드를 가집니다.

이 메서드들은 함수의 execution context에서 this에 임의의 값을 설정할 수 있습니다.

 

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 person = new Person("John", "Reed");
person.displayName(); // Prints Name: John Reed
let person2 = new Person("Paul", "Adams");
person2.displayName(); // Prints Name: Paul Adams

person.displayName.call(person2); // Here we are setting value of this to be person2 object
//Prints Name: Paul Adams

 

call과 apply의 유일한 차이점은 args가 전달되는 과정입니다.

apply의 경우, 두 번째 arg가 args 배열이지만

call의 경우, args가 개별적으로 전달됩니다.

 


 

“this” With the Bind Method

bind 메서드는 this가 전달된 첫 번째 arg를 참조하는 메서드를 반환합니다.

위의 예시에서 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 person = new Person("John", "Reed");
person.displayName(); // Prints Name: John Reed
let person2 = new Person("Paul", "Adams");
person2.displayName(); // Prints Name: Paul Adams

let person2Display = person.displayName.bind(person2);  // Creates new function with value of “this” equals to person2 object
person2Display(); // Prints Name: Paul Adams

 


 

“this” With the Fat-Arrow Function

ES6에서 새로이 소개된 함수 정의 방법입니다.

let displayName = (fn,ln) => {
	console.log(Name: ${fn}${ln});
};

 

화살표가 사용될 때는 this에 새로운 값이 담기지 않습니다.

즉, this는 함수의 외부에서 참조하고 있는 객체를 계속 참조합니다.

 

추가적인 예시를 더 보겠습니다.

function multiply(p, q, callback) {
	callback(p * q);
}

let user = {
	a: 2,
	b:3,
	findMultiply: function() {
		multiply(this.a, this.b, function(total) {
			console.log(total);
			console.log(this === window);
		})
	},

	ff: function() {
		console.log(this === window);
	},

	af: () => {
		console.log(this === window);
	}
}

user.findMultiply();
user.ff();
user.af();
//Prints 6
//Prints true
//Prints false
//Prints true

callback이 multiply 함수 안에서 호출될 때, callback 메서드의 execution context내에서 this는 global 객체인 window를 참조합니다.

따라서 this === window의 결과는 true를 출력합니다.

 

추가적으로 user 객체를 참조하는 ff는 false를 출력하고, 위에서 잠깐 언급했던 arrow function은 true를 출력하는 것을 확인할 수 있습니다.

 

var count = 5;
function test () {
	console.log(this.count === 5);
}

test() 
// Prints true as “count” variable declaration happened in global execution context 
// so count will become part of global object.

count 변수는 global execution context에 선언되었기 때문에 전역 객체의 일부분입니다.

따라서 test 함수의 결괏값은 true인 것입니다.

 


 

Summary

이제 우리는 this 값이 아래 심플한 규칙을 따른다는 것을 알 수 있습니다.

 

  • 기본적으로 this는 전역 객체를 참조하며, NodeJS와 브라우저 환경에서 전역 객체는 window이다.
  • 메서드가 객체의 속성으로써 호출될 때, this는 부모 객체를 참조한다.
  • 함수가 new 키워드와 함께 호출될 때, this는 새로이 생성된 인스턴스를 참조한다.
  • call, apply 메서드를 사용한 함수가 호출될 때, this는 전달받은 첫 번째 arg를 참조한다.

 

위에서 쭉 보았듯이 this는 때때로 혼란스러울 수 있습니다.

하지만 위 규칙을 이해한다면 this 값을 알아내는데 도움이 될 것입니다.

 

 

 

 

 

원문: https://betterprogramming.pub/understanding-the-this-keyword-in-javascript-cb76d4c7c5e8

 

Understanding the “this” Keyword in JavaScript

How the value of “this” is assigned in different scenarios

betterprogramming.pub

 

 

반응형

'Web > Java Script' 카테고리의 다른 글

binding에 대해  (0) 2021.05.16

댓글