04장 변수
사람은 계산과 기억을 두뇌에서 하지만 컴퓨터는 CPU를 사용해 연산을 하고, 메모리를 사용해 데이터를 기억한다.
메모리는 데이터를 저장할 수 있는 메모리 셀의 집합체다.
각 셀은 고유의 메모리 주소를 갖는다. 메모리 주소는 메모리 공간의 위치를 나타내고, 0부터 시작해 메모리 크기만큼 정수로 표현된다.
컴퓨터의 모든 데이터는 데이터 종류와 상관없이 2진수로 이루어져 있다!
10 + 20 이라는 연산을 했다는 것은 그 연산 결과가 필요하고 이를 사용해 무언가 하겠다는 의도가 있다는 것이다.
하지만 메모리 주소를 통해 값에 접근하는 것은 올바른 방법이 아니다.
그래서 필요한 것이 변수인데, 변수는 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름을 말한다.
변수에 값을 저장하는 것을 할당이라 하고, 변수에 저장된 값을 읽어 들이는 것을 참조라 한다.
변수 이름을 사용해 참조를 요청하면 자바스크립트 엔진은 변수 이름과 매핑된 메모리 주소를 통해 메모리 공간해 접근해서 저장된 값을 반환한다.
변수 이름을 식별자라고도 한다. 식별자는 어떤 값을 구별해서 식별할 수 있는 고유한 이름을 말한다.
식별자는 값이 아니라 메모리 주소를 기억한다. 식별자로 값을 구별해서 식별한다는 것은 식별자가 기억하고 있는 메모리 주소를 통해 메모리 공간에 저장된 값에 접근할 수 있다는 의미이다. 즉, 식별자는 메모리 주소에 붙인 이름이다!
식별자라는 용어는 변수 이름에만 국한해서 사용하지 않고 변수, 함수, 클래스 등의 이름은 모두 식별자이다. 즉, 메모리 상에 존재하는 어떤 값을 식별할 수 있는 이름은 모두 식별자라고 부른다.
변수, 함수, 클래스 등의 식별자는 네이밍 규칙을 준수해야 하고, 선언에 의해 자바스크립트 엔진에 식별자의 존재를 알린다.
변수 선언이란 변수를 생성하는 것이다.
(값을 저장하기 위한 메모리 공간을 확보하고 변수 이름과 확보된 메모리 공간의 주소를 연결해서 값을 저장할 수 있게 준비)
변수를 사용하려면 반드시 선언이 필요하고, 변수를 선언할 때는 var, let, const 키워드를 사용한다.
var score;
이렇게 변수를 선언만 하고 아직 값을 할당하지 않았을 때에, 확보된 메모리 공간은 비어있는 것이 아니라 자바스크립트 엔진에 의해서 undefined라는 값이 암묵적으로 할당되어 초기화된다!
변수 선언은 2단계에 거쳐 수행한다.
🧐 변수 이름을 비롯한 모든 식별자는 실행 컨텍스트에 의해 등록된다. 실행 컨텍스트는 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위해 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역이다. 자바스크립트 엔진은 실행 컨텍스트를 통해 식별자와 스코프를 관리한다.
일반적으로 초기화란 변수가 선언된 이후 최초로 값을 할당하는 것을 말하는데, 초기화 단계를 거치지 않으면 확보된 메모리 공간에는 이전에 다른 애플리케이션이 사용했던 값이 남아있을 수 있다. 이러한 값을 쓰레기 값(garbage value)이라 한다.
console.log(score); // undefined
var score;
변수 선언보다 참조를 먼저 했을 때, 참조 에러가 발생할 것 같지만 undefined가 출력된다.
변수 선언이 소스코드가 한 줄씩 순차적으로 실행되는 시점인 런타임이 아니라 그 이전 단계에서 먼저 실행되기 때문이다.
자바스크립트 엔진은 변수 선언이 소스코드의 어디에 있든 다른 코드보다 먼저 실행한다.
이렇게 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 것을 변수 호이스팅이라 한다!🐤
변수에 값을 할당할 때는 할당 연산자 =를 사용한다.
변수 선언과 값의 할당의 실행 시점이 다르다.
변수 선언은 소스코드가 순차적으로 실행되는 시점인 런타임 이전에 먼저 실행되지만, 값의 할당은 소스코드가 순차적으로 실행되는 시점인 런타임에 실행된다.
console.log(score); // undefined
var score = 80;
console.log(score); // 80
재할당이란 이미 값이 할당되어 있는 변수에 새로운 값을 또 다시 할당하는 것을 말한다. var 키워드로 선언한 변수는 값을 재할당할 수 있다.
만약 값을 재할당할 수 없어서 변수에 저장된 값을 변경할 수 있다면 변수가 아니라 상수이다.
🧐 가비지 콜렉터
가비지 콜렉터는 애플리케이션이 할당한 메모리 공간을 주기적으로 검사해 더 이상 사용되지 않는 메모리(어떤 식별자도 참조하지 않는 메모리 공간)를 해제하는 기능을 말한다. 이를 통해 메모리 누수를 방지한다.
네이밍 컨벤션은 하나 이상의 영어 단어로 구성된 식별자를 만들 때 가독성 좋게 규정한 명명 규칙이다.
var firstName;
var first_name;
var FirstName;
var strFirstName; // type + identifier
var $elem = document.getElementById('myId'); // DOM 노드
var observable$ = fromEvent(document, 'click'); // RxJS 옵저버블
일반적으로 변수, 함수 이름은 카멜 케이스, 생성자 함수, 클래스 이름은 파스칼 케이스를 사용한다.
05장 표현식과 문
값은 식이 평가되어 생성된 결과를 말한다.
즉 10 + 20 이 평가되어 숫자 값 30을 생성한다.
변수는 하나의 값을 저장하기 위해 확보된 메모리 공간이기 때문에,
var sum = 10 + 20;
sum 변수에 할당되는 것은 10 + 20 이 아닌 평가된 결과인 값 30이다.
값을 생성하는 가장 기본적인 방법은 리터럴을 사용하는 것이다.
리터럴은 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법이다.
리터럴은 사람이 이해할 수 있는 문자(아라비아 숫자, 알파벳, 한글 등) 또는 약속된 기호('', "", ., [], {}, // 등)로 표기한 코드다.
리터럴의 종류
표현식은 값으로 평가될 수 있는 문을 말하는데, 표현식이 평가되면 새로운 값을 생성하거나 기존 값을 참조한다.
var score = 100;
여기서 100은 리터럴이고, 자바스크립트 엔진에 평가되어 값을 생성하므로 리터럴은 그 자체로 표현식이다.
score; // 100
변수 식별자를 참조하면 변수 값으로 평가되는데, 식별자 참조는 값을 생성하지는 않지만 값으로 평가되기 때문에 표현식이다.
표현식은 리터럴, 식별자, 연산자, 함수 호출 등의 조합으로 이루어질 수 있다. 값으로 평가될 수 있는 문은 모두 표현식!🐣
표현식과 표현식이 평가된 값은 동등한 관계(동치)이다.
1 +2는 3과 동치이다.
즉 문법적으로 값이 위치할 수 있는 자리에 표현식도 위치할 수 있다!
문은 프로그램을 구성하는 기본 단위이자 최소 실행 단위이고, 컴퓨터에게 내리는 명령이기 때문에 명령문이라고도 한다.
문의 집합이 프로그램이고 문을 작성하고 순서에 맞게 나열하는 것이 프로그래밍이다.
문은 여러 토큰으로 구성되는데, 토큰은 문법적인 의미를 가지고 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소이다.
var sum = 1 + 2;
// var, sum, =, 1, +, 2가 토큰
문은 선언문, 할당문, 조건문, 반복문 등으로 구분된다.
문의 종료를 나타내기 위해서는 세미콜론(;)을 붙여야 한다.
하지만 코드 블록( {...} ) 뒤에는 세미콜론을 붙이지 않는다.
코드 블록은 언제나 문의 종료를 의미하는 자체 종결성을 갖기 때문!
표현식인 문은 값으로 평가될 수 있는 문이고,
표현식이 아닌 문은 값으로 평가될 수 없는 문이다.
var x;
변수 선언문은 값으로 평가될 수 없기 때문에 표현식이 아닌 문이다.
이것을 구분하는 가장 간단한 방법은 변수에 할당해 보는 것이다.
var foo = var x;
이 변수 선언문은 값으로 평가될 수 없어 표현식이 아닌 문이다.
var x;
x = 100;
이 할당문 x = 100;은 그 자체가 표현식이다.
할당문은 표현식인 문이기 때문에 값처럼 사용할 수 있다.
var foo = x = 100;
console.log(foo); // 100
할당문을 값처럼 변수에 할당하면 이 할당문은 할당된 값으로 평가되어 foo 변수에 100으로 할당된다.
06 데이터 타입
자바스크립트에는 7개의 데이터 타입이 있는데 원시 타입과 객체 타입으로 나뉜다.
C나 자바는 정수와 실수를 구분해 int, long, float, double 등 다양한 숫자 타입을 제공하는데, 자바스크립트는 하나의 숫자 타입만 존재한다.
모든 수를 실수로 처리하고 정수만 표현하기 위한 데이터 타입이 별도로 존재하지 않는다.
세 가지 특별한 값도 표현할 수 있다.
문자열 타입은 텍스트 데이터를 나타내는 데 사용한다.
'', "", ``으로 텍스트를 감싼다.
템플릿 리터럴은 멀티라인 문자열, 표현식 삽입, 태그드 템플릿 등 편리한 문자열 처리 기능을 제공한다.
템플릿 리터럴은 백틱(``)을 사용한다.
일반 문자열 내에서는 줄바꿈이 허용되지 않는다.
줄바꿈 등의 공백을 표현하려면 백슬래시(\ )로 시작하는 이스케이프 시퀀스를 사용해야 한다.
이스케이프 시퀀스
문자열 연결은 연산자 +를 사용해 연결할 수 있는데,
템플릿 리터럴 내에서는 표현식 삽입을 통해 간단히 문자열을 삽입할 수 있다.
var first = 'Ung-mo';
var last = 'Lee';
console.log(`My name is ${first} ${last}.`)
불리언 타입의 값은 참, 거짓을 나타내는 true, false 뿐이다.
undefined 타입의 값도 undefined가 유일하다.
undefined는 개발자가 의도적으로 할당하기 위한 값이 아니라 자바스크립트 엔진이 변수를 초기화할 때 사용하는 값이다.
만약 변수에 값이 없다는 것을 명시하고 싶을 때에는 undefined이 아닌 null을 할당하면 된다.
null 타입의 값도 null이 유일하다.
null은 변수에 값이 없다는 것을 의도적으로 명시할 때 사용한다.
함수가 유효한 값을 반환할 수 없는 경우 명시적으로 null을 반환하기도 한다.
심볼 값은 다른 값과 중복되지 않는 유일한 값이다.
따라서 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 사용한다.
자바스크립트는 객체 기반 언어이고 자바스크립트를 이루고 있는 거의 모든 것이 객체이다.
자바스크립트 엔진은 데이터 타입에 따라 정해진 크기의 메모리 공간을 확보한다. 즉, 변수에 할당되는 값의 데이터 타입에 따라 확보해야 할 메모리 공간의 크기가 결정된다.
모든 값은 데이터 타입을 가지고 메모리에 2진수, 즉 비트의 나열로 저장된다.
데이터 타입이 필요한 이유
C나 자바같은 정적 타입 언어는 변수를 선언할 때 변수에 할당할 수 있는 값의 종류, 즉 데이터 타입을 사전에 선언해야 한다. 이것을 명시적 타입 선언이라고 한다.
정적 타입 언어에서는 변수의 타입을 변경할 수 없고, 타입에 맞는 값만 할당할 수 있다.
자바스크립트는 정적 타입 언어와 다르게 변수를 선언할 때 타입을 선언하지 않는다. 그래서 어떠한 데이터 타입의 값도 자유롭게 할당할 수 있다.
typeof 연산자로 변수에 연산하면 변수의 데이터 타입을 반환한다.
자바스크립트의 변수는 선언이 아닌 할당에 의해 타입이 결정(타입 추론)되고, 재할당에 의해 변수의 타입은 언제든지 동적으로 변할 수 있다.
이러한 특징을 동적 타이핑이라 하고, 자바스크립트를 정적 타입 언어와 구분하기 위해 동적 타입 언어라고 한다.
변수 값은 언제든지 변경될 수 있기 때문에 복잡한 프로그램에서는 변화하는 값을 추적하기 어려울 수 있다. 또 자바스크립트는 개발자의 의도와는 달리 자바스크립트 엔진에 의해 타입이 자동으로 변환되기도 한다.
결국 동적 타입 언어는 유연성은 높지만 신뢰성은 떨어진다.
변수를 사용할 때 주의할 사항