🔰변수
변수란 무엇인가? 왜 필요한가?
변수는 프로그래밍 언어에서 데이터를 관리하기 위한 핵심 개념이다.
메모리는 데이터를 저장할 수 있는 메모리 셀의 집합체로, 메모리 셀 하나의 크기는 1B이다. 컴퓨터는 메모리 셀 단위로 데이터를 write & read 한다. 각 셀은 고유의 메모리 주소를 갖는데, 이는 메모리 공간의 위치를 의미한다. 컴퓨터는 모든 데이터를 2진수로 처리하므로, 메모리에 저장되는 모든 데이터는 데이터 종류와 상관없이 모두 2진수로 저장된다.
프로그래밍 언어는 기억하고 싶은 값을 메모리에 저장하고 저장된 값을 읽어 들여 재사용하기 위해 변수를 제공한다. 메모리 주소로 개발자가 직접 접근하는 것은 운영체제가 관리하는 값을 변경하는 등의 치명적인 오류를 발생시킬 수 있으므로 허용하지 않는다.
프로그래밍 언어의 컴파일러 또는 인터프리터에 의해 변수는 값이 저장된 메모리 공간의 주소로 치환되어 실행된다.
변수가 가리키는 메모리 공간에 저장된 값을 식별하는 고유한 이름을 변수명이라 하고, 저장된 값을 변수 값이라 한다.
변수에 값을 저장하는 것을 할당(대입, 저장), 값을 읽어 들이는 것을 참조라 한다.
변수명으로 참조를 요청하면 자바스크립트 엔진은 변수 이름과 매핑된 메모리 주소를 통해 메모리 공간에 접근해서 저장된 값을 반환한다.
변수명으로 변수 값의 의미를 명확히 하여 가독성, 협업과 품질 향상에 도움을 줄 수 있다.
식별자
값을 구별해서 식별할 수 있는 고유한 이름이다. 변수, 함수, 클래스명은 모두 식별자다.
식별자와 값이 저장되어 있는 메모리 주소는 매핑되어 있고, 이 매핑 정보도 메모리에 저장된다.
식별자는 값이 아니라 메모리 주소를 기억하고 있다. 즉, 메모리 주소에 붙은 이름이다.
자바스크립트 엔진은 선언을 통해 식별자의 존재를 판단한다.
변수 선언
변수를 생성하는 것을 말한다. 메모리 공간을 확보하고 변수명과 확보된 메모리 공간의 주소를 연결해서 값을 저장할 수 있게 준비하는 것이다. 확보된 메모리 공간은 release되기 전까지는 보호된다.
JS에서는 var, let, const 키워드로 변수를 선언한다. 선언하지 않은 식별자에 접근하면 ReferenceError가 발생한다.
🍎 키워드
자바스크립트 엔진이 수행할 동작을 규정한 일종의 명령어다. 키워드를 만나면 약속된 동작을 수행한다.
var로 선언하면 확보된 메모리 공간에는 자바스크립트 엔진에 의해 undefined가 암묵적으로 할당되어 초기화된다. 다시 말하면 선언 단계와 초기화 단계가 동시에 진행된다. 초기화 단계를 거치지 않으면 garbage value가 남아있을 수 있다.
변수 선언의 실행 시점과 변수 호이스팅
JS에서 변수 선언을 포함한 모든 선언문은 런타임이 아니라 그 이전 단계인 소스코드 평가 과정에서 실행된다. 평가 과정이 끝나면 선언문을 제외한 소스코드를 한 줄씩 순차적으로 실행한다. 즉, 변수 선언은 소스코드 상의 위치에 상관없이 먼저 실행된다.
변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 현상을 변수 호이스팅이라고 한다. var, let, const function, function*, class 키워드로 선언한 모든 식별자는 호이스팅된다.
값의 할당
할당 연산자(=)를 사용하여 변수에 값을 할당한다. 변수 선언과 값의 할당을 하나의 문으로 단축 표현해도 자바스크립트 엔진은 두 개의 문으로 나누어 각각 실행한다.
값의 재할당
값을 재할당할 수 없어서 변수에 저장된 값을 변경할 수 없다면 상수라 한다. const 키워드로 선언한 변수는 재할당이 금지된다.
값을 재할당 할 때는 새로운 메모리 공간을 확보해서 새 값을 저장한 뒤, 변수와 연결한다. 어떤 식별자와도 연결되어 있지 않은 값들은 가비지 콜렉터에 의해 메모리에서 자동 해제된다. 언제 해제될지는 예측할 수 없다.
🍎 가비지 콜렉터
메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리를 release하는 기능이다. 자바스크립트는 매니지드 언어로서 가비지 콜렉터를 통해 메모리 누수를 방지한다.
managed language | unmanaged language |
메모리 할당 및 해제를 하는 메모리 관리 기능을 언어 차원에서 담당하고, 개발자의 직접적인 메모리 제어를 허용하지 않는다. 메모리 관리를 개발자의 역량에 의존하지 않아도 되어 생산성을 확보할 수 있다는 장점이 있지만, 성능 면에서 손실이 발생할 수 있다. | 개발자가 명시적으로 메모리를 할당하고 해제하도록 malloc 또는 free와 같은 저레벨 메모리 제어 기능을 제공한다. 개발자의 역량에 따라 최적의 성능을 확보할 수 있지만, 치명적 오류를 발생시킬 가능성도 있다. |
식별자 네이밍 규칙
자바스크립트에서는 일반적으로 변수나 함수의 이름은 카멜 케이스, 생성자 함수나 클래스의 이름은 파스칼 케이스를 사용한다.
ES5부터 식별자를 만들 때 유니코드 문자를 허용한다.
🔰표현식과 문
값
표현식이 평가되어 생성된 결과를 말한다.
모든 값은 데이터 타입을 가지고 메모리에 2진수로 저장된다. 같은 2진수여도 데이터 타입에 따라 다르게 해석될 수 있다.
리터럴
사람이 이해할 수 있는 문자 또는 기호를 사용해 값을 생성하는 표기법이다. 런타임에 리터럴이 평가되면 값을 생성한다.
표현식
값으로 평가될 수 있는 문이다. 표현식이 평가되면 새로운 값을 생성하거나 기존값을 참조한다. 표현식은 다른 표현식의 일부가 되어 새로운 값을 만들어 낼 수 있다.
표현식과 그 표현식이 평가된 값은 동치다. 즉, 값이 위치할 수 있는 자리에는 동치인 표현식이 위치할 수 있다.
문
프로그램을 구성하는 기본 단위이자 최소 실행 단위다. 명령문이라고도 부른다. 선언문, 할당문, 조건문, 반복문 등이 있다.
문은 여러 토큰으로 구성된다. 토큰이란 문법적 의미를 가진 더 이상 나눌 수 없는 코드의 기본 요소를 의미한다.
세미콜론과 세미콜론 자동 삽입 기능
세미콜론은 문의 종료를 나타낸다.
자바스크립트 엔진은 세미콜론으로 문이 종료한 위치를 파악하고 순차적으로 하나씩 문을 실행한다. 단, 0개 이상의 문을 중괄호로 묶은 코드 블록({...}) 뒤에는 세미콜론을 붙이지 않는다. 코드 블록은 언제나 문의 종료를 의미하는 자체 종결성(self-closing)을 가진다.
자바스크립트 엔진에 세미콜론 자동 삽입 기능(ASI)가 있기 때문에 세미콜론은 생략가능하다. 다만 개발자의 의도와 다른 경우가 있으므로 주의해야 한다.
표현식인 문과 표현식이 아닌 문
표현식은 문의 일부일 수도 있고 그 자체가 문일 수도 있다. 값으로 평가될 수 있는 문은 표현식인 문이고, 그렇지 않으면 표현식이 아닌 문이다. 할당문은 값으로 평가될 수 있으므로 표현식인 문이다.
크롬 개발자 도구에서 표현식이 아닌 문을 실행하면 언제나 완료 값인 undefined를 실행한다. 완료 값은 표현식의 평가 결과가 아니다.
🔰데이터 타입
값의 종류를 말한다. 자바스크립트의 모든 값은 데이터 타입을 갖는다. 원시 타입과 객체 타입으로 분류할 수 있다.
데이터 타입에 따라 확보하는 메모리 공간의 크기와 저장되는 2진수, 읽어 들여 해석하는 방식이 다르다.
숫자 타입
자바스크립트는 하나의 숫자 타입만 존재한다. 숫자 타입의 값은 배정밀도 64bit 부동소수점 형식을 따른다. 모든 수는 실수로 처리된다.
2진수, 8진수, 16진수, 정수를 표현하는 데이터 타입이 없다. 따라서 이 값들을 참조하면 모두 10진수로 해석된다.
Infinity, -Infinity, NaN의 특별한 값도 존재한다.
문자열 타입
텍스트 데이터를 나타낸다. 0개 이상의 16bit 유니코드 문자(UTF-16)의 집합으로 대부분의 문자를 표현할 수 있다.
템플릿 리터럴
멀티라인 문자열, 표현식 삽입, 태그드 템플릿 등 편리한 문자열 처리 기능을 제공한다. 런타임에 일반 문자열로 변환되어 처리된다.
🍎 line feed(\n) & carriage return(\r)
개행 문자는 텍스트의 한 줄이 끝났음을 표시하는 문자 또는 문자열이다. 라인 피드와 캐리지 리턴이 있다.
과거 타자기에서 커서를 제어하는 방식에서 유래했다. 라인 피드는 커서를 정지한 상태에서 종이를 한 줄 올리는 것이고, 캐리지 리턴은 종이를 움직이지 않고 커서를 맨 앞줄로 이동하는 것이다.
현대 컴퓨터 운영체제는 서로 다른 체계의 개행 방식을 사용하므로 다른 운영체제에서 작성한 텍스트 파일은 서로 개행 문자를 인식하지 못한다. 대부분의 텍스트 에디터가 자동 변환 기능을 제공한다.
자바스크립트에서 라인 피드와 캐리지 리턴 모두 개행을 의미하지만 일반적으로 라인 피드를 이용해 개행한다.
불리언 타입
논리적 참과 거짓을 나타내는 true와 false 뿐이다.
undefined 타입
undefined가 유일하다. 자바스크립트에서 undefined는 변수에 값을 할당하여 변수의 실체를 명확히 하지 않은 것을 의미한다. undefined는 개발자가 의도적으로 할당하기 위한 값이 아니라 자바스크립트 엔진이 변수를 초기화할 때 사용하는 값이다. 변수에 값이 없다는 것을 명시하고 싶을 때는 null을 권장한다.
null 타입
null이 유일하다. 변수에 값이 없다는 것을 의도적으로 명시한다. 변수에 null을 할당하는 것은 변수가 이전에 참조하던 값을 더 이상 참조하지 않겠다는 의미다.
함수가 유효한 값을 반환할 수 없는 경우 명시적으로 null을 반환하기도 한다.
심벌 타입
ES6에서 추가된 타입으로, 원시 타입이다. 심벌 값은 외부에 노출되지 않으며 다른 값과 중복되지 않는 유일무이한 값이다. 객체의 유일한 프로퍼티 키를 만들 때 사용한다.
심벌은 리터럴이 없고, Symbol 함수를 호출해 생성한다.
객체 타입
원시 타입 이외의 값은 모두 객체 타입이다.
데이터 타입의 필요성
데이터 타입에 따라 확보해야 할 메모리 공간의 크기가 결정된다. 문자열과 숫자 타입 외에는 ECMAScript 사양으로 명시되어 있지 않으므로 자바스크립트 엔진 제조사의 구현에 따라 확보하는 메모리 공간 크기가 다를 수 있다.
값을 참조하려면 읽어 들여야 할 메모리 공간의 크기를 알아야 한다. 타입에 따라 읽어 들이는 크기가 다르다.
🍎 심벌 테이블
컴파일러 또는 인터프리터는 심벌 테이블 자료 구조를 통해 식별자를 키로 하는 값의 메모리 주소, 데이터 타입, 스코프 등을 관리한다.
메모리에서 읽어 들인 2진수를 해석하는 방식도 데이터 타입에 따라 결정된다.
동적 타이핑
동적 타입 언어 | 정적 타입 언어 |
변수를 선언할 때 타입을 선언하지 않는다. 어떠한 데이터 타입의 값이라도 자유롭게 할당할 수 있다. 값을 할당하는 시점에 변수의 타입이 동적으로 결정되고 변수의 타입을 언제든지 자유롭게 변경할 수 있다(동적 타이핑). 값을 확인하기 전에는 변수의 타입을 확신할 수 없다. 유연성은 높지만 신뢰성은 떨어진다. |
변수를 선언할 때 데이터 타입을 선언한다(명시적 타입 선언). 변수의 타입에 맞는 값만 할당할 수 있다. 컴파일 시점에 타입 체크를 수행하여 런타임에 발생하는 에러를 줄인다. 변수 선언 후에는 변수의 타입을 변경할 수 없다. |
JS 변수는 주의하여 사용해야 한다. 꼭 필요한 경우에 제한적으로 사용하고, 스코프는 최대한 좁게 만든다. 전역 변수는 지양한다. 변수보다는 상수를 사용한다. 변수명을 목적과 의미를 파악할 수 있도록 짓는다.
'독서 > 모던 자바스크립트 Deep Dive' 카테고리의 다른 글
모던 자바스크립트 Deep Dive (16장 ~ 18장) (2) | 2023.03.29 |
---|---|
모던 자바스크립트 Deep Dive (13장 ~ 15장) (0) | 2023.03.28 |
모던 자바스크립트 Deep Dive (10장 ~ 12장) (0) | 2023.03.19 |
모던 자바스크립트 Deep Dive (7장 ~ 9장) (0) | 2023.03.15 |
모던 자바스크립트 Deep Dive (1장 ~ 3장) (0) | 2023.03.09 |