var

var

var 문은 함수 스코프 또는 전역 스코프를 가진 변수를 선언하며, 선택적으로 각각을 값으로 초기화합니다. Baseline Widely available — 2015년 7월부터 여러 브라우저에서 지원되는 잘 정착된 기능입니다.

출처: var

본문

var 문은 함수 스코프 또는 전역 스코프를 가진 변수를 선언하고, 선택적으로 각각을 값으로 초기화합니다.

시도해 보기 (Try it)

var x = 1;

if (x === 1) {
  var x = 2;

  console.log(x);
  // Expected output: 2
}

console.log(x);
// Expected output: 2

구문 (Syntax)

var name1;
var name1 = value1;
var name1 = value1, name2 = value2;
var name1, name2 = value2;
var name1 = value1, name2, /* …, */ nameN = valueN;
  • nameN: 선언할 변수의 이름입니다. 각각은 유효한 JavaScript 식별자이거나 구조 분해 바인딩 패턴이어야 합니다.
  • valueN: 변수의 초기 값입니다. 유효한 표현식이면 무엇이든 될 수 있습니다. 기본값은 undefined입니다.

설명 (Description)

var로 선언된 변수의 스코프는 var 문을 가장 가깝게 포함하는 다음 중괄호로 감싸진 구문 중 하나입니다:

  • 함수 본문
  • 정적 초기화 블록

또는 위의 어느 것도 해당하지 않으면:

  • 모듈 모드로 실행되는 코드인 경우 현재 모듈
  • 스크립트 모드로 실행되는 코드인 경우 전역 스코프
function foo() {
  var x = 1;
  function bar() {
    var y = 2;
    console.log(x); // 1 (function `bar` closes over `x`)
    console.log(y); // 2 (`y` is in scope)
  }
  bar();
  console.log(x); // 1 (`x` is in scope)
  console.log(y); // ReferenceError, `y` is scoped to `bar`
}

foo();

중요하게도, 블록 문, try...catch, switch, for 문 중 하나의 헤더 등 다른 블록 구문은 var에 대한 스코프를 만들지 않으며, 그러한 블록 안에서 var로 선언된 변수는 블록 밖에서도 계속 참조할 수 있습니다.

for (var a of [1, 2, 3]);
console.log(a); // 3

스크립트에서 var로 선언된 변수는 전역 객체의 비구성(non-configurable) 속성으로 추가됩니다. 이는 그 속성 설명자(property descriptor)를 변경할 수 없고 delete로 삭제할 수도 없다는 뜻입니다. JavaScript는 자동 메모리 관리를 하므로, 전역 변수에 delete 연산자를 사용할 수 있게 하는 것은 말이 되지 않습니다.

"use strict";
var x = 1;
Object.hasOwn(globalThis, "x"); // true
delete globalThis.x; // TypeError in strict mode. Fails silently otherwise.
delete x; // SyntaxError in strict mode. Fails silently otherwise.

Node.js CommonJS 모듈과 네이티브 ECMAScript 모듈 모두에서 최상위 변수 선언은 모듈로 스코프되며, 전역 객체의 속성으로 추가되지 않습니다.

var 키워드 뒤의 목록은 바인딩 목록이라고 불리며 쉼표로 구분됩니다. 여기서 쉼표는 쉼표 연산자가 아니고 =는 할당 연산자가 아닙니다. 목록의 뒷부분 변수의 이니셜라이저는 목록의 앞부분 변수를 참조하여 초기화된 값을 얻을 수 있습니다.

호이스팅 (Hoisting)

var 선언은 스크립트의 어디에서 발생하든, 스크립트 안의 어떤 코드가 실행되기 전에 처리됩니다. 코드 어디에서든 변수를 선언하는 것은 최상단에서 선언하는 것과 동등합니다. 이는 또한 변수가 선언되기 전에 사용되는 것처럼 보일 수 있다는 뜻이기도 합니다. 이 동작은 변수 선언이 그 변수가 발생한 함수, 정적 초기화 블록, 또는 스크립트 소스의 최상단으로 이동된 것처럼 보이기 때문에 호이스팅(hoisting)이라고 합니다.

참고: var 선언은 현재 스크립트의 최상단으로만 호이스팅됩니다. 하나의 HTML에 두 개의 <script> 요소가 있다면, 첫 번째 스크립트는 두 번째 스크립트가 처리되고 실행되기 전에는 두 번째가 선언한 변수에 접근할 수 없습니다.

bla = 2;
var bla;

이는 암시적으로 다음과 같이 이해됩니다:

var bla;
bla = 2;

이런 이유로 항상 변수를 스코프의 최상단(전역 코드의 최상단과 함수 코드의 최상단)에서 선언하는 것을 권장하며, 그래야 어떤 변수가 현재 함수로 스코프되는지 명확해집니다.

호이스팅되는 것은 변수의 선언뿐이며, 초기화는 아닙니다. 초기화는 할당 문에 도달했을 때만 발생합니다. 그때까지 변수는 undefined로 남습니다(선언되긴 했으므로):

function doSomething() {
  console.log(bar); // undefined
  var bar = 111;
  console.log(bar); // 111
}

이는 암시적으로 다음과 같이 이해됩니다:

function doSomething() {
  var bar;
  console.log(bar); // undefined
  bar = 111;
  console.log(bar); // 111
}

재선언 (Redeclarations)

var를 사용한 중복 변수 선언은 엄격 모드에서도 오류를 일으키지 않으며, 선언이 이니셜라이저를 가지지 않는 한 변수는 값을 잃지 않습니다.

var a = 1;
var a = 2;
console.log(a); // 2
var a;
console.log(a); // 2; not undefined

var 선언은 함수 선언과 같은 스코프에 있을 수도 있습니다. 함수 선언과 var 선언 모두 최상단으로 호이스팅되므로, 두 선언의 상대적 위치와 무관하게 함수 값은 스코프 시작부터 변수의 이니셜라이저 또는 첫 할당까지 접근할 수 있습니다.

console.log(typeof a); // "function"
function a() {}
var a;
console.log(typeof a); // "function"
var a = 1;
function a() {}
console.log(a); // 1

var 선언은 let, const, class, import 선언과 같은 스코프에 있을 수 없습니다.

var a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared

var 선언은 블록으로 스코프되지 않기 때문에, 이 규칙은 다음 경우에도 적용됩니다:

let a = 1;
{
  var a = 1; // SyntaxError: Identifier 'a' has already been declared
}

letvar의 자식 스코프에 있는(같은 스코프가 아닌) 다음 경우에는 적용되지 않습니다:

var a = 1;
{
  let a = 2;
}

함수 본문 안의 var 선언은 매개변수와 같은 이름을 가질 수 있습니다.

function foo(a) {
  var a = 1;
  console.log(a);
}

foo(2); // Logs 1

catch 블록 안의 var 선언은 catch로 바인딩된 식별자와 같은 이름을 가질 수 있지만, catch 바인딩이 단순 식별자일 때만 가능하며 구조 분해 패턴일 때는 불가능합니다. 이것은 폐기(deprecated)된 문법이므로 의존해서는 안 됩니다. 이 경우 선언은 catch 블록 밖으로 호이스팅되지만, catch 블록 안에서 할당된 어떤 값도 밖에서는 보이지 않습니다.

try {
  throw new Error();
} catch (e) {
  var e = 2; // Works
}
console.log(e); // undefined

예제 (Examples)

두 변수 선언 및 초기화

var a = 0,
  b = 0;

단일 문자열 값으로 두 변수 할당

var a = "A";
var b = a;

이는 다음과 동등합니다:

var a, b = a = "A";

순서에 주의하세요:

var x = y,
  y = "A";
console.log(x, y); // undefined A

여기서 xy는 코드가 실행되기 전에 선언되지만, 할당은 나중에 발생합니다. x = y가 평가될 때 y는 존재하므로 ReferenceError가 발생하지 않고 그 값은 undefined입니다. 따라서 x에는 undefined 값이 할당됩니다. 그런 다음 y에 값 "A"가 할당됩니다.

여러 변수의 초기화

var x = y = 1 구문에 주의하세요 — y는 실제로 변수로 선언되지 않으므로, y = 1은 한정되지 않은 식별자 할당(unqualified identifier assignment)이며, 비엄격 모드에서 전역 변수를 만듭니다.

var x = 0;
function f() {
  var x = y = 1; // Declares x locally; declares y globally.
}
f();

console.log(x, y); // 0 1

// In non-strict mode:
// x is the global one as expected;
// y is leaked outside of the function, though!

위와 같은 예제지만 엄격 모드인 경우:

"use strict";

var x = 0;
function f() {
  var x = y = 1; // ReferenceError: y is not defined
}
f();

console.log(x, y);

암시적 전역 변수와 외부 함수 스코프

암시적 전역 변수처럼 보이는 변수들은 외부 함수 스코프의 변수에 대한 참조일 수 있습니다:

var x = 0; // Declares x within file scope, then assigns it a value of 0.

console.log(typeof z); // "undefined", since z doesn't exist yet

function a() {
  var y = 2; // Declares y within scope of function a, then assigns it a value of 2.

  console.log(x, y); // 0 2

  function b() {
    x = 3; // Assigns 3 to existing file scoped x.
    y = 4; // Assigns 4 to existing outer y.
    z = 5; // Creates a new global variable z, and assigns it a value of 5.
    // (Throws a ReferenceError in strict mode.)
  }

  b(); // Creates z as a global variable.
  console.log(x, y, z); // 3 4 5
}

a(); // Also calls b.
console.log(x, z); // 3 5
console.log(typeof y); // "undefined", as y is local to function a

구조 분해를 사용한 선언

=의 왼쪽도 바인딩 패턴일 수 있습니다. 이를 통해 한 번에 여러 변수를 만들 수 있습니다.

const result = /(a+)(b+)(c+)/.exec("aaabcc");
var [, a, b, c] = result;
console.log(a, b, c); // "aaa" "b" "cc"

자세한 내용은 구조 분해(Destructuring) 문서를 참고하세요.

명세 (Specifications)

var 문은 ECMAScript 언어 명세에 정의되어 있습니다.

브라우저 호환성 (Browser compatibility)

이 기능은 대부분의 현대 브라우저에서 널리 지원됩니다(Baseline Widely available). 자세한 호환성 표는 MDN의 브라우저 호환성 섹션을 참고하세요.

더 알아보기

  • let
  • const
  • 호이스팅 (Hoisting), 구조 분해 (Destructuring)