본문 바로가기

Today I Learned

[TIL] 220418 (월) | var/let/const, 인터프리터, 호이스팅, Node.js 공부 기록

728x90

 

2022.04.18 (월)

노드타운 스프린터스 스터디 1일차 


To do

 

var, let, const의 차이

 

자바스크립트가 실행되면 실행 context가 구성된다.

execution context : 자바스크립트 코드가 동작할 수 있는 환경이 구성되는 것.

variable, function, this, argument 등이 정상적으로 동작할 수 있게 하는 환경.

 

근데 의문점.

그렇다면, 컴파일링 될 때 context를 구성한 다음에 변수와 함수등이 시작되는 것인가?

실행컨텍스트가 컴파일링에 포함?

애초에 자바스크립트는 컴파일을 하는가?

 

컴파일 : high level language를 기계가 알아들을 수 있는 0과 1로 이루어진 기계언어인 low level language로 변환시키는 것.

 

컴파일 언어 : 실행 전에 기계어로 바꾸고 런타임 환경에서 빠르게 작동. 실행하기 전에 에러를 잡아줌. 컴파일하는 시간은 걸리나, 컴파일 과정에서 에러를 감지하기 때문에 실제 런타임에서는 에러 적음.

인터프리터 언어 : 실행하면서 한 줄씩 해석하면서 실행. 바로 실행을 하기 떄문에 변경 사항을 빠르게 테스트하기에 용이.

 

그래서 자바스크립트는 컴파일 언어 or 인터프리터 언어?

자바스크립트를 실행하는 환경인 V8엔진. 필요에 따라 컴파일을 거쳐 자바스크립트 실행 성능을 높이는 방식을 사용함.

 

Inside the JavaScript Engine, Leonardo Freitas

V8 엔진에서 javascript 실행 -> parse 됨 -> abstract syntax tree(AST) -> 인터프리터.

이때 인터프리터에서 코드를 해석하면서 bytecode(중간 언어)로 변환. 이때는 unoptimize(비 최적화) 상태라고 함.

이 과정에서 최적화할 수 있는 코드들이 있으면 just-in-time 컴파일러로 넘겨서 컴파일시켜서 효율적으로 처리한다.

 

따라서 컴파일을 할 수 있긴한데 어쨌든 인터프리터 과정을 거치기 때문에 애매하지만 일단 인터프리터언어이다.

 

*** 컴파일, 인터프리팅, 실행 컨텍스트가 연관관계인지는 V8엔진을 더 살펴봐야할 것 같음.


그래서 다시 var, let, const로 돌아오자면,

 

var

es5까지는 변수를 선언할 수 있는 방법이 var 뿐이었다.

그러나 var는 주의를 기울이지 않으면 여러가지 문제를 일으킬 수 있다는 단점이 있었다.

 

var x = 1;
var x = 100;

var y = 1;
var y;
// 초기화 문이 없는 변수 선언문은 무시됨

console.log(x);
console.log(y);
//x = 100;
//y = 1;

var로 변수를 선언하면 중복 선언할 수 있다.

그리고 선언만 하고 초기화 값을 할당하지 않는다면 무시된다.

만약에 이미 동일한 이름의 변수가 선언되어있는지 모르고 변수를 중복선언해서 값을 바꾸어 버린다면, 의도치 않게 예전에 쓰던 변수를 바꿔버리는 문제가 생길 수 있다.

 

함수레벨 스코프.

외부에 전역으로 var로 x를 선언하고

함수에 x로 중복 선언하면 값이 바뀌고, 함수 내부에 있는 것도 전역변수가 된다.

 

var 호이스팅.

var는 변수 생성단계에서 선언, 초기화가 동시에 이루어지기 때문에 변수 선언문 이전에도 참조할 수 있다. 

console.log를 찍으면 오류가 나지 않고 undefined가 찍힌다.

선언문 이전에 변수를 참조하는 것은 에러가 나지 않지만, 프로그램의 흐름상 맞지 않고 가독성을 떨어뜨리고 오류를 발생시킬 여지를 남긴다.

 

let

var의 단점을 보완하기 위해 es6에서 등장했다.

 

변수 중복 선언 금지.

같은 이름의 변수를 같은 스코프 내에서 중복으로 선언하지 못한다.

 

var는 함수의 코드 블록만을 지역 스코프로 하는 함수 레벨 스코프.

let은 모든 코드 블록(함수, if, for, while, try/catch 등)을 지역 스코프로 인정.

따라서 다른 블록에서 선언된 변수는 서로 참조할 수 없다.

 

let은 선언단계, 초기화 단계가 분리되어 실행된다.

런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언단계가 시작되지만, 초기화 단계는 변수 선언문에 도달했을 때 실행된다.

 

// 런타임 이전에 선언단계 실행. 아직 변수가 초기화 되지 않음.
// 초기화 이전의 일시적 사각지대에세는 변수를 참조할 수 없다.
console.log(foo); //referenceError: foo is not defined

let foo; // 변수선언문에서 초기화 단계 실행
console.log(foo); // undefined

foo = 1; // 할당문에서 할당 단계 실행
console.log(foo); //1

 

이렇지만  let도 호이스팅은 발생한다.

let foo = 1; // 전역변수
{
 console.log(foo); // ReferenceError: Cannnot acccess 'foo' before initializaion
 let foo = 2; // 지역변수
}

지역변수의 호이스팅이 발생하지 않는다면, 전역변수의 1값이 출력되어야하지만, 호이스팅이 일어났기 때문에 참조에러 발생.

그래서 자바스크립트는 ES6에서 도입된 let, const 등을 모두 호이스팅한다.

단, let, const, class를 사용한 선언문은 호이스팅이 발생하지 않는 것처럼 동작한다고 한다. (발생했으면 undefined 찍혀야함, 호이스팅은 됐지만 되지 않는 것처럼 동작)

 

const

 

상수(constant 고정된 수)를 선언하기 위해 사용. 반드시 상수만을 위해서는 아니라고 함.

선언과 동시에 초기화 해야한다.

const foo = 1;

const foo; //syntaxError : missing initaializer in const declaration

 

let과 마찬가지로 블록레벨 스코프를 가짐. 변수 호이스팅이 발생하지 않는 것처럼 동작한다.

{
//변수 호이스팅이 발생하지 않는 것처럼 동작
//호이스팅은 일어났지만, 호이스팅이 발생하지 않는 것처럼 동작하므로 undefined가 아닌 before initialization 에러.
console.log(foo); //referenceError: cannot access 'foo' before initialization
const foo = 1;
console.log(foo) = 1; //1
}

// 블록 레벨 스코프를 갖는다.
console.log(foo); //referenceError: foo is not defined 
// 위의 블록 안에 있는 것을 참조 하지 못한다. 블록이 달라서.

 


호이스팅이란 무엇인가?

 

변수 선언문 이전에 참조되는 것.

var : undefined (선언문 이전에 참조하면 undefined 반환)

let, const : before initialization 오류  (참조에러 발생. 호이스팅이 일어나지만, 일어나지 않는 것처럼 동작한다)

 


Node.js란?

chrome v8엔진으로 빌드된 자바스크립트 런타임 (공식문서)

 

chorme v8엔진 이전에는 브라우저에서만 javascript를 실행할 수 있었다면(외부에서 사용하려는 시도가 있었으나 너무 느려서 사용하기 힘들었음), chrome v8엔진 출시 이후 이를 활용하여 node.js가 출시되어 (라이언 달) 외부에서도 자바스크립트를 사용할 수 있게 되었다.


Node.js를 사용해야 하는 이유는?

 

브라우저 외부에서도 javascript를 쓸 수 있기 때문에.

유연하다. 

기본 서버가 내장되어 있어서 서버 만들 때 사용하기에 좋다.

 

싱글스레드 관련해서 더 알아보기.

none blocking 관련해서 더 알아보기.

이벤트 루프 파보기.

 

 

이벤트 루프 관련.

https://zereight.tistory.com/855

 

이벤트 루프는 힙, 콜스택, 스택큐를 관리하면서 반복적으로 다음의 단계를 거치면서 처리할 게 있는지 계속 확인한다.

https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

 

 


 

Node.js의 동작 원리는 무엇인가?

 

binding 이란?

바인딩은 기본적으로 두 개의 다른 프로그래밍 언어를 "바인딩"하여 한 언어로 작성된 코드를 다른 라이브러리에서 작성된 코드에서 사용할 수 있도록 하는 라이브러리입니다. 바인딩이 있으면 언어가 다르다고 해서 모든 코드를 다시 작성할 필요가 없습니다. 바인딩의 또 다른 동기는 다양한 프로그래밍 언어의 이점을 활용할 수 있다는 것입니다. 예를 들어 C/C++는 JavaScript보다 훨씬 빠릅니다. 성능을 위해 일부 코드를 C/C++로 작성하는 것이 좋습니다.

 

node.js core library 코드작성.

node.js binding 코드를 바인딩해준다. (v8, libuv를 위해 javascript <-> c++)

v8 : 자바스크립트 실행 (메인 실행)

libuv : 비동기 작업 나오면 여기로 보내서 실행된다

 

지금 이해되기로는 이정도.

정확한 동작원리에 대해서 좀 더 파봐야할 필요가 있다.

 

 

 

 

 

 

 

참고자료

컴파일이란 무엇이며, 자바스크립트는 인터프리터 언어인가? https://devlog-of-yein.tistory.com/m/6  

이벤트 루프란? https://zereight.tistory.com/855  

이벤트 루프 https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/  

모던 자바스크립트 딥다이브 http://www.yes24.com/Product/Goods/92742567  

let const https://poiemaweb.com/es6-block-scope 

what are node.js binding? https://stackoverflow.com/questions/20382396/what-are-node-js-bindings 

V8 엔진은 어떻게 내 코드를 실행하는 걸까? https://evan-moon.github.io/2019/06/28/v8-analysis/ 

V8 엔진에 대해서...(메모리구조, 컴파일 방식) https://hwan-shell.tistory.com/343 

728x90