Posts 모던 자바스크립트 Deep Dive : 2장 ~ 5장 내용 정리
Post
Cancel

모던 자바스크립트 Deep Dive : 2장 ~ 5장 내용 정리

모던 자바스크립트 Deep Dive를 읽고 정리한 내용입니다. 새롭게 알게 된 내용을 위주로 정리했습니다.

2장. 자바스크립트란

2.3.4 Node.js

  • Node.js는 비동기 I/O를 지원하며 단일 스레드 이벤트 루프 기반으로 동작함으로써 요청 처리 성능이 좋다.
  • 따라서 Node.js는 데이터를 실시간으로 처리하기 위해 I/O가 빈번하게 발생하는 SPA에 적합하다.
  • 하지만, CPU 사용률이 높은 애플리케이션에는 권장하지 않는다.

2.4 자바스크립트와 ECMAScript

ECMAScript는 자바스크립트의 표준 사양인 ECMA-262를 말하며, 프로그래밍 언어의 값, 타입, 객체와 프로퍼티, 함수, 표준 빌트인 객체 등 핵심 문법을 규정한다. 이에 따라 각 브라우저 제조사는 ECMAScript 사양을 준수해서 브라우저에 내장되는 자바스크립트 엔진을 구현한다.

자바스크립트는 일반적으로 프로그래밍 언어로서 기본 뼈대를 이루는 ECMAScript 와 브라우저가 별도로 지원하는 클라이언트 사이드 *Web API를 아우르는 개념이다.

*Web API : DOM, BOM, Canvas, XMLHttpRequest, fetch, requesteAnimationFrame, SVG, Web Storage, Web Component, Web Worker 등

2.5 자바스크립트의 특징

자바스크립트는 개발자가 별도의 컴파일 작업을 수행하지 않는 인터프리터 언어이다. 인터프리터는 소스코드를 즉시 실행하고, 컴파일러는 빠르게 동작하는 머신 코드를 생성하고 최적화한다. 이를 통해 컴파일 단계에서 추가적인 시간이 필요함에도 더욱 빠르게 코드를 실행할 수 있다.

3장. 자바스크립트 개발 환경과 실행 방법

3.1 자바스크립트 실행 환경

모든 브라우저와 Node.js는 자바스크립트를 해석하고 실행할 수 있는 자바스크립트 엔진을 내장하고 있다. 그래서 자바스크립트는 브라우저 환경과 Node.js 환경에서 실행할 수 있다.

하지만, 브라우저는 Node.js는 용도가 다르기 때문에 Node.js에서는 ECMAScript 이외에 추가로 제공하는 기능은 호환되지 않는다. 브라우저는 HTML, CSS, 자바스크립트를 실행하여 화면에 렌더링 하는 것이 주된 목적이지만, Node.js는 브라우저 외부에서 자바스크립트 실행 환경을 제공하는 것이 주된 목적이기 때문이다.

예를 들어, Node.js는 HTML 요소를 선택하거나 조작하는 기능의 집합인 DOM API를 다룰 필요가 없기 때문에 제공하지 않는다. 반대로, Node.js에서는 파일을 생성하고 수정할 수 있는 파일 시스템을 기본 제공하지만, 브라우저는 이를 지원하지 않는다. (Web API인 FileReader 객체를 사용하면 파일을 읽는 것은 가능하다.)

웹 애플리케이션의 자바스크립트는 사용자 컴퓨터의 브라우저에서만 동작한다. 만약, 브라우저를 통해 다운로드된 자바스크립트가 사용자 컴퓨터의 로컬 파일을 삭제하거나 수정한다면 보안성이 낮아지기 때문이다.

정리하자면, Node.js는 클라이언트 사이드 Web API를 지원하지 않고, ECMAScript와 Node.js 고유의 API를 지원한다.

4장. 변수

4.1 변수란 무엇인가? 왜 필요한가?

  • 변수 값 : 변수에 저장된 값
  • 할당 : 변수에 값을 저장하는 것
  • 참조 : 변수에 저장된 값을 읽어 들이는 것

4.3 변수 선언

변수 선언문은 변수 이름을 등록하고, 값을 저장할 메모리 공간을 확보한다.

var 키워드를 사용한 변수 선언은 선언 단계와 초기화 단계가 동시에 진행된다. var a; 는 선언 단계를 통해 변수 이름 a 를 등록하고, 초기화 단계를 통해 score 변수에 암묵적으로 undefined 를 할당해 초기화한다. 초기화란 변수가 선언된 이후로 최초로 값을 할당하는 것을 말한다. 따라서 var 키워드로 선언한 변수는 어떠한 값을 할당하지 않아도 undefined 값을 갖는다.

만약 초기화 단계를 거치지 않으면, 확보된 메모리 공간에는 이전에 다른 애플리케이션이 사용했던 값이 남아 있을 수 있다. 이러한 값을 쓰레기 값(garbage value) 라 한다. 따라서 메모리 공간을 확보한 다음, 값을 할당하지 않은 상태에서 곧바로 변수 값을 참조하면 쓰레기 값이 나올 수 있다. 자바스크립트의 var 키워드는 암묵적으로 초기화를 수행하므로 이러한 위험으로부터 안전하다.

4.4 변수 선언과 실행 시점과 변수 호이스팅

자바스크립트 변수 선언은 소스코드가 한 줄씩 순차적으로 실행되는 시점인 런타임이 아니라 그 이전 단계에서 먼저 실행된다.

자바스크립트 엔진은 소스코드를 한 줄씩 순차적으로 실행하기 앞서 먼저 소스코드의 평가 과정을 거치면서 소스코드를 실행하기 위한 준비를 한다. 이때, 소스코드 실행을 위한 준비 단계인 소스코드의 평가 과정에서 자바스크립트 엔진은 변수 선언을 포함한 모든 선언문을 소스코드에서 찾아내 먼저 실행한다. 그리고 소스코드의 평가 과정이 끝나면 변수 선언을 포함한 모든 선언문을 제외하고 소스코드를 한 줄씩 순차적으로 실행한다.

1
2
3
console.log(a); // undefined

var a;

위의 코드처럼 변수 선언문이 출력문보다 나중에 선언 되었음에도 값이 undefined 로 할당된 것을 확인할 수 있는데, 이를 변수 호이스팅 이라고 한다. 참고로 자바스크립트에서는 var, let, const, function, class 키워드를 사용해서 선언하는 모든 식별자는 호이스팅된다.

4.5 값의 할당

변수 선언은 소스코드가 순차적으로 실행되는 시점인 런타임 이전에 먼저 실행되고, 값의 할당은 소스코드가 순차적으로 실행되는 시점인 런타임에 실행된다.

1
2
3
4
5
6
console.log(a); // undefined

var a;
a = 10;

console.log(a); // 10

변수 호이스팅에 의해 a 라는 변수는 초기화 과정을 거쳐 undefined가 할당된다. 이후 순서대로 코드를 실행하다가 변수에 10을 할당하고 나서 출력하면 10이 출력되는 것을 확인할 수 있다.

변수에 값을 할당할 때는 이전 값 undefined가 저장된 메모리 공간을 지우고 그 메모리 공간에 할당 값 10을 새롭게 저장하는 것이 아니라, 새로운 메모리 공간을 확보하고 그곳에 할당 값 10을 저장하는 것이다.

4.6 값의 재할당

재할당은 이미 값이 할당된 변수에 새로운 값을 다시 할당하는 것을 말한다.

사실 var score = 80 도 엄밀한 의미에서는 최종적으로 재할당을 하는 것이다.

1
2
var score = 80; // 변수 선언과 값의 할당
score = 90; // 값의 재할당

재할당이 이루어지고 나서 이전 값들은 어떤 식별자와도 연결되어 있지 않아서 가비지 콜렉터에 의해 메모리에서 자동 해제된다. 대신, 메모리에서 언제 해제될지는 예측할 수 없다.

가비지 콜렉터 (Garbage Collector)

애플리케이션이 할당한 메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리를 해제하는 기능을 말한다. 자바스크립트는 가비지 콜렉터를 내장하고 있는 매니지드 언어로서 가비지 콜렉터를 통해 메모리 누수(memory leak)를 방지한다.

언매니지드 언어(unmanaged language)와 매니지드 언어(managed language)

프로그래밍 언어는 메모리 관리 방식에 따라 언매니지드 언어와 매니지드 언어로 분류한다. C언어와 같은 언매니지드 언어는 개발자가 명시적으로 메모리를 할당하고 제어하는 기능을 제공한다. 그래서 개발자의 역량에 따라 최적의 성능을 확보할 수 있지만, 반대의 경우에는 치명적 오류가 발생할 수도 있다. 자바스크립트 같은 매니지드 언어는 메모리의 할당 및 해제를 위한 메모리 관리 기능을 언어 차원에서 담당하고 개발자의 직접적인 메모리 제어를 허용하지 않는다. 즉, 개발자가 명시적으로 메모리를 할당하고 해제할 수 없다. 덕분에 개발자가 일정한 생산성을 확보할 수는 있지만, 성능 면에서 어느 정도의 손실은 감수할 수 밖에 없다.

4.7 식별자 네이밍 규칙

자바스크립트에서는 일반적으로 변수나 함수의 이름에는 카멜 케이스를 사용하고, 생성자 함수, 클래스 이름에는 파스칼 케이스를 사용한다.

5.2 리터럴

리터럴(literal)은 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법을 말한다.

1
2
// 숫자 리터럴 3
3;

숫자 리터럴 3을 코드에 기술하면 자바스크립트 엔진은 이를 평가해서 숫자 값 3을 생성한다

이처럼 리터럴은 사람이 이해할 수 있는 문자(아라비아 숫자, 알파벳, 한글 등) 또는 미리 약속된 기호(‘’, “”, ., [], {}, // 등)로 표기한 코드다. 자바스크립트 엔진은 코드가 실행되는 시점인 런타임에 리터럴을 평가해 값을 생성한다. 즉, 리터럴은 값을 생성하기 위해 미리 약속한 표기법이라고 할 수 있다.

5.3 표현식

표현식(expression)은 값으로 평가될 수 있는 문(statement)이다. 즉, 표현식이 평가되면 새로운 값을 생성하거나 기존 값을 참조한다. 리터럴도 값으로 평가되므로 표현식이라고 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 리터럴 표현식
10;
("Hello");

// 식별자 표현식 (선언이 이미 존재한다고 가정)
sum;
person.name;
arr[1];

// 연산자 표현식
10 + 20;
sum = 10;
sum !== 10;

// 함수, 메서드 호출 표현식 (선언이 이미 존재한다고 가정)
square();
person.getName();

5.4 문

문(statement)은 프로그램을 구성하는 기본 단위이자 최소 실행 단위다. 문의 집합으로 이루어진 것이 프로그램이며, 문을 작성하고 순서에 맞게 나열하는 것이 프로그래밍이다.

문은 여러 토큰으로 구성된다. 토큰(token)은 문법적인 의미를 가지며, 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소를 의미한다.

문은 선언문, 할당문, 조건문, 반복문 등으로 구분할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 변수 선언문
var x;

// 할당문
x = 5;

// 함수 선언문
function foo() {}

// 조건문
if (x > 1) {
  console.log(x);
}

// 반복문
for (var i = 0; i < 2; i++) {
  console.log(i);
}

5.5 세미콜론과 세미콜론 자동 삽입 기능

세미콜론(;)은 문의 종료를 나타낸다. 자바스크립트 엔진은 소스코드를 해석할 때, 문의 끝이라고 예측되는 지점에 세미콜론을 자동으로 붙여주는 세미콜론 자동 삽입 기능(ASI; Automatic Semicolon Insertion)을 암묵적으로 수행한다. 대신, 중괄호로 묶은 코드 블록({ … }) 뒤에는 붙이지 않는다. 코드 블록 자체가 자체 종결성을 갖기 때문이다.

하지만, 세미콜론 자동 삽입 기능이 원하는 대로 동작하지 않는 경우도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function foo() {
  return;
  {
  }
  // ASI 동작 결과 => return; {};
  // 개발자의 예측 => return {};
}

console.log(foo()); // undefined

var bar = (function () {})(function () {})();
// ASI 동작 결과 => var bar = function() {}(function() {})();
// 개발자의 예측 => var bar = function() {}; (function() {})();
// TypeError: (intermediate value)(...) is not a function

5.6 표현식인 문과 표현식이 아닌 문

표현식인 문과 표현식이 아닌 문을 구별하는 가장 간단하고 명료한 방법은 변수에 할당해 보는 것이다. 표현식인 문은 값으로 평가되므로 변수에 할당할 수 있다. 하지만 표현식이 아닌 문은 값으로 평가할 수 없으므로 변수에 할당하면 에러가 발생한다.

1
2
3
4
var foo = var; // SyntaxError: Unexpected token var

var foo = x = 100;
console.log(foo); // 100

완료 값(completion value)

크롬 개발자 도구에서 표현식이 아닌 문을 실행하면 언제나 undefined를 출력한다. 이를 완료 값이라 한다.

1
2
3
4
5
6
var foo = 10; // undefined
if (true) {
} // undefined

100 + foo; // 110
foo = 100; // 100
This post is licensed under CC BY 4.0 by the author.

프로그래머스 Level 2 - 문자열 압축 (Javascript)

프로그래머스 Level 1 - 로또의 최고 순위와 최저 순위