JS - 변수 선언(호이스팅, 스코프)

지송현·2022년 9월 21일
0

JS

목록 보기
1/9
post-thumbnail

js에서 변수의 선언은 var, const, let으로 한다. 이전에는 const, let 없이 var만 쓰였고, ES6부터 const와 let이 추가되었다.

변수 할당

var a // 변수 선언
a = '가나다' // 값 할당

var a = '가나다' // 변수 선언과 할당

변수 선언과 할당은 하나로 표현할 수 있지만, 각각 실행 시점이 다르다.

변수 선언은 호이스팅되어 런타임 이전에 실행되지만, 값의 할당은 소스코드가 순차적으로 실행되는 런타임에 실행된다.




var, const, let

  • const(constant-상수) : 반드시 선언과 할당이 동시에 이루어져야 한다.
const a = 1; // O

const b;
const b = 2; // error

이름에서 알 수 있다시피 처음 선언한 뒤 변경하지 않을 값을 할당할 때 쓴다.

const a = 1;
a = 2; // error

  • let : const와 달리 재할당이 가능하다.
let a = 1;
a = 2; // O

  • var : 예전에는 var로만 변수 선언이 가능했다. const, let과 다른 점은 여러가지가 있지만 일단 중복 선언이 가능하다는 것이다.
var a = 1;
var a = 2;
console.log(a) // 결과값 2
var a = 3;
console.log(a) // 결과값 3

이렇게 해도 에러가 나지 않는다. 유연하게 변수 선언이 가능하지만 이것으로 인한 장점보다 중복 선언으로 인한 위험성이 더 크기 때문에 지금은 const와 let 사용을 권장하는 것 같다.

이외에 var와 let/const의 차이점을 더 알기 위해 먼저 호이스팅과 스코프에 대해 알아야 한다.



호이스팅(hoisting)

var과 const, let의 차이점을 설명하는 글을 볼 때마다 이 호이스팅이라는 것이 보여서 한 번 정리해보려 한다.
(hoisting은 '끌어 올리다'라는 뜻이다.)

호이스팅이란

  • js 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언한다.
    - 자바스크립트 parser가 함수 실행 전 해당 함수를 한 번 훑는다.
    - 함수 안에 존재하는 변수/함수 선언에 대한 정보를 기억했다가 실행시킨다.
    - 유효 범위 : 함수 블록 {} 안에서 유효(아래 scope 항목 참조)
  • 즉, 함수 내에서 아래쪽에 존재하는 내용 중 필요한 값들을 위로 끌어올리는 것이다.
    - 실제로 코드가 끌어올려지는 것은 아니며, js parser 내부적으로 끌어올려 처리한다.
    - 실제 메모리에서는 변화가 없다.

호이스팅의 대상

var 변수 선언함수 선언문에서만 호이스팅이 일어난다.

var 변수 선언의 경우

var 변수/함수의 선언만 위로 끌어올려지며, 할당은 끌어 올려지지 않는다. let/const 변수 선언과 함수 표현식에서는 호이스팅이 발생하지 않는다.

console.log("가나다");
var a = '123';
let b = '321';
// 위의 코드 호이스팅 결과
var a; // 호이스팅 (선언)

console.log("가나다");
a = '123'; // 할당
let b = '321'; // 호이스팅 X

첫번째 코드를 js parser가 읽은 결과가 아래 코드이다. 호이스팅된 후에 코드를 표현한 것이다. 위의 설명처럼 var 변수만 호이스팅이 일어났고 모든 코드보다 위로 끌어올려진 것을 볼 수 있다. 따라서 아래와 같은 코드도 동작하게 된다.

console.log(a); // 결과값 : undefined
var a = '123';

var가 아닌 let/const였으면 에러가 나왔을 것이다. 결과값이 undefined가 나온 것은 위에서 볼 수 있다시피 호이스팅은 선언만 끌어 올리기 때문이다. 값은 할당되지 않았으니 undefined가 나온다.


함수 선언문의 경우

일단 함수를 정의하는 네 가지 방식을 살펴보자.

// 1. 함수 선언문(함수 이름 생략 불가능)
function abc() {
  console.log("123");
};

// 2. 함수 표현식(함수 이름 생략 가능)
var abc = function() {
  console.log('123');
};
// 함수 이름 작성 시
var abc = function 123() {
  console.log('123');
};

// 3. Function 생성자 함수 

// 4. 화살표 함수
var abc = () => {
  console.log('123');
};
  1. 생성자 함수는 아직 개념이 확실하지 않아 적지 않았다. 일단 위에서 언급한 함수 선언문과 표현식은 알았으니 넘어가자.

이제 함수 선언문과 표현식에서의 호이스팅을 알아보자. 간단한 예시를 보면 다음과 같다.

f1();
f2();

// 함수 선언문
function f1() {
  console.log('123');
}

// 함수 표현식
var f2 = function() {
  console.log('321');
}
// 위의 코드 호이스팅 결과
var f2; // [호이스팅] 함수보다 먼저 변수값이 선언되는 것을 볼 수 있다.
function f1() { // [호이스팅] 함수 선언문
  console.log('123');
}

f1();
f2(); // error 발생

f2 = function() {
  console.log('321');
}

이렇게 함수 선언문만 호이스팅되는 것을 볼 수 있다. 함수 표현식의 경우 var로 선언했기 때문에 변수 부분만 호이스팅되고 함수 부분은 호이스팅되지 않았다. 따라서 f2는 선언만 된 상태기 때문에 실행시 에러가 발생한다. 또 둘 다 호이스팅 되었을 때, 변수가 함수보다 위에 오는 것을 알 수 있다.



!주의점

  • 코드의 가독성과 유지보수를 위해 호이스팅이 일어나지 않도록 한다.
    -- 호이스팅을 정확하게 알지 못해도 함수와 변수의 정의와 실행을 순서대로 입력한다면, 호이스팅으로 인한 스코프 꼬임 현상은 방지할 수 있다.
    -- let/const를 사용한다.
  • 현재 권장되지 않는 var를 알아야 하는 이유는 아직 ES6를 사용하지 않는 경우도 있기 때문에 예전 코드를 알아야 할 필요가 있기 때문이다.



스코프(scope)

식별자(ex. 변수명, 함수명 등)의 유효 범위를 말하며, 선언된 위치에 따라 스코프가 달라진다.
전역에 선언된 변수는 전역 스코프를, 지역에 선언된 변수는 지역 스코프를 갖는다.

  • 전역 변수 : 어디에서든지 사용 가능한 값
  • 지역 변수 : 함수 내부에서 사용 가능한 값(선언된 지역 스코프와 그 하위 지역 스코프에서 사용 가능)

또 한가지, 자바스크립트에서 모든 코드 블록(if, for, while, try/catch 등)이 지역 스코프를 만들며 이러한 특성을 블록 레벨 스코프라고 한다. 그리고 함수의 코드 블록만을 지역 스코프로 인정하는 것을 함수 레벨 스코프라고 한다.

const a = 1; // 전역 변수 

if (true) {
  const b = 2; // 지역 변수(블록 레벨 스코프)
};

function c() {
  const d = 3; // 지역 변수(함수 레벨 스코프)
};

그런데 여기서도 var와 let/const의 차이가 나타난다. let/const는 함수 레벨 스코프는 물론 블록 레벨 스코프를 인정한다. 그러나 var는 함수 레벨 스코프만 인정한다.

let a = 1;

if (true) {
  let a = 2;
};

console.log(a); // 결과값 : 1

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

var a = 1;

if (true) {
  var a = 2;
};

console.log(a); // 결과값 : 2

let의 경우 if 안에서 선언된 것은 if 안에서만 쓰일 수 있다. 그러나 var의 경우 블록 레벨을 무시하므로 if 안의 값이 출력된 것이다. 왜 이런 것인가 살펴보면 이것도 호이스팅에 의한 것이라고 볼 수 있다. 호이스팅의 정의를 다시 보면

  • 유효 범위 : 함수 블록 {} 안에서 유효

호이스팅의 범위가 함수 안까지라는 것이니 함수가 아니라면 if든 for든 무시하고 문서의 최상단으로 끌어올려지기 때문에 var는 함수 레벨 스코프만을 인정하는 것이다.

profile
백엔드 개발자

0개의 댓글