책과 강연/모던 자바스크립트 DeepDive

모던 자바스크립트 Deep Dive 4장 : 변수

데비시 2023. 3. 31. 15:37

변수의 개념

사람과 달리 컴퓨터는 CPU를 이용하여 연산하고, 메모리를 사용하여 데이터를 기억한다.

메모리

- 메모리는 데이터를 저장할 수 있는 메모리 셀의 집합체이다. 메모리 셀 하나의 크기는 1byte(8bit)이며, 컴퓨터는 메모리 셀의 크기, 즉 1바이트 단위로 데이터를 저장하거나 읽는다.

- 각 셀은 그래서 바이트 단위로 고유의 메모리 주소를 갖는다. 예를 들어서, 4GB의 경우 4,294,967,295(0x00000000 ~0xFFFFFFFF)의 주소를 가진다.

- 모든 데이터는 2진수로 저장된다. 이 저장된 메모리를 CPU에서 읽어서 연산을 수행하고 그 결과를 임의의 위치에 저장한다.

  => 여기서 문제가 생긴다. 우리는 이 연산 결과를 재사용할 수 없다. 이 결과는 임의의 장소에 저장되었고, 이를 접근하고 싶다면 메모리주소를 통해서만 접근할 수 있다. 하지만, JS는 메모리 주소를 통한 직접적인 메모리 제어를 허용하지 않는다. 왜냐하면, 이는 치명적 오류를 발생시킬 가능성이 매우 높아서 위험하기 때문이다.

 

따라서, 프로그래밍 언어는 기억하고 싶은 값을 메모리에 저장하고 읽어들일 수 있는 메커니즘을 제공하는데 이를 변수라 한다.

 

 

※ 실제 저장의 최소단위는 1bit로 0이냐 1이냐로 저장하지만, 이 경우 너무 활용도가 떨어지기때문에, 아스키코드를 담을 수 있는 1byte(8bit)가 메모리 셀의 크기가 된다.

 

※ 0x는 16진수임을 알려주는 접두사이다.

 

 

변수

- 하나의 값을 저장하기 위해 확보한 메모리 공간 또는 메모리 공간의 이름으로 값의 위치를 가리키는 상징적인 이름이다.

- 컴파일 또는 인터프리터에 의해서 이 변수는 메모리 주소 값으로 치환되어서 값에 접근할 수 있다.

- 변수의 구성 요소

- 변수명 : 변수를 식별할 수 있는 고유한 이름

- 변수값 : 변수에 저장되어 있는 값

- 할당(assignment) : 변수에 값을 저장하는 것

- 참조(reference) : 변수에 저장된 값을 읽는 것

- 변수명을 잘 지으면 가독성이 올라간다. 심사숙고해서 짓도록 하자.

 

 

식별자

 

- 어떤 값을 구별해서 식별할 수 있는 고유한 이름.

- 이름과 메모리 주소를 매핑한다.

- 대표적으로 변수명이 있지만, 변수명뿐 아니라 함수, 클래스 모두 식별자이다.

- 아래 네이밍 규칙을 준수해야하며, 선언에 의해서 자바스크립트 엔진에 식별자의 존재를 알릴 수 있다.

변수의 선언

- 변수를 생성하는 것 = 메모리 공간을 확보(allocate)하고 주소를 연결(name binding)하는 것

- 확보를 해제(release)하기 전에는 누구도 확보된 메모리 공간을 사용할 수 없도록 보호한다.

- 선언키워드로는 var, let ,const 가 있다.

var

var score

- var은 사실 ES5 때 사용하던 문법으로, 해당 키워드의 문제를 극복하고자 ES6에서 let, const가 출시되게 되었다.

- 위처럼 선언 키워드 이후에, 변수명을 적으면 변수가 선언된다. (1단계 : 선언)

- 위처럼 값이 할당 되지 않으면, undefined가 기본값으로 할당되어 초기화된다. (2단계 : 초기화)

  => 초기화를 하는 이유는, 이전에 다른 애플리케이션에서 사용했던 값이 남아있을 수 있기 때문이다. 이를 우리는 쓰레기 값(garbage value)라 한다.

  => 왜 초기값을 안 지우냐면, 다시 이를 비우는 것이 상당한 코스트가 들기 때문이다.

- ReferenceError(참조 에러)는 변수를 자바스크립트 엔진에서 찾을 수 없다는 에러이다.

호이스팅

console.log(score);

var score;

- 자바스크립트는 인터프리터에 의해서 한 줄씩 순차적으로 실행된다.

- 위 코드는 에러가 날 거 같지만, 발생하지 않고 제대로 출력된다. 이유는 변수 선언이 런타임(인터프리터가 한 줄씩 읽는 시점)이 아니라 그 이전 단계에서 먼저 실행되기 때문이다.

- 실행 전 준비 단계인 소스코드의 평가 단계에서, 모든 선언문을 찾아내서 먼저 실행한다. 그리고 이 평가 과정이 끝나면, 선언문을 제외한 소스코드를 한 줄씩 순차적을 실행한다.

- 이렇게 선언문을 먼저 실행시키는 것을 호이스팅이라 한다.

할당

console.log(score) // undefined

var score // 선언
score = 80 // 할당
// var score = 80; 선언 + 할당 한 번에

console.log(score) // 80

- 선언과 할당은 다르다. 코드로는 동시에 적을 수 있지만, 선언은 호이스팅에서 먼저 실행되고, 할당은 런타임 단계에서 실행된다.

- 선언은 먼저 되나 변수 값 할당은 런타임에 실행되기에, 첫 번째와 마지막 score는 다른 결과가 나온다.

- 이 흐름에서 score는 undefined 에서 80으로 재할당된다. 이 때, 같은 메모리의 값이 바뀌는 게 아니라 전혀 다른 메모리 공간을 확보하여서 그 곳에 값을 넣는다.

  => 이는 자바스크립트는 타입을 추론하기 때문에, 적절한 메모리 공간을 확보하고, 이전 값을 참조하는 다른 변수에 영향을 주지 않기 위해서임

  => 가비지 콜렉터(garbage coolector)는 할당 후 해제되지 않아서 낭비되는 메모리의 할당을 해제하는 기능으로 식별자가 없는 메모리를 찾아서 할당을 해제하고 이를 통해서 메모리 누수를 막는다.

메모리 누수(memory leak) 현상은 컴퓨터 프로그램이 필요하지 않은 메모리를 계속 점유하고 있는 현상이다.

 

※ 언매니지드 언어 vs 매니지드 언어 : 메모리 관리를 직접 지원하는 언어 (C)와 지원하지 않는 언어(JS)가 있다. 이를 매니지드, 언매지니드 언어로 구분하는데, 메모리 관리가 가능한 언어는 최적화가 가능하나 역으로 최적화가 실패할 수도 있다. 매니지드언어는 완벽한 최적화는 어렵지만, 일정량 이상의 생산성과 성능을 가져갈 수 있다.

 

 

 

식별자 네이밍 규칙

- 식별자는 _, $, 문자, 숫자만 허용한다.

 

- 숫자로 시작할 수 없다.

- 예약어 (let, return 등)는 식별자로 사용할 수 없다.

 

※ 카멜케이스(firstName), 스네이크케이스(first_name), 파스칼케이스(FirstName), 헝가리언케이스( type + identifier), 케밥케이스(first-name) 등 다양한 네이밍 컨벤션이 있다. 이 중 ES에서는 카멜과 파스칼을 사용하므로, 둘을 따르는 것이 유리하다.