변수

변수는 값에 대표 이름을 할당하는 데이터 구조입니다. 모든 종류의 데이터를 포함할 수 있습니다.

변수의 이름을 식별자라고 합니다. 유효한 식별자는 다음 규칙을 따라야 합니다.

  • 식별자에는 유니코드 문자, 달러 기호 ($), 밑줄 문자 (_), 숫자 (0~9), 일부 유니코드 문자까지 포함할 수 있습니다.
  • 파서는 공백을 사용하여 입력 요소를 구분하므로 식별자는 공백을 포함할 수 없습니다. 예를 들어 myVariable 대신 my Variable 변수를 호출하려고 하면 파서는 두 개의 식별자 myVariable를 보고 문법 오류 ('예기치 않은 토큰: 식별자')를 발생시킵니다.
  • 식별자는 문자, 밑줄 (_) 또는 달러 기호 ($)로 시작해야 합니다. 숫자와 식별자가 혼동되지 않도록 숫자로 시작할 수 없습니다.

    let 1a = true;
    
    > Uncaught SyntaxError: Invalid or unexpected token
    

    JavaScript가 식별자 시작 부분에 숫자를 허용하면 숫자로만 구성된 식별자가 허용되어 숫자로 사용되는 숫자와 식별자로 사용되는 숫자 간에 충돌이 발생합니다.

    let 10 = 20
    
    10 + 5
    > ?
    
  • 이미 문법적으로 의미가 있는 '예약된 단어'는 식별자로 사용할 수 없습니다.

  • 식별자에는 특수문자 (! . , / \ + - * =)를 포함할 수 없습니다.

다음은 식별자를 만드는 엄격한 규칙은 아니지만 코드 유지보수를 더 쉽게 하는 업계 권장사항입니다. 특정 프로젝트에 다른 표준이 있는 경우 일관성을 위해 해당 표준을 따르세요.

JavaScript의 내장 메서드와 속성에 의해 설정된 예시를 따르면 카멜 케이스('camelCase'라고도 표기)는 여러 단어로 구성된 식별자에 매우 일반적인 약어입니다. 카멜 표기법은 공백 없이 가독성을 높이기 위해 첫 단어를 제외한 모든 단어의 첫 글자를 대문자로 표기하는 방법입니다.

let camelCasedIdentifier = true;

일부 프로젝트는 컨텍스트와 데이터의 특성에 따라 다른 이름 지정 규칙을 사용합니다. 예를 들어 클래스의 첫 글자는 일반적으로 대문자로 표시되므로 여러 단어로 구성된 클래스 이름은 일반적으로 '대문자 카멜 표기법' 또는 Pascal 표기법이라고 하는 카멜 표기법의 변형을 사용합니다.

class MyClass {

}

식별자는 포함된 데이터의 특성을 간결하게 설명해야 하며 (예: currentMonthDaystheNumberOfDaysInTheCurrentMonth보다 나은 이름임) 한눈에 명확하게 읽을 수 있어야 합니다 (originalValueval보다 낫음). 이 모듈 전반에서 사용되는 myVariable 식별자는 개별 예시의 컨텍스트에서 작동하지만, 포함된 데이터에 관한 정보를 제공하지 않으므로 프로덕션 코드에서는 매우 유용하지 않습니다.

식별자는 포함된 데이터에 대해 너무 구체적이어서는 안 됩니다. 스크립트가 해당 데이터에 작용하는 방식이나 향후 유지보수자가 내리는 결정에 따라 값이 변경될 수 있기 때문입니다. 예를 들어 원래 식별자 miles가 할당된 변수를 프로젝트 후반에 킬로미터 단위의 값으로 변경해야 할 수 있습니다. 이 경우 유지보수자가 나중에 혼란을 피하기 위해 해당 변수에 대한 모든 참조를 변경해야 합니다. 이를 방지하려면 대신 distance를 식별자로 사용하세요.

JavaScript는 밑줄 문자 (_)로 시작하는 식별자에 특별한 권한이나 의미를 부여하지 않지만, 일반적으로 변수, 메서드 또는 속성이 '비공개'임을 나타내는 데 사용됩니다. 즉, 이를 포함하는 객체의 컨텍스트 내에서만 사용하도록 의도되었으며 해당 컨텍스트 외부에서 액세스하거나 수정해서는 안 됩니다. 이는 다른 프로그래밍 언어에서 가져온 약속이며 JavaScript의 비공개 속성이 추가되기 이전부터 사용되었습니다.

변수 선언

JavaScript가 식별자를 인식하도록 하는 방법에는 여러 가지가 있습니다. 이를 '변수 선언'이라고 합니다. 변수는 let, const 또는 var 키워드를 사용하여 선언됩니다.

let myVariable;

let 또는 var를 사용하여 언제든지 변경할 수 있는 변수를 선언합니다. 이러한 키워드는 JavaScript 인터프리터에 문자열이 값을 포함할 수 있는 식별자라고 알려줍니다.

최신 코드베이스에서 작업할 때는 var 대신 let를 사용하세요. var는 최신 브라우저에서도 계속 작동하지만, JavaScript의 초기 버전에서 정의되었으며 이후 하위 호환성을 유지하기 위해 변경할 수 없는 직관적이지 않은 동작이 있습니다. var 설계와 관련된 일부 문제를 해결하기 위해 ES6에 let가 추가되었습니다.

선언된 변수는 변수에 값을 할당하여 초기화됩니다. 단일 등호 (=)를 사용하여 변수에 값을 할당하거나 다시 할당합니다. 선언하는 동일한 문에 이를 포함할 수 있습니다.

let myVariable = 5;

myVariable + myVariable
> 10

즉시 초기화하지 않고 let (또는 var)를 사용하여 변수를 선언할 수도 있습니다. 이 경우 코드에서 값을 할당할 때까지 변수의 초깃값은 undefined입니다.

let myVariable;

myVariable;
> undefined

myVariable = 5;

myVariable + myVariable
> 10

undefined 값을 가진 변수는 아직 식별자가 선언되지 않은 정의되지 않은 변수와 다릅니다. 선언하지 않은 변수를 참조하면 오류가 발생합니다.

myVariable
> Uncaught ReferenceError: myVariable is not defined

let myVariable;

myVariable
> undefined

식별자를 값에 연결하는 것을 일반적으로 '바인딩'이라고 합니다. let, var 또는 const 키워드 뒤에 오는 문법을 '바인딩 목록'이라고 하며, 쉼표로 구분된 여러 변수 선언을 허용합니다(예상되는 세미콜론으로 끝남). 따라서 다음 코드 스니펫은 기능적으로 동일합니다.

let firstVariable,
     secondVariable,
     thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;

변수의 값을 재할당하면 JavaScript가 이미 변수가 존재한다는 것을 알고 있으므로 let (또는 var)가 사용되지 않습니다.

let myVariable = true;

myVariable
> true

myVariable = false;

myVariable
> false

기존 값을 기반으로 변수에 새 값을 재할당할 수 있습니다.

let myVariable = 10;

myVariable
> 10

myVariable = myVariable * myVariable;

myVariable
> 100

프로덕션 환경에서 let를 사용하여 변수를 다시 선언하려고 하면 다음과 같은 문법 오류가 발생합니다.

let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable

브라우저의 개발자 도구let (및 class) 재선언에 더 관대하므로 개발자 콘솔에 동일한 오류가 표시되지 않을 수 있습니다.

기존 브라우저 호환성을 유지하기 위해 var는 모든 컨텍스트에서 오류 없이 불필요한 재선언을 허용합니다.

var myVariable = true;
var myVariable = false;

myVariable\
> false

const

const 키워드는 즉시 초기화되어야 하며 이후 변경할 수 없는 변수 유형인 상수를 선언하는 데 사용합니다. 상수의 식별자는 let (및 var)를 사용하여 선언된 변수와 동일한 규칙을 모두 따릅니다.

const myConstant = true;

myConstant
> true

상수는 생성된 후 재할당할 수 없으므로 즉시 값을 할당하지 않고는 상수를 선언할 수 없습니다. 따라서 초기화되지 않은 상수는 영원히 undefined로 유지됩니다. 상수를 초기화하지 않고 선언하려고 하면 문법 오류가 발생합니다.

const myConstant;
Uncaught SyntaxError: missing = in const declaration

let (또는 var)로 선언된 변수의 값을 변경하는 방식으로 const로 선언된 변수의 값을 변경하려고 하면 유형 오류가 발생합니다.

const myConstant = true;

myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'

그러나 상수가 객체와 연결된 경우 해당 객체의 속성을 변경할 있습니다.

const constantObject = { "firstvalue" : true };

constantObject
> Object { firstvalue: true }

constantObject.secondvalue = false;

constantObject
> Object { firstvalue: true, secondvalue: false }

객체를 포함하는 상수는 변경할 수 없는 변경 가능한 데이터 값 참조입니다. 상수 자체는 변경할 수 없지만 참조된 객체의 속성은 변경, 추가 또는 삭제할 수 있습니다.

const constantObject = { "firstvalue" : true };

constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'

변수가 재할당될 것으로 예상되지 않는 경우 상수로 만드는 것이 좋습니다. const를 사용하면 개발팀이나 향후 프로젝트 유지관리자에게 해당 값을 변경하지 말라고 지시하여 코드가 사용되는 방식에 관한 가정(예: 변수가 예상되는 데이터 유형을 기준으로 평가된다는 가정)이 깨지지 않도록 합니다.

변수 범위

변수의 범위는 해당 변수를 사용할 수 있는 스크립트의 일부입니다. 변수의 범위 외부에서는 undefined 값을 포함하는 식별자가 아니라 선언되지 않은 것처럼 정의되지 않습니다.

변수를 선언하는 데 사용하는 키워드와 변수를 정의하는 컨텍스트에 따라 블록 문이 포함된 범위 (블록 범위), 개별 함수 (함수 범위) 또는 전체 JavaScript 애플리케이션(전역 범위)으로 변수 범위를 지정할 수 있습니다.

차단 범위

let 또는 const를 사용하여 선언하는 모든 변수는 가장 가까운 포함 블록 문으로 범위가 지정됩니다. 즉, 해당 블록 내에서만 변수에 액세스할 수 있습니다. 포함 블록 외부에서 블록 범위 변수에 액세스하려고 하면 존재하지 않는 변수에 액세스하려고 할 때와 동일한 오류가 발생합니다.

{
    let scopedVariable = true;
    console.log( scopedVariable );
}
> true

scopedVariable
> ReferenceError: scopedVariable is not defined

JavaScript에 관해서는 블록 범위 변수가 이를 포함하는 블록 외부에 존재하지 않습니다. 예를 들어 블록 내부에서 상수를 선언한 다음 동일한 식별자를 사용하는 다른 상수를 블록 외부에 선언할 수 있습니다.

{
  const myConstant = false;
}
const myConstant = true;

scopedConstant;
> true

선언된 변수는 상위 블록으로 확장할 수 없지만 모든 하위 블록에서 사용할 수 있습니다.

{
    let scopedVariable = true;
    {
    console.log( scopedVariable );
    }
}
> true

선언된 변수의 값은 하위 블록 내에서 변경할 수 있습니다.

{
    let scopedVariable = false;
    {
    scopedVariable = true;
    }
    console.log( scopedVariable );
}
> true

새 변수가 상위 블록의 변수와 동일한 식별자를 사용하더라도 하위 블록 내에서 let 또는 const로 오류 없이 초기화할 수 있습니다.

{
    let scopedVariable = false;
    {
    let scopedVariable = true;
    }
    console.log( scopedVariable );
}
> false

함수 범위

var를 사용하여 선언된 변수의 범위는 가장 가까운 포함 함수(또는 클래스 내의 정적 초기화 블록)로 지정됩니다.

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

함수가 호출된 후에도 마찬가지입니다. 함수가 실행되는 동안 변수가 초기화되더라도 함수의 범위 외부에서는 변수를 사용할 수 없습니다.

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

myFunction();
> true

scopedVariable;
> ReferenceError: scopedVariable is not defined

전역 범위

전역 변수는 전체 JavaScript 애플리케이션에서 모든 블록과 함수 내에서 페이지의 모든 스크립트에 사용할 수 있습니다.

이는 바람직한 기본값으로 보일 수 있지만 애플리케이션의 모든 부분에서 액세스하고 수정할 수 있는 변수는 불필요한 오버헤드를 추가하거나 동일한 식별자를 가진 애플리케이션의 다른 위치에 있는 변수와 충돌을 일으킬 수 있습니다. 이는 서드 파티 라이브러리 및 사용자 분석과 같이 페이지 렌더링과 관련된 모든 JavaScript에 적용됩니다. 따라서 가능하면 전역 범위를 오염시키지 않는 것이 좋습니다.

상위 함수 외부에서 var를 사용하여 선언되거나 상위 블록 외부에서 let 또는 const를 사용하여 선언된 모든 변수는 전역입니다.

var functionGlobal = true; // Global
let blockGlobal = true; // Global

{
    console.log( blockGlobal );
    console.log( functionGlobal );
}
> true
> true

(function() {
    console.log( blockGlobal );
    console.log( functionGlobal );
}());
> true
> true

변수를 명시적으로 선언하지 않고 값을 할당하면 (즉, var, let 또는 const를 사용하여 만들지 않음) 함수나 블록 내에서 초기화되더라도 변수가 전역 범위로 승격됩니다. 이 패턴을 사용하여 만든 변수를 '암시적 전역'이라고도 합니다.

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

변수 호이스팅

변수 및 함수 선언은 범위 상단으로 호이스팅됩니다. 즉, JavaScript 인터프리터는 스크립트의 어느 지점에서 선언된 변수를 처리하고 스크립트를 실행하기 전에 이를 괄호로 묶인 범위의 첫 번째 줄로 효과적으로 이동합니다. 즉, var를 사용하여 선언된 변수는 오류가 발생하지 않고 변수가 선언되기 전에 참조될 수 있습니다.

hoistedVariable
> undefined

var hoistedVariable;

초기화가 아닌 변수 선언만 호스팅되므로 var, let 또는 const로 명시적으로 선언되지 않은 변수는 호이스팅되지 않습니다.

unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined

unhoistedVariable = true;

앞서 언급한 바와 같이 선언되었지만 초기화되지 않은 변수에는 undefined 값이 할당됩니다. 이 동작은 호이스팅된 변수 선언에도 적용되지만 var를 사용하여 선언된 변수 선언에만 적용됩니다.

hoistedVariable
> undefined

var hoistedVariable = 2 + 2;

hoistedVariable\
> 4

이 직관적이지 않은 동작은 초기 JavaScript 버전에서 이루어진 설계 결정에서 비롯된 것으로, 기존 사이트가 손상될 위험이 없이는 변경할 수 없습니다.

letconst는 변수가 생성되기 전에 액세스될 때 오류를 발생시켜 이 동작을 해결합니다.

{
    hoistedVariable;

    let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization

이 오류는 선언되지 않은 변수에 액세스하려고 할 때 발생할 수 있는 'hoistedVariable is not defined' 오류와 다릅니다. JavaScript가 변수를 호이스팅했으므로 변수가 지정된 범위 내에 생성된다는 것을 알고 있습니다. 그러나 선언 전에 undefined 값으로 이 변수를 사용할 수 있도록 하는 대신 인터프리터는 오류를 발생시킵니다. let 또는 const (또는 class)로 선언된 변수는 '시간적 데드존' ('TDZ')에 있다고 합니다. 이 시간적 데드존은 괄호로 묶인 블록의 시작부터 변수가 선언된 코드의 지점까지입니다.

시간적 데드존을 사용하면 작성자가 let의 동작을 var보다 더 직관적으로 파악할 수 있습니다. const 설계에도 중요합니다. 상수는 변경할 수 없으므로 범위 상단으로 호이스팅되고 암시적 값 undefined가 지정된 상수는 의미 있는 값으로 초기화할 수 없습니다.

이해도 확인

식별자를 시작할 수 있는 문자 유형은 무엇인가요?

편지
밑줄
숫자

값을 언제든지 변경할 수 있는 변수를 선언하는 데 선호되는 방법은 무엇인가요?

let
const
var