JavaScript/Basics

[JavaScript] 오래된 var의 특징

Sonny Cucumber 2022. 3. 9. 18:22

Var

조금 구식인건 알고있었지만 오래된 스크립트에서

let 대신 var를 쓰는 경우가 있는데 이건 오래된 방식이다

 

조금 더 깊게 파헤쳐보자면 var 는 블록 스코프가 없다. (scope: 범위)

이게 무슨 말이냐면 이렇게 선언된 변수의 스코프는

함수 스코프이거나 전역 스코프 이다. 블록을 기준으로 스코프가 생기지 않기에

밖에서 접근이 가능하다. 

if (true) {
	var test = true; //let test=true; 면 밖에서 부를 수 없음
}

alert(test);

 

함수 안에 있다면 위에 말했던 것처럼

전역 스코프 or 함수 스코프 이기에

함수 안에 있으니 함수 안으로만 범위가 설정된다.

function sayHi() {
	if (true) {
    	var phrase = "Hello";
    }
    alert(phrase); //제대로 작동
}

sayHi();
alert(phrase); //Error

그래서 alert(phrase)부분이 에러가 뜨는 것.

 

그리고 정말 이상한게 var는

선언을 또 할 수 있다. (let 은 안됨)

let user;
let user; //SyntaxError

var user = "sonny";
var user = "no one";

alert(user); // no one

심지어 선언을 안해도 쓸 수 있다.

function sayHi() {
	phrase = "Hello"; //이것 처럼
    
    alert(phrase);
    
    var phrase;
}
sayHi();

var선언은 함수가 시작될 때  처리되는데 전역(global)에서 선언한

변수라면 스크립트가 시작될 때 처리된다.

 

위처럼 함수 본문 내에서 var로 선언한 변수느 선언 위치와 상관없이 함수

본문이 시작되는 지점에서 정의됩니다. 

 

위 코드는 아래와 같이 동작합니다

function sayHi() {
  var phrase; //이렇게 끌어올림

  phrase = "Hello";

  alert(phrase);
}
sayHi();

이렇게 끌어올려지는 현상을 호이스팅(Hoisting)이라고 하는데 var로

선언한 모든 변수는 함수의 최상위로 '끌어 올려지기 때문이다

 

function sayHi() {
  phrase = "Hello"; // (*)

  if (false) {
    var phrase;
  }

  alert(phrase);
}
sayHi();

위 코드에서 코드블록은 무시되기 때문에 (코드블록 이란 중괄호 안에 작성된 것)

위위 코드와 동일하게 동작합니다.

 

if (false) 안의 코드는 실행이 되지 않지만, 호이스팅에는 영향을 못미침.

이 안의 var는 함수 안 제일 윗부분에 처리되므로 이미 정의가 된거지

하지만 할당은 호이스팅 되지 않음.

 

예로 var phrase = "Hello";

이 행에선 두가지 일이 일어나는데

선언과 할당이다.

 

변수의 선언만 var phrase; 시작 시 처리되기 때문에

어디서든 참조가 가능하다. 무언가를 담기 전엔 undefined 이 되겠지만.

 

IIFE ( immediately-invoked function expressions)

이건 즉시 실행 함수 표현식인데 var의 스코프는 블록 레벨 수준이 아니기에

var도 가질 수 있게 고려된 것 중 하나가 이것이다. 요즘엔 잘 안씀.

 

(블록 레벨 스코프 = 코드 블록 함수, if, for, while, try/catch 내에서 선언된 변수는

코드 블록 내에서만 유효하며 코드 불록 외부에서는 참조할 수 없다. 즉, 지역 변수.)

 

예시

(function() {

  let message = "Hello";

  alert(message); // Hello

})();

특징이라고 한다면 이건 이름처럼 바로 실행이 되는데

바로 실행되기 때문인지 이름이 필요가 없다.

 

괄호를 빼고 사용한다면 선언이라고 생각하기에

이름을 넣어야 한다고 에러가 나오게 될 것이다. 

 

그렇다고 괄호를 빼고나서 이름까지 넣는다고 해도

선언으로 정의한 함수를 바로 사용할 수 없기에 바로 호출이 안된다.

 

// IIFE를 만드는 방법

(function() {
  alert("함수를 괄호로 둘러싸기");
})();

(function() {
  alert("전체를 괄호로 둘러싸기");
}());

!function() {
  alert("표현식 앞에 비트 NOT 연산자 붙이기");
}();

+function() {
  alert("표현식 앞에 단항 덧셈 연산자 붙이기");
}();

예전에 이렇게 하는게 이해도 안되고 참 힘들었던 기억이 나는데

어느 순간 이후로 이렇게는 자연스럽게 안쓰는게 이유도 모르고 지나가버렸다.