TIL18. var let const

조연정·2020년 8월 21일
0
post-thumbnail

변수 선언방식 var, let, const 각각의 특징에 대해 알아보자.
(2021년 1월 19일, 수정)

변수란?

변수는 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위한 이름을 말한다.

그렇다면 변수를 왜 사용하는 걸까?

애플리케이션은 데이터를 입력받아 처리하고, 그 결과를 출력한다. 그 안에서 변수는 프로그래밍 언어에서 데이터를 관리하기 위한 핵심 개념이다.

1 + 2 라는 연산을 한다고 가정해보자. 숫자 값 1과 2는 임의의 메모리 주소에 기억(저장)되고, CPU는 이 값을 읽어 연산을 수행한다. 연산 결과 값 3도 마찬가지로 메모리 상의 임의의 위치에 저장된다.

여기서 문제는 결과 3은 한번밖에 사용하지 못한다는 것이다.
연산 결과를 재사용하고 싶다면 메모리 주소를 통해 결과값 3이 저장된 메모리 공간에 직접 접근하는 해야하는데 이 방법은 오류를 발생시킬 확률이 높다.
실수로 운영체제가 사용하고 있는 값을 변경하면 시스템이 작동을 멈출수도 있기때문에 js는 개발자의 직접적인 메모리 제어를 허용하지 않는다.
메모리 제어를 허용하더라도, 메모리 주소는 코드가 실행될 때마다 메모리의 상황에 따라 변경되고, 코드가 실행되기 전까지는 값이 저장된 메모리 주소를 알 수가 없다.

기억할 값을 메모리에 저장하고, 그 값을 읽어 들여 재사용하기 위한 바로 이때 변수를 사용하는 것이다.

변수 선언

자바스크립트 변수 종류에는 var, let, const가 있다. ES6 이전에는 var를 사용했지만, ES6가 출범한 이후에는 let과 const의 사용이 두드러졌다.

선언방법

선언 방법에는 차이가 없다.

var variable1 = 1;
let variable2 = 1;
const variable3 = 1;

재선언과 재할당

  • var - 재할당 o, 재선언 o
  • let - 재할당 o, 재선언 x
  • const - 재할당 x, 재선언 x
var a = 1
a = 2
var a = 3
console.log("const:",a) //const: 3

let b = 4
b = 5
let b = 6 // Identifier 'b' has already been declared

const c = 7 
c = 8  // x
const c = 9  // x

hoisting

호이스팅은 '끌어올리다'라는 뜻으로, 변수나 함수의 호출 선언문을 유효범위 최상단으로 끌어올리는 것을 말한다. 모든 선언에는 호이스팅이 발생하지만, var로 선언된 변수와는 달리 let, const으로 선언된 변수를 선언문 이전에 참조하면 일시적 사각지대에 빠지게 되어 참조에러가 발생한다.

var변수는 선언 단계와 초기화 단계가 한번에 이루어진다.즉, 스코프에 변수를 등록(선언 단계)하고 메모리에 변수를 위한 공간을 확보한 후, undefined로 초기화(초기화 단계)한다. 따라서 변수 선언문 이전에 변수에 접근하여도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않는다.( 다만 undefined를 반환)이후 변수 할당문에 도달하면 비로소 값이 할당된다.
반면에, let 변수는 선언 단계와 초기화 단계가 분리되어 진행된다. 변수가 초기화되지 않은 상태에서 접근을 하기 때문에 참조에러가 발생한다. 이때, 스코프의 시작 지점부터 초기화 시작지점까지의 구간을 일시적 사각지대라고 한다.

// var의 경우
console.log(x);  // undefined
var x;

// let의 경우
console.log(x); // ReferenceError: x is not defined 
let x;

위의 예에서 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징 변수 호이스팅을 잘 볼 수 있다.

var 변수 선언문보다 변수를 참조하는 코드가 앞에 있지만 참조 에러가 발생하지 않고, undefined가 출력된다. js 코드는 인터프리터에 의해 한 줄씩 순차적으로 실행되기에 console.log(x)가 가장 먼저 실행될 것 같지만, 그렇지 않다. 변수 선언이 런타임시점에서 실행되지 않고 그 이전 단계에서 먼저 실행됙 때문이다.

자바스크립트 엔진은 변수 선언을 포함한 모든 선언문을 소스코드에서 찾아내 먼저 실행하는데 이 과정을 소스코드 평가 과정이라고 한다. 소스 코드의 평가 과정이 끝나면, 선언문을 제외한 소스코드를 순차적으로 실행한다.
즉, 변수 선언이 소스코드의 어디에 있든 상관없이 변수를 참조할 수 있다는 것이다.

변수 scope(유효범위)

변수에는 유효한 범위가 존재하는데, 그 범위를 벗어나게되면 오류가 발생한다.
var는 function scope, let과 const는 block scope를 가진다.

1.function scope

함수 스코프를 따른다는 의미는 새로운 함수가 생성될 때마다 새로운 스코프가 발생된다는 뜻이다.
var로 선언된 변수는 한 함수 내에서만 활동이 가능하다. 함수 선언없이 변수를 선언할 경우 새로운 환경, 새로운 스코프가 형성되지 않는다. 스코프가 형성되지 않으므로 동일한 실행 컨텍스트 내에 존재하는 것이다.

// 1. 함수 선언없이 변수 var를 선언했을 때
if(true) {
  var x = 'abc'
}

x // abc

// 2. 함수 안에 변수 var를 선언했을 때
function myFuc() {
  var x = 'abc';
}

x  // x is not defined

1번의 경우, 새로운 스코프가 형성되지 않았기 때문에 동일한 실행 컨텍스트 내에 존재한다. 변수 x에 대한 접근이 어디서나 가능하다.
2번의 경우, 함수 생성과 동시에 새로운 컨텍스트가 생성이 되고, 이 실행 컨텍스트 내부에 존재하는 변수 환경에 변수 x가 저장된다. 따라서 외부에서 변수x에 접근하려고 하면 스코프가 다르기 때문에 접근이 불가능하다.

let x = 3; // 전역 변수

function Myfunction() {
	let x = 5;	//지역 변수
	console.log(x);
}

Myfunction(); // 5
console.log(x); //3

함수 스코프와 전역 스코프에 동일한 변수가 선언되어 있을 때에는, 실행 컨텍스트가 생성되는 과정에 의해 내부 스코프부터 참조하게 됩니다.
위 코드를 보면 가장 먼저 로컬에 변수가 있는지 확인한 후, 없으면 전역 변수를 확인하는 것을 알 수 있다.

2.block scope

블록 스코프는 {}단위형태(for문, if문...)로 이루어진 블록 안에서만 활동이 가능하다. 블록단위 안에서 선언한 let, const변수는 블록 바깥에서 접근할 수 없다는 것이 핵심이다.

// 1.변수가 함수 스코프를 따를 경우
function loop() {
  for (var i = 0; i < 3; i++) {
    console.log(i);
  }
  console.log('final', i);
}

loop();
/*
0
1
2
final 3
*/

// 2.변수가 블록 스코프를 따를 경우
function loop() {
  for (let i = 0; i < 3; i++) {
    console.log(i);
  }
  console.log('final', i);
}
loop();
// ReferenceError: i is not defined

1번의 경우, loop라는 함수 스코프 안에 var변수 i가 존재하기 때문에 문제없이 i에 접근하여 값을 출력한다.
2번의 경우 let으로 변수를 선언했기 때문에 for문 내에만 종속되며 for문 외부에서는 i에 접근할 수 없다.

profile
Lv.1🌷

0개의 댓글