이 포스트는 [모던 자바스크립트 Deep Dive] 서적을 기반으로 정리한 글입니다.
다시 한번 돌아가서,
조금 급한 마음으로 학습을 진행하고, 프로젝트를 진행하느라 예전에 공부했었던 자바스크립트가 가물가물하다. 사실 뭐 얼마나 지났다고 벌써부터 이런건지 당황스럽지만, 인간은 망각의 동물이 아니던가? 체념하고 다시 더 깊숙히 공부를 해보자.
마침 좋은 책이 있어서 이 책을 기반으로 정리하는 식으로 글을 작성해보려 한다. 조금은 간략하게 작성할 수 있겠지만, 추가할 내용이 있으면 추가하고 사실 이 책 하나만 제대로 파고 공부해도, 충분히 자바스크립트에 대하여 다질 수 있을 것이라 생각하여 매일같이 공부를 해보고자 한다.
분량이 많은 편이기에, 길게 잡고 공부를 이어가보자.
4-1. 변수란 무엇인가?
간단한 계산을 한다고 생각할 때, 인간이라면 약속된 기호를 바탕으로 쉬운 계산은 금방 할 수 있을 것이다.
하지만 컴퓨터는 당연히 할 수 있겠지 라는 인간적인 사고를 가지고 접근해서는 안될 것이다. 우리가 마치 당연하다고 여기는 부분 이상까지 생각하여서 구현해주어야 제대로 된 계산을 할 수 있을 것이다.
우리가 간단한 계산을 그냥 암산처리 할 수 있는 이유는, 이미 계산 방법과 숫자들이 머리속에 저장되어 있기 때문이고, 그 결과도 머릿속에 바로 저장이 가능하기 떄문이다. 허나 컴퓨터는 그렇지 않다. 컴퓨터에게는 고유의 저장장소가 필요하다.
컴퓨터는 CPU 를 사용해 연산을 하게 되고, 메모리를 사용해 데이터를 기억한다. 메모리는 데이터를 저장할 수 있는 메모리 셀의 집합체. 하나의 크기는 1바이트(8비트)이며 컴퓨터는 1바이트 기준으로 데이터를 저장하거나 읽는다.
그리고 이러한 메모리 셀들은 각각의 고유한 메모리 주소를 가지게 된다. 모든 값은 2진수로 저장이되며, 이떄의 메모리 주소는 메모리 셀의 공간을 가리킨다.
만일 10이라는 숫자와 20이라는 숫자, 그리고 그것의 합산 30이라는 숫자가 있을 때, 3가지 숫자 모두 각각 다른 메모리 공간안에 할당이 된다. 그렇다면 이 결과값인 30이라는 숫자를 재사용하기 위해서는 어떻게 해야할까.
메모리에는 각각의 주소가 할당되어있기 때문에, 이 주소를 통해 접근하는 방식을 생각할 수 있겠다. 허나, 메모리 주소를 통해 값에 직접 접근하는 것은 치명적인 오류를 발생시킬 가능성이 높은 매우 위험한 일이다. 만일 우리가 메모리 주소에 접근이 가능하다고 할 지라도, 값이 저장될 메모리 주소는 코드가 실행될 때 메모리의 상황에 따라 임의로 결정된다고 한다.
직접 접근하는 방법은 위험하지만, 기존에 사용했던 값을 재사용하고 싶다. 그렇다면 무슨 방법이 있을까...
이러한 고민에 대한 해답으로 변수라는 메커니즘을 제공한다.
변수(variable)는 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 불린 이름을 말한다.
즉, 값을 저장하고 참조하는 메커니즘이자 값의 위치를 가리키는 상징적인 이름! 우리가 변수를 통해 값에 접근하려 시도하면, 프로그래밍 언어의 컴파일러 혹은 인터프리터는 알아서 주소값으로 치환시켜 실행된다.
var result = 20 + 10;
이렇게 result 라는 변수이름을 결과값 30이 저장될 메모리의 주소에 붙이는것이다.
용어를 좀 더 확인할 필요가 있는것이, 변수에 값을 저장하는 것을 할당(대입, 저장) 한다고 하며, 값을 읽어 들이는 것을 참조 한다고 한다.
4-2. 식별자
변수 이름을 식별자라고도 하는데
식별자는 어떤 값을 구별해서 식별할 수 있는 고유한 이름을 말한다.
의미적으로 봤을 때 변수와 일맥상통한다. 값은 메모리 공간에 저장되어있고, 식별자는 메모리 공간에 저장되어있는 어떤 값을 구별해서 식별해야한다. 우리가 변수를 선언하고 할당하는 것은 결국은 다시 참조하기 위함이기에, 정확한 값을 의도한대로 가져올 수 있어야 한다.
식별한다는 것은 구별짓는다는 것과 같기에, 비단 변수에만 해당하는 용어는 아니다. 예를 들어 변수, 함수, 클래스 등의 이름은 모두 식별자이다.
4-3. 변수 선언
변수를 선언한다는 것은 변수를 생성하는 것을 의미한다. 값을 저장하려면 메모리 공간이 필요하다고 앞에서 설명했었다. 즉, 내가 변수를 생성하기 위해서는 당연하게도 메모리의 공간이 필요하다. 만일 공간이 없다면 당연하게도 값을 저장할 수 없을 테니 말이다. 변수 선언에 의해 확보된 메모리 공간은 확보가 해체되기 전까지는 누구도 확보된 메모리 공간을 사용할 수 없도록 보호되므로 안전하게 사용할 수 있다.
이떄, 변수를 사용하려면 반드시 선언이 필요하다. 그냥 이름만 써서 사용할 수 있는게 아니라 var, let, const 키워드를 사용해서 선언을 해주어야 한다. (함수 스코프를 제공하는 var 에는 한계가 있어서 ES6 부터 let, const 가 등장. 추후 자세히)
// BAD
result = 10 + 20;
//Good
let result = 10 + 20;
우선 변수를 선언하는 것부터 살펴보자.
var score; // 변수 선언
위 선언문은 변수 이름을 등록하고 값 을 저장할 메모리 공간을 확보한다. 여기서 우린 score 변수에 값을 할당하지 않았다. 그렇다면 메모리공간에는 아무것도 없는 상태로 유지되는것인가?
자바스크립트는 특이하게도 변수값이 할당되지 않았을 때는 undefiend 라는 값이 암묵적으로 할당되어 초기화된다.
초기화? 초기화는 무슨 말인가. 처음 나오는 단어인데, 이는 자바스크립트의 성질과 관련이 있다. 자바스크립트는 변수를 생성할 때 기본적으로 2단계를 먼저 거치게 된다.
- 선언 단계 : 변수 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.
- 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefiend 를 할당해 초기화 한다.
이렇게 2단계를 거쳐서 수행하게 된다. 이처럼 초기화는 변수가 선언된 이후 최초로 값을 할당하는 것을 말한다. 그렇다면 왜 초기화를 진행하는 것일까? 만일 초기화를 진행하지 않는다면, 예전에 사용하였던 값이 남아있을 수 있다.(이를 쓰레기값이라 한다).
근데 위에서 계속 변수를 누군가에게 알린다고 설명하고 있다. 하긴 변수를 생성했는데 이를 누구는 알고 있어야 하지 않겠는가? 그렇다면 이러한 변수들은 어디에 등록이 되는 것일까?
변수 이름을 비롯한 모든 식별자는 실행 컨텍스트에 저장이 된다. 실행 컨텍스트(execution context)는 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위해 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역이다.
4-4. 변수 선언의 실행 시점과 변수 호이스팅
console.log(score); // undefined
var score;
변수를 선언하지 않고 변수를 불러오게 되면, 참조 오류가 발생하게 된다. 그렇다면 위의 코드는 에러가 발생해야 정상이지 않는가?
변수의 참조가 변수의 선언보다 위에 적혀있다. 자바스크립트의 인터프리터는 한줄씩 순차적으로 실행되기 떄문에, console.log(score); 가장 먼저 실행되고 순차적으로 다른 코드를 실행한다. 그러면 오류가 발생해야 하는데 그렇지 않다.
이유는 변수를 선언하는 단계가 소스코드를 한 줄씩 순차적으로 실행되는 시점(런타임) 전 단계이기 때문이다.
자바스크립트는 런타임에 들어가기 전에 선언된 식별자들을 먼저 찾아서 실행한다. 그 다음 런타임이 시작되면 모든 선언문을 제외하고 나머지 코드를 한 줄씩 순차적으로 실행한다. 이 말은 변수 선언이 어느 위치에 있던 먼저 실행된다는 의미이다. 그래서 위의 코드에서 undefined 가 참조오류 대신 출력되는 것이다.
이처럼 마치 변수선언들이 모두 소스코드 위로 끌어 올려진 것처럼 동작하는 자바스크립트의 고유의 특징을 변수 호이스팅(variable hoisting) 이라고 한다.
변수선언이라고 했지만 사실 선언되는 모든 식별자는 호이스팅이된다.
4-5. 값의 할당
변수에 값을 할당할때는 할당 연산자 '=' 를 사용한다.
var score;
score = 80;
var score = 80; // 한줄에 가능
보통 한줄로 할당까지 표현하는 편인데, 설사 한줄로 표현되어있다 한들 2개의 문으로 나누어 각각 실행한다.
나누어 실행? 나누어 실행한다는 의미는 변수의 선언과, 변수값의 할당이 서로 다른 단계에서 진행한다는 의미이다. 이는 중요한 의미를 지니는데, 앞에서 모든 식별자 선언은 런타임 이전 단계에서 실행된다고 하였다. 허나, 변수값을 할당하는 과정은 소스코드가 순차적으로 실행되는 런타임에 실행된다.
console.log(score); // undefined
var score;
score = 80;
console.log(score); // 80;
위 코드의 출력값이 저렇게 나오는 것을 이젠 알 수 있을 것이다. 값의 할당은 동기적인 순서로 이루어 지기 때문에, 맨 위 콘솔창에는 값이 할당이 되지 않아 undefined 가 나오게 되고, 이후 값이 선언 된 후에는 선언된 값을 출력한다. 지금은 선언과 할당을 나누어놔서 좀 더 이해가 쉬웠는데, 햇갈리지 말아야하는 점은 아래 코드다
console.log(score); // undefined;
var score = 80;
console.log(score); // 80
한줄이다 보니 마치 선언과 동시에 할당이 될것이라 판단이 되긴하지만, 결과는 그렇지 않다는 점을 다시 명심하자.
변수를 선언할때는 선언단계와 초기화단계 순으로 진행된다고 하였다. 그렇다면 초기화 단계에서는 undefined 를 할당한다고 하였는데, 어찌보면 80이라는 숫자는 재할당이라고 생각해도 될 것이다. 이렇게 할당이 될떄 기존의 메모리 공간에서 값을 교체하는거겠지 라고 생각하였는데, 그것이 아니라 undefined 가 있는 공간이 아닌 새로운 공간에 저장을 한다. (추후 이런 쓰레기값은 자바스크립트 엔진에 의해 알아서 삭제된다. 삭제 시점은 모른다.)
4-6. 값의 재할당
변수가 선언이 될 떄 초기화 과정에서 이미 첫 할당이 이루어지기에, 이후 값의 할당을 하는 것이니 모든 할당과정은 재할당이라 할 수 있겠다만, 일단은 아래 코드와 같은 상황을 일반적으로 재할당한다고 한다.
var score = 80;
score = 100;
재할당은 변수에 저장된 값을 다른 값으로 변경한다. 값이 변하기 때문에 변수라 칭하는 것이다. 만일 값이 변하지 않는다면 이를 부르는 말로는 변수가 아니라 상수(constant) 라고 부른다. 물론 어차피 변수가 선언될 때 한번 값이 초기화 되고 그 다음 할당되는 것이라, 더 정확하게 상수를 표현하자면 딱 한번 값의 할당할 수 있는 변수 라고 하면 되겠다.
앞에서 값을 할당할 때마다 메모리 공간을 바꿔서 저장한다는 것을 설명했고, 쓰레기 값을 처리하는 것도 언급했었는데, 쓰레기값을 처리하는 엔진을 가비지 콜렉터라 한다.
가비지 콜렉터가 알아서 메모리를 관리를 해주는데, 여기서 관리해준다는 것에 초점을 맞춰보자. 프로그래밍 언어는 메모리 관리 방식에 따라 언매니지드 언어와 매니지드 언어로 분류할 수가 있는데, 자바스크립트는 예상하였겠지만 매니지드 언어다.
매니지드 언어의 특징은 메모리의 할당 및 해제를 위한 메모리 관리 기능을 사용자가 접근하지 못한다는 점에 있다. 이러한 부분은 언어 차원에서 알아서 관리하기 때문에, 사용의 편리성이 있지만 사용자에 의한 최적화를 시킬 수 없다는 단점이 있다.
4-7. 식별자 네이밍 규칙
식별자는 고유한 이름을 말하는 것이기에 규칙이 있는데,
- 식별자는 특수문제를 제외한 문자, 숫자, 언더스코어(_), 달러 기호($) 를 포함할 수 있다.
- 단, 식별자는 숫자로 시작하는 것을 허용하지 않는다
- 예약어는 식별자로 사용할 수 없다.
예약어라면 프로그래밍 언어에서 미리 사용되는, 이를 테면 await, break, false 등등을 뜻한다.
이런 기본적인 규칙 외에도 변수명을 지을 때는 사용자가 변수명으로서 현재 값이나 함수 등이 어떠한 역할을 하는지 알 수 있어야 한다. 이런 부분을 최대한 고려하면서 변수명을 지어보자.
'Programing > Javascript' 카테고리의 다른 글
[Deep Dive] 제어문 (0) | 2022.10.21 |
---|---|
[Deep Dive] 연산자 (0) | 2022.10.19 |
[Deep Dive] 데이터 타입 (2) | 2022.10.07 |
[Deep Dive] 표현식과 문 (0) | 2022.10.06 |
웹페이지 내 다크모드 (0) | 2022.06.04 |