JavaScript 변수

업데이트:

모든 프로그래밍 언어가 그렇듯이 자바스크립트도 변수로 값을 저장하고 또 이 값을 활용하여 여러가지 프로그래밍적인 처리를 한다. 이때 이 변수는 어떤값을 저장한다 라고 쉽게 표현할수도 있지만 정확하게 표현하자면 어딘가에 존재하는 메모리영역에 값이 저장되고 그 값이 저장된 메모리의주소값을 변수가 가르키고 있다라고 볼 수 있다. (이 개념은 CS50 에서 C 언어로 프로그래밍 기초에 대해서 설명하는것에 매우 잘 나와있다.)

C언어에서는 이 메모리 영역을 지정하고 제거하는 방법이 있지만 자바스크립트는 가비지콜렉터에 의해서 자동으로 더이상 사용되지않는 값들에 대해서 메모리영역에서 삭제하는 작업을 자동으로 실행한다.

이때 값이 저장된 메모리영역의 주소는 고정이아니라 코드가 실행될때 메모리의 상황에 따라 임의로 결정된다. 즉 변수는 하나의 값을 저장하기위해 확보한 메모리공간 자체 또는 그 메모리 공간을 식별하기위해서 붙여진 이름이라고 볼 수 있다.

변수를 사용하는 이유는 바로 이 매번 임의로 지정되는 메모리주소에 우린 직접 접근할 수 없기때문에 이름을붙여서 항상 동일한 값이 접근하기위해서 사용한다라고 볼 수 있다.

그러면 이 변수의 이름은 어디에 저장되는가? 라고 생각할 수 있는데 변수이름뿐만 아니라 모든 식별자는 실행컨텍스트 에 등록된다. 자바스크립트의 엔진은 실행컨텍스트를 통해 식별자와 스코프를 관리한다.

타입추론

자바스크립트의 변수는 선언이 아닌 할당에 의해 타입이 결정된다. 그리고 재할당을 통해서 언제든 타입이 동적으로 변할 수 있는데 이걸 동적 타이핑 이라고하고 정적타입 언어와 구별하기위해 동적타입언어 라고한다. 이러한 암묵적 형변환때문에 매우 유연하게 코드작성이 가능하지만 이때문에 변수에 대한 신뢰성이 떨어지고 변수의 추적이 어려워진다는 단점이 존재한다.

호이스팅

console.log(hello); // undefined

var hello; // 변수 선언

위의 흐름을 예상해보면 자바스크립트는 인터프리터에 의해 한줄씩 순차적으로 실행이되는데 console.log(hello) 이걸 호출할 당시 해당 변수는 아직 선언되지않았기 때문에 ReferenceError(참조에러) 가 발생해야할것같지만 에러없이 동작하면서 undefined 를 출력하는걸 확인할 수 있다.

변수는 런타임시점이 아닌 그 이전단계에서 먼저 실행되기때문에 에러가 발생하지않는데 이걸 호이스팅이라고 한다. 런타임시점 이전에 실행되는것은 변수뿐만아니라 함수선언문도 해당된다.

일단 var 는 나중에 선언하더라도 먼저 호출된 코드에서 에러를 발생시키지는 않는다. 그렇다면 let, const 도 호이스팅된다고했는데 에러가 날지 안날지 궁금증이 생긴다.

let

console.log(hello);
let hello;

Uncaught ReferenceError: hello is not defined

const

console.log(hello);
const hello;

Uncaught SyntaxError: Missing initializer in const declaration

일단 두 변수는 var 처럼 정상동작이 되는것이 아닌 에러를 출력한다. 똑같이 호이스팅된다면 undefined 를 뱉어야할것같은데 에러를 출력하고있고 심지어 두 변수의 에러메세지 내용또한 다르게 나온다.

class

new Person('kang');

class Person {
	constructor(name) {
    	this.name = name
    }
}

???

function

hello('kang');
function hello(name) {
	return `Hello ${name}`;
}

???

자바스크립트에서는 class 와 function 도 호이스팅이 발생한다고 했다. 그렇다면 위의 두 코드는 어떤 결과가 나와야할까?

class

new Person('kang');

class Person {
	constructor(name) {
    	this.name = name
    }
}

Uncaught ReferenceError: Person is not defined

function

hello('kang');
function hello(name) {
	return `Hello ${name}`;
}

“Hello kang”

class 는 에러를 리턴하지만 함수는 정상적으로 동작한다. 일단 종합적으로 정리해보자면

let, const, class => 에러발생 var, function => 정상출력 (함수는 정상값, var 는 undefined)

TDZ(Temporal Dead Zone)

한글로 직역하면 일시적 사각지대인데 이 지대는 스코프의 시작지점부터 초기화 지점까지의 구간을 지칭한다. 자바스크립트에서 변수는 선언, 초기화, 할당 이라는 세가지 단계에 걸쳐서 생성이된다.

var a; // 변수 선언 + 초기화
a = 1; // 할당

var 로 생성된 변수는 선언과 동시에 초기화(undefined) 가 이루어지면서 메모리영역에 undefined를 저장한다. 그리고 값을 할당해주면 새로운 다른 메모리영역에 할당한값이 저장된다.

function 같은경우는 선언 초기화 할당 세가지가 동시에 진행된다.

let으로 선언된 변수는 선언단계와 초기화단계가 분리되서 진행되고 때문에 실행컨텍스트에 변수를 등록은했지만 초기화단계가 아직 진행되지않아 메모리할당이 되어있지않아 접근할 메모리주소가없기때문에 참조에러가 발생하게된다.

즉 let 이란 변수 선언 후 초기화단계가 발생하기전에 변수에 접근하려고하면 에러를 발생시키는것이다 바로 이 구간까지가 TDZ 인것이다.

var 나 let 은 선언후 나중에 할당해주어도 되지만 const 는 선언과 동시에 할당해주어야하고 중복할당이 불가능하다.

블록스코프 && 함수스코프

var 같은경우 함수스코프내에서 움직이기때문에 블록스코프내에서 선언하고 사용하게되면 전역변수로 호이스팅이 발생한다. var 블록스코프

if (true) {
	var a = 1;
  	console.log(a) // 1
}
console.log(a) // 1

var 함수스코프

function test () {
    var b = 2;
    console.log(b) // 2
}
test()
console.log(b) // undefined

let 블록스코프

if (true) {
	let c = 1;
  	console.log(c) // 1
}
console.log(c) // ReferenceError: c is not defined

댓글남기기