JS | Core 와 ES6+ 한방에 때려잡기_this(2/5)

sik2·2021년 7월 17일
0

JavaScript

목록 보기
6/11

시작에 앞서

지난 포스팅에 이어 바로 자바스크립트 this 에 대해 다루어 보도록 하겠습니다.

그전에 지난번 문제에 대한 내용을 공개합니다.

정답 1번) 1, 2번) 2 , 3번) 3

혹시 이해가 안되신다면 댓글로 질문 부탁드립니다.

저도 this를 이해할때 많이 힘들었습니다. 이해했다 싶으면 이해가 안되고...

this 파트에서 넘어가질 못하고 다시 돌아가거나 했던 삽질의 기억이 새록새록 ㅠㅠ

자바스크립트에서 this 공부를 시작 전

자바스크립트에서 this 공부를 시작 후

지금 보면 별거아닌데 정말 고생했던 것 같습니다.

아무래도 이전시간에 배운 실행컨택스트라는 개념을 따로 공부하고 큰 틀에서 맥락을 찾지 못해서였던 것 같습니다. 😂😂😂

그럼 시작하도록 하겠습니다.

이번장은 자바스크립트 ThisBinding에 대해 설명하며
화살표 함수(Arrow Function) 키워드에 대해 다룹니다.

지난번 보았던 벽돌같이 생겼던 실행 컨택스트 기억나시나요?

그안에 LexicalEnvironment 가 있고 또 그안에 enviromentRecord, outerEnviromentReference 가 있다고 했었습니다. 이는 각각 호이스팅스코프 체인과 연관이 있다고 했습니다.


출처: 코어자바스크립트

그 실행 컨텍스트가 열릴때 ThisBinding이 일어나는데요.

이는 자바스크립트에서 this 를 쓸 경우 내부적으로 약속 값을 참조하는걸 의미합니다

경우는 크게 보면 4가지가 되겠습니다.

  • 전역공간에서 : window(global)
  • 함수 호출시 : window(global)
  • 메서드 호출시 : 메서드 호출 주체(메서드명 앞 .앞)
  • 생성자 함수 호출시 : (인스턴스)

코드 예시로 살표 보겠습니다.

전역공간에서 : window(global)

여기서 전역은 브라우저 전역이므로 window입니다. 만약 nodejs 환경이라면 global이 전역이겠쥬?

지금 당장 브라우저에서 개발자 도구를 열고 콘솔에 this를 찍어보면 아래와 같이 나옵니다.

console.log(this); //Window {parent: Window, opener: null, top: Window, length: 1, frames: Window, …}

함수 호출시 : window(global)

사실 이해가 어려워지는 부분은 함수 호출시 this가 전역을 바라보고 있기 때문인데요.

function a() {
	console.log(this);
}
a();

이때 콘솔에 찍히는 this는 ? window 입니다. 함수 a를 호출 했기 때문입니다.

function b() {
	function c() {
		console.log(this);
	}
	c();
}
b();

이때 콘솔에 찍히는 this는 ? window 입니다. 함수 c를 호출 했기 때문입니다.

var d = {
	e: function() {
		function f() {
			conosole.log(this);
		}
		f();
	}
}
d.e();

이때 콘솔에 찍히는 this는 ? window 입니다. 함수 f를 호출 했기 때문입니다.

자바스크립트를 첫 언어로 접한다면 어찌보면 쉽게 받아들일 수 도 있습니다.
단지 함수 호출thiswindow를 바라본다고 기억하기만 하면됩니다.
해당 this 가 어떻게 호출 되었는지만 파악하면 됩니다. 이걸 반드시 기억해주세요.

메서드 호출시 : 메서드 호출 주체(메서드명 앞 .앞)

사실 헷갈리기 시작하는걸 정확하게 말하자면
메서드 호출시 this가 메서드 호출 주체를 바라본다는 개념을 공부하다보면
함수 호출시 전역을 바라본다는 개념과 섞여 헷갈린다는 표현이 맞는 것 같습니다.

var a = {
	b: function() {
		console.log(this);
	}
}
a.b();

이때 this가 어딜 바인딩할까요? a 입니다. 메서드 호출 주체는 a이기 때문입니다. 쉽게 생각해서 . 앞 이 무엇인지 생각하면됩니다.

var a = {
	b: {
		c: function() {
			console.log(this);			
		}
	}
}
a.b.c();

이때 this가 어딜 바인딩할까요? b? 땡! a.b 입니다. . 앞 이 무엇인지 생각해보라고 했죠? .c() 앞 a.b 가 호출 주체이므로 this는 a.b를 바인딩합니다.

자 이제 위에서 배운걸 토대로 코드를 짜보겠습니다.

var a = 10;
var obj = {
	a: 20,
	b: function() {
		console.log(this.a); // (가)
		
		function c() {
			console.log(this.a); // (나)
		}
		c();
	}
}
obj.b();

자 여기서 1번과 2번에서 어떤 값이 콘솔에서 찍힐까요?

음... (가)는 객체 내부에 a 값이 있으니까 20?일 거고 그안에 함수니까 (나)도 똑같이 20 아닌가?

땡!

(가)는 20 (나)는 10입니다.

사실 위에서 내용을 기억하고 그대로 따라 왔다면 헷갈릴 일도 없습니다.

호출 주체가 누구인지만 알면 해당 this가 어디를 바인딩하는지 알 수 있습니다.

(가)는 obj.b()로 메서드 호출this 바인딩이 일어납니다. 메서드 호출의 경우 . 앞이라고 했죠? this는 obj 객체에 바인딩 되므로 내부 a 프로퍼티를 참조합니다.

(나)는 c() 함수 호출this 바인딩이 일어납니다. 두번째 개념인 함수 호출시 this는 어디라고 했죠? window 입니다.

전역에 위치한 a를 this가 참조하기에 10이 출력됩니다.

이때 함수 호출과 메서드 호출 두개념을 따로 분리해서 공부해서 난해해 질때가 있는데 이를 한가지 기준으로 기억하면 됩니다.

호출시 . 앞을 보자 !

만약 .이 없다면 앞에 window 가 생략 될 걸로 생각하자

이렇게 이해하고 다시 코드를 보면 .앞이라는 원칙으로 이해를 한방에 할 수 있습니다.

자바스크립트이 이러한 this 바인딩 때문에 의도치 않은 에러를 야기할때가 있었는데 나름 편법(?)같이

this를 self, that, _this 와 같은 변수에 담아 썼습니다.

var a = 10;
var obj = {
	a: 20,
	b: function() {
	  var self = this;
		console.log(this.a); // (가)
		
		function c() {
			console.log(self.a); // (나)
		}
		c();
	}
}
obj.b();
function a() {
	console.log(this);
}
a(); //<= 앞에 뭐가 없다 window.a(); 라고 생각하자 . 앞인 window를 this가 호출시 바인딩한다.

이때 (가) : 20 (나) : 20이 출력됩니다.

self 변수에는 obj에 바인딩된 this 값이 담겨 있기 때문입니다.

생성자 함수 호출시 : (인스턴스)

생성자 함수 호출시에는 this가 인스턴스를 바인딩 하게 됩니다. 자바스크립트 보다 먼저 다른언어를 공부하신분은 쉽게 이해하실 겁니다.

function Person(name, age) {
	this.name = name;
	this.age = age;
}

var IU = new Person('이지은', 28) // 생성자 함수 호출
console.log(IU) //Person {name: "이지은", age: 28}

화살표 함수(Arrow Function)

드디어 화살표 함수를 살펴 볼건데요. ES6+ 이후부터 등장한 개념으로 기존의 자바스크립트 function 키워드를 보완하기위해 나온 개념입니다.

아래와 같은 문법을 사용합니다.

기존 function 키워드

var add = function(a, b) {
  return a + b;
}
console.log(add(1, 2));

화살표 함수(Arrow Function)

const add = (a, b) => {
  return a + b;
};

console.log(add(1, 2));

const add = (a, b) => a + b; //코드 블록 내부에서 바로 return 을 하는 경우는 다음과 같이 줄여서 쓸 수도 있다.
console.log(add(1, 2));

const add = a => a + b; // 매개 변수가 1개일 경우 ()를 생략할 수도 있다. (선택사항)
console.log(add(1, 2));

축약법은 이보다 많지만 여기까지만 알아보고 화살표 함수와 기존 함수 키워드와 차이점을 살펴봅시다.

기존 function 키워드에서 함수 호출시 this가 전역을 바라보기때문에 (나)에서 10을 출력했는데요.

이때 를 방지하고자 self와 같은 변수를 이용한다고 했습니다.

var a = 10;
var obj = {
	a: 20,
	b: function() {
		console.log(this.a); // (가)
		
		function c() {
			console.log(this.a); // (나)
		}
		c();
	}
}
obj.b();

//

var a = 10;
var obj = {
	a: 20,
	b: function() {
	  var self = this;
		console.log(this.a); // (가)
		
		function c() {
			console.log(self.a); // (나)
		}
		c();
	}
}
obj.b();

화살표 함수가 등장하고 매번 번거롭게 이럴 필요가 없어졌습니다.

아래와 같이 화살표함수를 쓰면 this는 obj 객체의 프로퍼티인 a를 바인딩하고 (나)에서 20을 출력합니다.

var a = 10;
var obj = {
	a: 20,
	b: function() {
		console.log(this.a); // (가)

		var c = () => console.log(this.a); // (나)

		c();
	}
}
obj.b();

이런 현상을 이해하기위해선 화살표함수 this 바인딩을 살펴봐야합니다.
화살표 함수의 this 바인딩은 아래와 같습니다.

화살표 함수를 사용하는 경우에는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다. 
화살표 함수는 this에 대한 binding이 없으며 화살표 함수가 정의되어있는 객체의 스코프를 그대로 가지고 있다. 
따라서 화살표 함수 내의 this는 상위 스코프의 this를 의미한다.

ES6+ 지원하는 환경이라면 화살표 함수를 쓰면되고 아니라면 this 바인딩의 특성을 잘 파악해서 사용하시면 됩니다.

이번 장도 역시 퀴즈가 있겠습니다.

var a = 10;
var obj = {
	a: 20,
	b: function() {
		console.log(this.a); // (가)
		
		function c() {
			console.log(this.a); // (나)
		}
		c();
	}
}

var d = obj.b;

d();

Q. (가), (나)에는 뭐가 찍힐까요? 검색하지말고 지금 당장 생각해서 풀어보세요😎

정답은 다음 포스팅에 👉다음포스팅

profile
기록

0개의 댓글