JS | Core 와 ES6+ 한방에 때려잡기_실행컨택스트, Scope(1/5)

sik2·2021년 7월 17일
0

JavaScript

목록 보기
5/11

시작에 앞서

자바스크립트는 저에게 희망과 좌절을 동시에 안겨준 언어인데요..

학생 때 쉬운줄 알고 덤볐다고 코어를 파면서 정말 난해한 부분을 많이 느꼈습니다.

당시 인사이드 자바스크립트 책을 거의 6번 돌렸는데 그래도 난해한 부분이 많았습니다.
최근 모던 자바스크립트를 공부 하면서 다시금 코어자바스크립트 정리의 필요성을 느꼈습니다. 그때 기존의 공부자료와 코어자바스크립트 책을 참조하여 내용을 정리해보니 그때 어려웠던 부분이 많이 해소됨을 느꼈습니다.

JS 완벽정복은 아직도 현재 진행중이지만 이번 정리를 통해 더더욱 좋은 자바스크립트 개발자로 성장했으면 좋겠습니다.

이번장은 실행컨텍스트에 대해 설명하며 const, let 키워드에 대해 다룹니다.

실행컨텍스트(Execution Context)

출처: 코어자바스크립트

자바스크립트 실행컨텍스트(Execution Context)를 이해하려면 콜스택 자료구조를 알아야 합니다. 아래와 같이 벽돌이 하나 하나 쌓이고 마지막 들어온 순서대로 다시 나가서 비워집니다.

저 벽돌 하나하나는 함수입니다. 즉 함수가 호출(call) 할때 쌓이고 비워집니다(stack)

실행 컨텍스트란 자바스크립트의에서 함수 실행 시 일어나는 일련의 처리 프로세스라고 기억하시면 됩니다.

출처: 코어자바스크립트

벽돌을 자세히 확대 해보면
LexicalEnviroment이 있고 안에 enviromentRecord, outerEnviromentReference 가 있습니다.

용어만 보면 어려워 보이지만 아래에서 자세히 풀어서 설명할테니 이런 개념이 있구나 라고만 생각하시고 넘어갑시다.

일단 두가지를 기억하자

  • 자바스크립트는 함수 호출호이스팅이 일어난다(선언이 아니라 호출!)
  • 자바스크립트는 함수는 스코프체인을 통해 내부에서 외부 함수를 참조할 수 있지만 외부에서 내부는 참조하지 못한다.

+) 선언과 호출의 차이

// 자바스크립트 변수, 함수를 단지 정의 했다면 선언이다. 
// 아래는 익명함수를 선언하고 선언한 변수 greeting에 할당했다.
var greeting = function(){ conosole.log("HI") };

// 선언한 함수를 실행할때 호출이라고 한다.
greeting();

먼저 닥치고 기억하라던 내용 중 호이스팅이라는 개념을 알아봅시다.

Hoisting

호이스팅이란 끌어올린다는 의미입니다.

자바스크립트는 선어한 함수, 변수를 위로 끌어 올립니다(할당은 올려지지 않습니다)

실제 코드가 아래처럼 변하는 건 아니지만 자바스크립트 V8엔진이 런타임시 저렇게 처리한다는 의미로 이해해 둡시다.

  • 실제코드
console.log(a);
var a = 1;
  • 호이스팅
var a; // 선언된 변수 a를 먼저 호이스팅한다.
console.log(a); // console.log(a) 를 해보니 변수 a에 아무런 빈 값이 없어 undefined를 출력한다.
a = 1; // 변수 a에 1을 할당한다.

자바스크립트를 입문언어로 배우면 당연해 보일 수 있다. 하지만 C, JAVA와 같은 언어를 공부한 입장에서는 조금 난해합니다. 사실 에러가 터질줄 알았는데 그냥 값이 비어 있다고만 나옵니다.

다른 예제를 보자

foo();

function foo() {
	consol.log("나는 호출된다!");
}

첫 줄에 foo() 라는 함수가 호출 되었는데
사실 이때 절차적으로 한 줄 한 줄 실행한다고 생각하는 입장에서
foo함수가 선언도 되기 전에 호출했기 때문에 오류가 터질 꺼 라고 생각합니다.

하지만 결과는 콘솔창에 "나는 호출된다!"가 찍힙니다.

이 또한 런타임이 호이스팅 아래와 같이 일어나기 때문입니다.

function foo() {
	consol.log("나는 호출된다!");
}

foo();

+) 그래서 es5에서는 자바스크립트에서는 함수를 변수에 할당해서 쓰는 함수표현식을 권장했습니다.

foo(); // error

var foo = function () {
	consol.log("나는 호출된다!");
}

foo(); // "나는 호출된다!"

다시 정리하자면 자바스크립트는 호출시 호이스팅으로 선언된 변수, 함수가 끌어 올려지게 됩니다.

두번째 Scope chain(스코프 체인)


출처


출처

가끔 드라마나 영화에서 볼 수 있는 취조실 사진입니다.

밖에 형사를 inner 함수 안에 있는 용의자를 outer 함수라고 가정하고 코드를 보면 이해가 빠를 겁니다.

function outer() {
 var a = 1;
	function inner() {
		console.log(a); 
	}
 inner();
}
outer();

inner함수가 호출됐을때 console.log(a)를 찍습니다. inner 함수 내부에는 아무것도 없으므로 에러 혹은 undefind가 나올 것이라 예상할 수도 있습니다. 하지만 outer 함수가 내부의 a에 할당됨 1이 콘솔에 찍히게 됩니다.

아까 취조실의 예 처럼
inner함수 ⇒ 형사이고 outer 함수 ⇒ 용의자 라고 했을 때
볼 수 있다라는 개념은 참조할 수 있다는 개념으로 이해하시면 됩니다.
inner 함수에 console.log(a) 시 만약 내부에 a 값이 있다면 그 값을 출력 하겠지만 만약 없다면 자기 부모한테 a 가 있는지 찾아보고 있다면 그 값을 참조할 수 있습니다.

이를 실행 컨텍스트 그림으로 표현하자면 아래아 같이 표현할 수 있습니다. 파란색은 참조가능, 빨간색은 불가능 입니다.

inner 함수는 outer 함수를 참조할 수 있고, outer 함수는 전역(Global)를 참조 할 수 있습니다.


출처: 코어자바스크립트
하지만 반대로 outer 함수는 inner를 참조 할 수 없습니다. 마치 취조실에서 형사가 보고있는지 모르는 것 처럼요.


출처: 코어자바스크립트

이렇게 타고 타고 올라가는게 마치 체인 같다고해서 참조하는 현상을 스코프 체인(Scope Chain)이라고 합니다.

+) 좀더 깊게 공부하실 분은 자바스크립트 엔진은 스코프 체인을 통해 렉시컬 스코프(Lexical Scope)를 확인한다 라는 키워드로 검색해보시면됩니다.

자바스크립트의 실행컨텍스트에서 다시 용어 정리를 해보자면

enviromentRecord호이스팅을 뜻합니다.

outerEnvironmentReference => 스코프 체인을 뜻합니다.

세줄 요약을 하자면 아래와 같습니다.

  • 자바스크립트는 함수가 호출(실행) 될 때 실행 컨택스트가 열린다
  • 실행컨텍스트는 enviromentRecord, outerEnvironmentReference 가 일어난다.
  • enviromentRecord호이스팅 , outerEnvironmentReference => 스코프 체인 을 의미한다.

Reactjs 와 Nodejs 같은 녀석들의 등장으로 자바스크립트 어플리케이션이 거대해 지면서 개발자들은 보다 쉽게 디버깅하고 유지보수하기 위해 ES6에서 다양한 키워드를 추가했습니다.

그중 ES6에서는 const, let 이라는 키워드가 있습니다.

  • const는 상수(constant) : 常항상 상을 써서 변하지 않는 수를 의미합니다. 다른 언어들에서 이미 쓰이던 상수 개념을 차용한 것으로 보입니다. 한번 할당하면 값을 변화 시킬 수 없습니다.

  • let은 변수 : ES6+부터는 변수는 var 키워드를 지양하고 let 키워드를 권장합니다. 어원은 let's go 할 때 let이더군요 (허락하다 이런의미 같네요 ㅡ,.ㅡ) 아무래도 먼저 나온 Swift 문법에서 아이디어를 채택한 듯 합니다.

    변수이므로 할당 후 값을 변화 시킬 수 있습니다.

const a = 1;
a = 2; //Uncaught TypeError: Assignment to constant variable. 에러(값 변화 불가)
console.log(a); //1

let b = 1;
b = 2; 
console.log(b); //2

용어 설명은 여기까지 하고

Scope

자바스크립트의 스코프는 말그대로 범위를 뜻합니다.

더 자세히 이야기하면 변수 혹은 함수를 선언하게 될 때 해당 변수 또는 함수가 유효한 범위를 의미합니다.

스코프는 총 3가지가 있습니다.

  1. Global (전역) Scope: 코드의 모든 범위에서 사용이 가능합니다.
  2. Function (함수) Scope: 함수 안에서만 사용이 가능합니다.
  3. Block (블록) Scope: if, for, switch 등 특정 블록 내부에서만 사용이 가능합니다.

const, let 의 호이스팅

이 두 키워드 const, letBlock Scope를 가집니다.
아까 말했던 var 키워드는 호이스팅이 된다고 했습니다.

즉! Block Scope호이스팅 을 방지할 수 있습니다.

+)엄밀히 말하면 호이스팅은 되지만 코드 블록의 선두부터 초기화가 이루어지는 지점까지 일시적 사각지대(TDZ)에 빠진다. const, let에 대해서 실제로 변수가 선언된 위치가 오기전에 해당 변수를 호출할 수 없음.

console.log(a); //Uncaught ReferenceError: Cannot access 'a' before initialization
const a = 1;

개발자 도구에서 찍어보니 에러가 터집니다.

이는 var 에서는 선언 변수 a가 호이스팅 된 덕에 에러가 아니라 빈 값 즉 undefind가 출력 되었지만
const에서는 호이스팅이 방지되기에 에러가 터지는 것입니다. let 또한 block 스코프이기에 결과는 같습니다.

const, let 의 스코프체인

function outer() {
 const a = 1;
	function inner() {
		console.log(a);  // 1 출력
	}
 inner();
}
outer();
function outer() {
 let a = 1;
	function inner() {
		console.log(a);  // 1 출력
	}
 inner();
}
outer();

inner 에서 outer const, let 으로 선언한 변수에 스코프 체인을 통해 접근 가능한 것을 볼 수 있습니다.

정리하자면 아래와 같습니다.

  • const let 은 블록스코프이기 때문에 기존 var 에서 발견한 호이스팅으로 인한 디버깅 오류를 방지할 수 있다.
  • const let 으로 선언한 변수에 스코프 체인을 통해 참조 가능하다.(기존과 동일하다)

Class 기반언어에서 메서드를 정의할때 private, protected, public 순으로 점진적으로 접근제한을 열어주는 것 처럼

한줄 요약

변수 키워드를 쓸때 const를 먼저 쓰고 필요할때 let을 쓰는 습관을 들이자. var는 안녕하자 ^^

+)

IE9, IE10 같은 브라우저에서는 const, let 키워드를 지원하지 않습니다.

IE는 개인주의야...

다만 React에서는 Babel이 구형브라우저에서 작동하는데 문제가 없게 var 키워드로 변환해줍니다. 어디까지 지원하는지는 잘 모르겠네요. (제가알기론 IE9 까지 가능한 걸로 압니다)

IE11 과 최신 edge 에서는 const, let 키워드를 쓸 수 있답니다. ^^

원래는 이번 장에서 this 까지 다루어 볼까 했는데

내용이 너무 길어졌네요.

한번 끊고 다음장에 this로 돌아오겠습니다.

복습 테스트

아래의 console.log(a) 값을 모두 맞추세요.


var a = 1;
function outer() {
	function inner() {
		console.log(a) // 1번
    var a = 3;
	}
  inner();
	console.log(a); // 2번
}
outer();
console.log(a); // 3번

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


ref)
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=206513031

https://www.inflearn.com/course/%ED%95%B5%EC%8B%AC%EA%B0%9C%EB%85%90-javascript-flow

https://www.hanbit.co.kr/store/books/look.php?p_code=B6479856408

https://medium.com/@khwsc1/%EB%B2%88%EC%97%AD-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8A%A4%EC%BD%94%ED%94%84%EC%99%80-%ED%81%B4%EB%A1%9C%EC%A0%80-javascript-scope-and-closures-8d402c976d19

profile
기록

0개의 댓글