변수 / 메모리 / 메모리 셀 / 데이터 / 메모리 주소 / 할당과 참조 / 변수명 / 식별자 / 선언과 초기화 / 참조 에러 / 호이스팅 / 재할당 / 가비지 콜렉터 / 네이밍 컨벤션
4.1 변수란 무엇인가? 왜 필요한가?
변수
프로그래밍 언어에서 데이터를 관리하기 위한 핵심 개념
why? 어떤 애플리케이션이든 데이터를 입력 → 처리 → 결과 출력의 과정을 통해 데이터를 다루기 때문
JS 엔진의 수식 해석
10 + 9
이런 식을 어떻게 계산할까?
코드 평가(계산) 시 필요 조건
- 10, 9, + 라는 기호의 의미를 알고 있어야 한다. (10과 9는 리터럴, +는 연산자이다.)
- 10 + 9라는 표현식의 의미를 해석(Parsing)할 수 있어야 한다.
메모리
식을 계산하기 위해선, 연산자의 좌우에 존재하는 피연산자를 기억해야 한다.
컴퓨터는 메모리를 이용해 데이터를 기억하고, CPU로 연산하며 각 역할에 따라 부품이 나뉘어 있다.
메모리와 메모리 셀
메모리는 데이터 저장 공간인 메모리 셀의 집합체 → 메모리 셀 하나의 크기: 1byte(8bit)
⇒ 컴퓨터는 메모리 셀 크기인 1바이트 단위로 데이터를 read / write 한다.
각 셀은 고유의 메모리 주소를 가지며, 이 주소는 메모리 공간의 위치를 나타낸다.
→ 주소의 표현: 0부터 시작해 메모리 크기만큼의 정수
컴퓨터는 어떤 데이터의 종류든 상관없이 모든 데이터를 2진수로 저장하고, 처리한다.
메모리에 값이 저장될 땐 임의의 위치(메모리 주소)에 저장되고, 연산 수행 시 CPU는 이 값을 읽어 들인다.
연산 결과로 생성된 숫자 값또한 메모리 상의 임의 메모리 주소에 저장된다. ✔️모든 값은 2진수로 저장된다.
변수의 필요성
저장한 연산 결과를 재사용하기 위해선, 이를 접근할 수 있는 수단이 필요하다.
직접 접근의 위험성
값이 저장된 메모리 공간에 직접 접근하는 것은 치명적 오류를 초래할 수 있다.
⇒ 따라서 JS는 개발자의 직접적인 메모리 제어를 허용하지 않는다.
자바스크립트는 실행 시마다 값이 저장될 메모리 주소가 메모리 상황에 따라 임의로 결정된다.
따라서 동일한 환경이더라도 값이 저장될 메모리 주소의 변경 가능성이 있기에
⇒ 메모리 주소를 통해 값에 직접 접근하는 것은 올바른 방법이라 할 수 없다.
변수
기억하고 싶은 값을 메모리에 저장하고, 저장된 값을 읽어 들여 재사용하기 위해 프로그래밍 언어가 제공하는 메커니즘
하나의 값을 저장하기 위해 확보한 메모리 공간 자체 or 그 메모리 공간 식별을 위해 붙인 이름
⇒ 프로그래밍 언어에서 값을 참조하는 메커니즘이며 값의 위치를 가리키는 상징적인 이름
이 변수는 컴파일러 or 인터프리터에 의해 값이 저장된 메모리 공간의 주소로 치환되어 실행된다.
⇒ 변수로 안전하게 값에 접근 가능 ← 개발자가 직접 메모리 주소를 통해 저장 및 참조 필요 X
변수는 하나의 값을 저장하기 위한 메커니즘으로 여러 개의 값을 저장하고 싶을 땐 여러 개의 변수를 사용해야 한다. 다만, 연관된 여러 개의 값을 그룹화해서 하나의 값처럼 사용할 수 있는데 이는 객체나 배열과 같은 자료구조를 사용하면 된다.
변수의 이름 / 값 / 할당 / 참조
- 변수 이름: 메모리 공간에 저장된 값의 식별 가능한 고유 이름
- 변수 값: 변수에 저장된 값
- 할당: 변수에 값을 저장하는 것
- 참조: 변수에 저장된 값을 읽어 들이는 것
변수명으로 값을 접근하는 과정
- 변수명을 통해 참조를 요청
- JS 엔진은 변수 이름과 매핑된 메모리 주소를 통해 메모리 공간에 접근
- 저장된 값을 반환
변수명의 중요성
변수명은 사람이 이해할 수 있는 언어로 명명하기에 좋은 이름일 때 더 의미를 명확히 할 수 있다.
해당 변수에 어떤 값이 저장되었는지 의미를 파악할 수 있는 변수명은 가독성을 높이는 부수적 효과도 존재한다.
코드는 컴퓨터에게 내리는 명령이자 개발자를 위한 문서다.
따라서 변수 네이밍 시 개발자의 의도가 드러나게 명확함을 담으면 코드의 이해도가 증가하고, 협업과 품질 향상 또한 도움이 된다.
4.2 식별자 (Identifier)
- 변수 이름의 또 다른 표현
- 어떤 값을 구별해서 식별할 수 있는 고유한 이름
- 메모리 공간에 저장된 값을 구별해 식별할 수 있어야 한다.
- 어떤 값이 저장된 메모리 주소 기억 필요
- 식별자가 기억하는 메모리 주소를 통해 메모리 공간에 저장된 값에 접근한다는 의미
- 값이 저장된 메모리 주소와 매핑 관계를 맺으며, 이 매핑 정보 또한 메모리에 저장돼야 한다.
- 식별자는 값이 아니라 메모리 주소를 기억하고 있다는 것이 Point! → 메모리 주소에 붙인 이름이다.
식별자의 다양한 활용
식별자는 변수명뿐만 아니라 함수, 클래스 등의 모든 이름을 의미한다.
메모리 상에 존재하는 어떤 값이든 식별 가능할 땐 모두 식별자라고 부른다.
따라서 모든 식별자는 네이밍 규칙을 준수해야 하며, 선언에 의해 JS 엔진에 식별자의 존재를 알린다.
4.3 변수 선언
- 변수를 생성하는 것을 의미
⇒ 값을 저장하기 위한 메모리 공간 확보 → 변수 이름과 확보된 *메모리 공간의 주소를 연결 → 값을 저장할 수 있게 준비 - 변수 선언에 의해 확보된 메모리 공간은 해제되기 전까지 누구도 해당 공간을 사용할 수 없게 보호되기에 안전한 사용이 가능하다.
- 변수 사용을 위해서 반드시 필요한 것
- 변수 선언용 키워드: var, let, const
*메모리 공간의 주소를 연결하는 것을 name binding이라고 표현한다.
var
*ES6 이전 유일한 변수 선언 *키워드 → ES6 이후 지양하는 키워드지만, 알아둘 필요성이 있다.
var score;
- 변수 선언문
변수 선언 시, 확보된 메모리 공간에는 JS 엔진에 의해 undefined 값이 암묵적 할당되어 초기화 된다. ⇒ JS의 독특한 특징
자바스크립트 엔진의 변수 선언 과정
- 선언 단계: 변수 이름을 등록해 JS 엔진에 변수 존재 알리기
- 초기화 단계: 값을 저장하기 위한 메모리 공간 확보 후 암묵적으로 undefined 할당해 초기화하기
var 키워드 사용 시 변수 선언에서 선언 단계와 초기화 단계가 동시 진행된다. → 값을 할당하지 않아도 undefined란 값을 갖는다.
초기화 단계가 없을 시 문제점
쓰레기 값이 나올 수 있다. → 이전에 다른 애플리케이션에서 사용한 값이 남아있을 수 있다.
메모리 공간 확보 후 값을 할당하지 않은 상태에서 변수 값을 참조하게 되면 쓰레기 값이 나올 가능성이 있다.
⇒ var 키워드는 암묵적인 초기화를 수행하므로 이런 위험으로부터 안전하다.
참조 에러
선언하지 않은 식별자에 접근할 때 발생하는 에러
변수, 함수, 클래스 등 모든 것을 사용하기 이전에 선언부터 해야한다.
*실행 컨텍스트: JS 엔진이 소스코드를 평가 / 실행하기 위해 필요 환경을 제공하고 코드의 실행 결과를 실제 관리하는 영역. 식별자는 여기에 등록되며 JS 엔진은 이를 통해 식별자와 스코프를 관리한다.
*ES5 vs ES6: var의 가장 대표적인 단점은 function scope 단위라는 것.
의도치 않게 전역 변수가 선언되는 심각한 부작용을 초래할 수 있다.
let과 const는 var의 여러 단점을 보완하기 위해 등장하였으며, 우선 var 키워드가 어떤 단점이 있었는지를 알아야 해당 키워드의 도입 이유를 정확히 파악할 수 있을 것이다.
ES6는 ES5의 상위 집합이기에 ES5의 사양도 잘 알아둘 것!
*키워드: JS 엔진이 수행할 동작을 규정한 일종의 명령어, 키워드를 통해 자신이 수행해야 할 약속된 동작을 수행
4.4 변수 선언의 실행 시점과 변수 호이스팅
변수 선언의 실행 시점
변수 선언은 런타임 이전에 먼저 실행된다.
console.log(name); // undefined
var name;
위와 같은 코드에서 콘솔의 출력 결과가 참조 에러가 아닌 undefined가 나오는 이유다.
JS 엔진의 평가 과정
JS 엔진은 제일 먼저 소스코드의 평가 과정을 거치며 소스코드 실행을 위한 준비를 한다.
이때 변수 선언을 포함한 모든 선언문을 소스 코드에서 찾아내 먼저 실행한다.
이 소스코드 평가 과정이 종료되면 모든 선언문을 제외하고 소스코드를 한 줄씩 순차적 실행하는 것이다.
⇒ 따라서 JS 엔진은 변수 선언의 위치와 상관없이 다른 코드보다 먼저 실행된다. 그렇기에 어디서든지 변수 참조가 가능하다.
호이스팅(Hoisting)
변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 JS의 고유 특징
모든 선언문은 런타임 이전 단계에서 먼저 실행되기에 변수 선언뿐 아니라 모든 식별자는 호이스팅 된다.
4.5 값의 할당
할당 연산자
변수에 값을 할당할 때 사용하는 연산자로 =
이다.
우변의 값을 좌변의 변수에 할당하는 형태로 작성한다.
var name;
name = 'minji';
var name = 'minji';
변수 선언과 값의 할당을 따로 분리할 수도 있으며, 두 과정을 하나의 문으로 아래와 같이 단축 표현도 가능하다.
⇒ JS 엔진은 변수 선언과 할당을 단축 표현한다 해도 2개의 문으로 나눠 각각 실행한다는 점을 알 수 있다.
변수 선언과 값 할당의 실행 시점
변수 선언
앞에서 말했듯이 런타임 이전 평가 단계에서 먼저 실행 (호이스팅)
값의 할당
소스코드가 순차적으로 실행되는 시점인 런타임에 실행
console.log(name); // undefined
var name = 'minji'; // 변수 선언 + 값 할당, var name; name = minji; 시에도 동일
console.log(name); // 'minji'
⇒ 변수의 선언과 값의 할당 시점이 다르기에 처음 변수엔 undefined가 할당되어 초기화됨은 동일하다.
값 할당 시 메모리 공간의 변화
값을 할당하게 되면 undefined가 저장된 기존의 메모리 공간을 활용하는 것이 아니라,
새로운 메모리 공간을 확보해 그 공간에 할당 값을 저장한다. → 불변성 유지 및 메모리 관리의 효율성
4.6 값의 재할당
var name = 'minji';
name = 'minhyuk'; // 값의 재할당
var
키워드로 선언한 변수는 값의 재할당이 가능하다.
재할당
현재 변수에 저장 값을 버리고 새로운 값을 저장하는 것
var는 초기 선언 시 undfined로 초기화가 되니, 엄밀히 따지면 처음 값을 할당할 때도 재할당이라 볼 수 있다.
변수
변수에 저장된 값을 다른 값으로 변경하는 재할당이 가능
상수
변수에 저장된 값이 변경 불가능(재할당 불가) ⇒ 한 번만 할당할 수 있는 변수
const
키워드 사용해 선언 가능
값의 재할당 시 과정
- 새로운 메모리 공간을 임의로 확보
- 그 메모리 공간에 새로운 값을 저장
- 이전 값이 새로운 값으로 변경
가비지 콜렉터
이 과정에서 발생한 변수의 이전 값은 어떤 변수도 값으로 갖고 있지 않은 상황이 된다.
이는 어떤 식별자와도 연결되어 있지 않다는 의미와 같다.
이러한 불필요한 값을 자동으로 해제해주는 것이 “가비지 콜렉터”다. → 다만 해제 시기 예측 불가
⇒ 애플리케이션이 할당한 메모리 공간을 주기적으로 검사해 더이상 사용되지 않는 불필요한 메모리를 해제하는 기능 (불필요한 메모리 = 어떤 식별자도 참조하지 않는 메모리 공간)
JS는 가비지 콜렉터를 내장하고 있는 *매니지드 언어로서 이를 통해 메모리 누수를 방지한다.
*매니지드 언어: 메모리 할당 및 해제를 위한 메모리 관리 기능을 언어 차원에서 담당.
언매니지드 언어: 개발자가 명시적으로 메모리 할당 / 해제위해 메모리 제어 기능 제공.
4.7 식별자 네이밍 규칙
식별자
어떤 값을 구별해서 식별해낼 수 있는 고유한 이름
네이밍 규칙 준수 필요
식별자 네이밍 규칙
- 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어, 달러 기호를 포함 가능
- 특수문자를 제외한 문자, 언더스코어, 달러 기호로 반드시 시작해야 한다.
- *예약어는 식별자로 사용할 수 없다.
*예약어: class, const, this 등 프로그래밍 언어에서 사용되고 있거나 사용될 예정인 단어를 의미
var person, $elem, _name, first_name, val1
→ 가능
var 1st_name, first-name, this
→ 불가능
대소문자 구분
JS는 대소문자를 구별하기에 firstName, FIRSTNAME, finstname
등은 모두 다 다른 변수로 취급된다.
좋은 변수의 이름
변수의 존재 목적을 쉽게 이해할 수 있게, 의미를 명확히 표현한 것 → 코드 가독성 상승
변수 선언에 별도 주석 없이 변수의 존재 목적을 명확히 드러내야 한다.
네이밍 컨벤션
하나 이상의 영단어로 구성된 식별자를 만들 때 가독성 좋게 단어를 한눈에 구분하기 위해 규정한 명명 규칙
JS에선 변수나 함수명에는 camelCase, 생성자 함수나 클래스 이름에는 PascalCase를 사용한다.
→ ES 사양에 정의된 객체와 함수들도 모두 이 네이밍 컨벤션을 다르고 있기에 코드 전체 가독성을 높이기 위해선 이를 따르는 것이 유리하다!
이외에 snake_case, typeHungarianCase는 다른 네이밍 컨벤션에서 자주 사용된다.
'FrontEnd' 카테고리의 다른 글
07. 연산자 (0) | 2025.03.04 |
---|---|
03. 자바스크립트 개발 환경과 실행 방법 (1) | 2025.02.22 |
React & Spring Boot 연동해보기 (2) | 2025.02.19 |