본문 바로가기

모던 자바스크립트

6.4 오래된 'var'

⚠️ 오래된 스크립트를 읽는 데 도움을 주는 글입니다. 

 

◾️ 변수 선언 방법

  1. let
  2. const
  3. var

◾️ let과 const는 렉시컬 환경 측면에서 정확히 같은 방식으로 동작한다. 

◾️ var는 초기 자바스크립트 구현 방식 때문에 전혀 다른 방식으로 동작한다. 

function sayHi () {
  var phrase = "Hello"; // 'let'대신 'var'를 사용해 지역 변수를 선언
  
  console.log(phrase); //Hello
}

sayHi(); // Hello

console.log(phrase); // Error, phrase is not defined

 

 

var는 블록 스코프가 없다. 

◾️ var로 선언한 변수의 스코프는 함수 스코프이거나 전역 스코프이다. 

◾️ 블록 기준으로 스코프가 생기지 않기 때문에 블록 밖에서 접근 가능하다. 

 

if(true) {
  var test = true;
}

console.log(test); // true

◾️ var는 코드 블록을 무시하기 때문에 test는 전역 변수가 된다. 전역 스코프에서 test에 접근할 수 있다. 

◾️ var 대신 let으로 선언했다면 에러가 발생한다. (if문 안에서만 접근할 수 있다. )

if(true) {
  let test = true;
}

console.log(test); // Error: test is not defined

◾️ 반복문에서 var → 반복문이 종료되었지만 i는 전역 변수이기 때문에 접근이 가능하다. 

for(var i = 0; i < 10; i++) {
  console.log(i); // 0, 1, ... 9
}

console.log(i); // 10

◾️ 코드 블록이 함수 안에 있다면, var는 함수 레벨 변수가 된다. 

function sayHi() {
  if(true){
    var phrase = "Hello";
  }
  
  console.log(phrase); // Hello
}

sayHi();
console.log(phrase); // Error: phrase is not defined

◾️ var는 if, for 등의 코드 블록을 관통한다. 오래전의 자바스크립트에선 블록 수준 렉시컬 환경이 만들어지지 않았기 때문

 

 

함수 시작과 함께 처리되는 var

◾️ var 선언은 함수가 시작될 때 처리된다. 

◾️ 전역에서 선언한 변수라면 스크립트가 시작될 때 처리된다. 

◾️ 함수 본문 내에서 var로 선언한 변수는 선언 위치와 상관없이 함수 본문이 시작되는 지점에서 정의된다 (단, 변수가 중첩 함수 내에서 정의 되지 않아야 이 규칙이 적용됨)

◾️ 3가지 예시 모두 동일하게 동작한다. 

function sayHi() {
  phrase = "Hello";
  
  console.log(phrase); // Hello

  var phrase;
}
sayHi();

 

function sayHi() {
  var phrase;

  phrase = "Hello";
  
  console.log(phrase); // Hello
}
sayHi();
function sayHi() {
  phrase = "Hello"; // (*)

  if (false) {
    var phrase;
  }

  console.log(phrase);
}
sayHi();

◾️ 호이스팅(hoisting) : 변수가 끌어올려 지는 현상

◾️ var로 선언한 모든 변수는 함수의 최상위로 끌어 올려진다. 

◾️ if(false) 블록 안 코드는 절대 실행되지 않지만, 호이스팅에 전혀 영향을 주지 않는다. 

◾️ if 내부의 var는 함수 sayHi의 시작부분에서 처리되므로 *로 표시한 줄에서 phrase는 이미 정의된 상태이다. 

 

✳️ 선언은 호이스팅 되지만 할당은 호이스팅 되지 않는다. 

function sayHi() {
  console.log(phrase);
  
  var phrase = "Hello";
}

sayHi();

◾️ var phrase = "Hello"행에선 두가지 일이 일어난다. 

  1. 변수 선언(var)
  2. 변수에 값을 할당(=)

◾️ 변수 선언은 함수 실행이 시작될 때 처리 되지만(호이스팅) 할당은 호이스팅 되지 않기 때문에 할당 관련 코드에서 처리된다. 

function sayHi() {
  var phrase; // 선언 → 함수 시작 시 처리
  
  console.log(phrase); // undefined
  
  phrase = "Hello"; // 할당 → 실행 흐름이 코드에 도달했을 때 처리
}

sayHi();

◾️ 모든 var 선언은 함수 시작 시 처리되기 때문에, var로 선언한 변수는 어디서든 참조할 수 있다. 

◾️ 변수에 값을 할당하기 전까지는 undefined

 

즉시 실행 함수 표현식

◾️ var도 블록 레벨 스코프를 가질 수 있게 만들어진 즉시 실행 함수 표현식(IIFE; immediately-invoked function expressions)

(function() {
  let message = "Hello";

  console.log(message); // Hello

})();

◾️ 함수 표현식이 만들어지고 바로 호출되면서, 해당 함수가 바로 실행된다.  

◾️ 즉시 실행 함수 형태 : (function () { ... })

// 함수를 선언과 동시에 실행하려고 함
function() { // <-- Error: Function statements require a function name
  let message = "Hello";

  console.log(message); // Hello
}();

◾️ 자바스크립트는 function이라는 키워드를 만나면 함수 선언문이 시작될 것이라 예상한다. 그런데 함수 선언문으로 함수를 만들 땐 반드시 함수의 이름이 있어야 하기 때문에 괄호로 감싸지 않으면 에러가 발생한다. 

// Error
function go() {

}(); // ← 함수 선언문은 선언 즉시 호출할 수 없다. 

◾️ 자바스크립트는 함수 선언문으로 정의한 함수를 정의와 동시에 바로 호출하는 것을 허용하지 않는다. 

◾️ 자바스크립트가 함수 표현식이라고 인식하게 해주는 다른 방법들(모던 자바스크립트에선 이렇게 코드를 작성할 필요가 없다.)

// IIFE를 만드는 방법

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

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

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

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

 

 

📝 요약

◽️ var로 선언한 변수는 let이나 const로 선언한 변수와 다른 두 가지 주요한 특성을 보인다. 
     1. var로 선언한 변수는 블록 스코프가 아닌 함수 수준 스코프를 갖는다. 
     2. var 선언은 함수가 시작되는 시점(전역 공간에선 스크립트가 시작되는 시점)에서 처리된다. 

 



📝 오늘 새롭게 배운 내용 📝

 

✅ var는 함수 스코프 let과 const는 블록 스코프

✅ var는 호이스팅(선언 하면 최상위로 끌어올려진다) 된다 

✅ 선언만 호이스팅 되고 할당은 실행 흐름 시점에서 이루어진다. (보통 선언과 할당을 동시에 해서 몰랐다..)

✅ 변수는 블록 레벨 스코프를 갖는 게 좋다. 

✅ 실행 되지 않는 반복문 안에 있는 변수에 접근할 수 있었다니... 

let과 const를 쓰자!!!!

 

 

📌 [JAVASCRIPT_INFO 오래된 'var']

 

오래된 'var'

 

ko.javascript.info

 

 

 

'모던 자바스크립트' 카테고리의 다른 글

6.6 객체로서의 함수와 기명 함수 표현식  (0) 2020.08.24
6.5 전역 객체  (0) 2020.08.22
6.3 변수의 스코프  (0) 2020.08.20
6.2 나머지 매개변수와 전개 문법  (0) 2020.08.19
6.1 재귀와 스택  (0) 2020.08.15