Javascript Variable


들어가며

  • javascript 에 변수 선언 방법을 알아 봅시다.

var [keyword]

  • var 라는 키워드는 변수를 선언할 때 사용 합니다.
  • 변수는 값을 담는 그릇 입니다.
  • 컴퓨터 관점에서 보면 메모리에 값을 할당 한다 라고 합니다.
    • 메모리 도시에 ADD001 이라는 주소가 있고 그 곳을 별칭 (alias) var01 이라 지정하고 초기값을 1 이라 지정한다고 했을 때
    • var var01 = 1; 이라고 표한 할 수 있겠습니다.
    • var var01 = 1, var02 = 2; 이와 같이 여러 변수를 한 번에 선언 할 수도 있습니다.
  • 변수는 전역변수와 지역변수로 나눌 수 있습니다.
    • 아래 코드에서 function 안에 var z 는 지역 변수 입니다.
    • function 안에 y 는 전역변수 입니다.
    • z는 function 안에서만 사용 가능 합니다.
    • y는 function 바깥에서도 사용 가능 합니다.
  • 아래와 같은 코드는 전역변수 와 지역변수에 개념을 이해 했다면 결과 값을 예측 할 수 있습니다.
  • 허나 아래 코드는 현 es6 문법 상 좋지 않은 코드이며 use strick 을 사용하게 되면 y 변수 역시 지역 변수로 인식 됩니다.
function x() {
  y = 1;     // 일반 javascript 에서는 전역 변수로 인식 됩니다. 단 use strict 모드에서는 오류로 인식 됩니다.
  var z = 2;
  console.log(z); // 2
}

x();

console.log(y); // 1
console.log(z); // Throws a ReferenceError: z is not defined outside x.
// z 변수가 not defined 인 이유는 var z = 2; 는 function 안쪽에서만 사용 되는 지역변수이기 때문 입니다.

hoisting

  • var 라는 변수는 hoisting 과 밀접한 연관이 되어 있습니다.
  • 간단한 예시로 들었던 코드로 설명을 하자면 암묵적으로 2번 코드로 수행이 된다 입니다.
// 1번
number1 = 12;
var number1;
console.log(number1);
//결과 값 : 12

// 2번
var number1;
number1 = 12;
console.log(number1);
//결과 값 : 12

variable scope

변수에 적용 범위를 확인 해 보자면 아래 소스를 보면 이해가 빠를 겁니다.
var 라는 keyword가 존재 해서 지역, 전역 구분이 애매한 부분이 있습니다.
아래 코드 중 typeof는 링크를 따라가 보시면 설명이 있습니다. Link typeof

var x = 0; // x 라는 변수를 선언하고 초기값 0 를 부여 합니다.

console.log(typeof z); // z 변수는 선언되지 않았기 때문에 "undefined"

function a() {
  var y = 2; // y 변수 선언 a 라는 function 안에서 만 사용가능 한 지역 변수 초기값 2 부여

  console.log(x, y); // 0(전역변수 이지만 해당 페이지에서만 사용 가능) 2(지역변수)

  function b() {
    x = 3; // 해당 페이지에서만 사용 가능 한 전역 변수 0 -> 3 으로 대체 
    y = 4; // a function 안에서 사용 가능한 y 변수 2 -> 4로 대체 
    z = 5; // 새로운 z 라는 전역 변수 사용 역시 페이지에서만 사용 가능한 변수 초기값 5
  }

  b(); // b라는 function을 불러와 x y 값은 대체 되고 z 라는 변수가 생성 됨 
  console.log(x, y, z); // 3(전역) 4(a 함수내 지역) 5(전역)
}

a(); // a function 호출 시 b function 도 호출 됨.
console.log(x, z);     // 3(var 가 있지만 페이지 단위로 보았을 때 전역) 5(전역)
console.log(typeof y); // a function 안에서만 사용가능하기 때문에 "undefined"

let [keyword]

  • let 은 block scope 변수를 선언 할 때 사용 합니다.
  • 여기서 block 이란 대게 {} 안쪽을 의미 합니다.
  • page 또한 block 이라 합니다.

let fruit0 = 'anyting';

function foo(){
    if(true){
        var fruit1 = 'apple';        //exist in function scope
        const fruit2 = 'banana';     //exist in block scope
        let fruit3 = 'strawberry';   //exist in block scope

    }
    console.log(fruit1);
    console.log(fruit2);
    console.log(fruit3);
}

foo();
console.log(fruit0);
//result:
//apple
//error: fruit2 is not defined
//error: fruit3 is not defined
//anyting

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // 상위 블록과 같은 변수!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // 상위 블록과 다른 변수
    console.log(x);  // 2
  }
  console.log(x);  // 1
}

let 은 전역객체 생성하지 않음

var x = 'global';
let y = 'global';
console.log(this.x); // "global" 전역 객체의 속성 x를 생성
console.log(this.y); // undefined 전역 객체의 속성 y를 생성하지 않음

생성자를 이용한 변수 접근

var Thing;

{
  let privateScope = new WeakMap();
  let counter = 0;

  Thing = function() {
    this.someProperty = 'foo';
    
    privateScope.set(this, {
      hidden: ++counter,
    });
  };

  Thing.prototype.showPublic = function() {
    return this.someProperty;
  };

  Thing.prototype.showPrivate = function() {
    return privateScope.get(this).hidden;
  };
}

console.log(typeof privateScope);
// "undefined"

var thing = new Thing();

console.log(thing);
// Thing {someProperty: "foo"}

thing.showPublic();
// "foo"

thing.showPrivate();
// 1

블록내에 재선언 시 SyntaxError

if (x) {
  let foo;
  let foo; // SyntaxError thrown.
}

const [keyword]

  • 상수값 지정을 위한 변수 이며
  • 지정 된 값은 일정 패턴이 아닌 이상 변경 이 불가 합니다.
  • Link mozilla-const
// 주의: 상수 선언에는 대소문자 모두 사용할 수 있지만,
// 일반적인 관습은 모두 대문자를 사용하는 것입니다.

// MY_FAV를 상수로 정의하고 그 값을 7로 함
const MY_FAV = 7;

// 에러가 발생함
MY_FAV = 20;

// 7 출력
console.log("my favorite number is: " + MY_FAV);

// 상수를 재선언하려는 시도는 오류 발생 - Uncaught SyntaxError: Identifier 'MY_FAV' has already been declared
const MY_FAV = 20;

// MY_FAV라는 이름은 위에서 상수로 예약되어 있어서 역시 실패함.
var MY_FAV = 20;

// 역시 오류가 발생함
let MY_FAV = 20;

// 블록 범위의 특성을 아는게 중요
if (MY_FAV === 7) { 
    // 블록 범위로 지정된 MY_FAV 라는 변수를 만드므로 괜찮습니다
    // (let으로 const 변수가 아닌 블록 범위를 선언하는 것과 똑같이 동작합니다)
    let MY_FAV = 20;

    // MY_FAV는 이제 20입니다
    console.log('my favorite number is ' + MY_FAV);

    // 이 선언은 전역으로 호이스트되고 에러가 발생합니다.
    var MY_FAV = 20;
}

// MY_FAV는 여전히 7
console.log('my favorite number is ' + MY_FAV);

// const 선언시에 초기값을 생략해서 오류 발생
const FOO; 

// const는 오브젝트에도 잘 동작합니다
const MY_OBJECT = {'key': 'value'};

// 오브젝트를 덮어쓰면 오류가 발생합니다
MY_OBJECT = {'OTHER_KEY': 'value'};

// 하지만 오브젝트의 키는 보호되지 않습니다.
// 그러므로 아래 문장은 문제없이 실행됩니다
MY_OBJECT.key = 'otherValue'; // 오브젝트를 변경할 수 없게 하려면 Object.freeze() 를 사용해야 합니다

// 배열에도 똑같이 적용됩니다
const MY_ARRAY = [];
// 배열에 아이템을 삽입하는 건 가능합니다
MY_ARRAY.push('A'); // ["A"]
// 하지만 변수에 새로운 배열을 배정하면 에러가 발생합니다
MY_ARRAY = ['B']