JS) 함수, 블럭 스코프 var / let, const 차이점, 호이스팅

kangdari·2020년 3월 22일
0

함수 스코프(function scope)

함수에 의해서 생기는 유효 범위

블럭 스코프(block scope)

블럭에 의해 생기는 유효 범위 => {}
ex) {}, if문, for문, while문, switch문

var

function-scope를 갖는 변수 선언에 사용 됨.

(function() {
    var a = 10;
    (function() {
        var a = 20;
        console.log(a); // 20
    })()
    console.log(a) // 10
})()
console.log(a); // ReferenceError: a is not defined

function hasValue (p) {
    console.log(v); // undefined, 호이스팅
    if(p){
        var v = 'blue'
        console.log(v) // blue
    }else{
        var v = 'red'
        console.log(v)
    }
    console.log(v) // blue
}
hasValue(10)

var는 block-scope의 영향을 받지 않습니다.

let

block-scope(블럭 유효 범위)를 갖는 지역 변수를 선언하는데 사용.
재선언이 불가능. 변수 재할당은 가능. ES6부터 추가

{
    let a = 10
    {
        let a = 20
        console.log(a) // 20
    }
    console.log(a) // 10
}
console.log(a) // ReferenceError: a is not defined
function hasValue (p) {
    console.log(v); // ReferenceError: v is not defined
    if(p){
        let v = 'blue'
        console.log(v) 
    }else{
        let v = 'red'
        console.log(v)
    }
    console.log(v) 
}
hasValue(10)

let은 block-scope를 가지기 때문에 참조할 변수 v가 존재하지 않아 ReferenceError가 발생한다.

const

block-scope(블럭 유효 범위)를 가지면서 단 한번만 할당할 수 있는 상수(변수)를 선언하는데 사용.
재선언, 변수 재할당 불가능.
반드시 초기화가 필요하다. ES6부터 추가

const a = 1;
console.log(a);
a = 2;      // TypeError: Assignment to constant variable.

const로 선언한 변수는 값을 변경할 수 없다.

단, const로 선언한 상수 값이 객체이거나 배열이면 수정이 가능하다.

const obj = {a: 1, b: 2};
obj.a = 3;
console.log(obj.a); // 3

당연히 for문에서 const를 사용하면 오류가 발생한다.

for(const i=0 ; i<5; i++){
    // TypeError: Assignment to constant variable.
    console.log(i);
}

하지만 for...in문의 경우 다르다. const로 선언하여도 오류가 발생하지 않는다.

var obj = {
    prop1: 1,
    prop2: 2,
    prop3: 3,
}

for(const prop in obj){
    console.log(prop)
}
// prop1
// prop2
// prop3

그 이유는 for...in문이 내부적으로 아래와 같이 작동하기 때문이다.

{
    let keys = Object.keys(obj);
    for(let i=0; i<keys.length; i++){
        const prop = obj[keys[i]];
        console.log(prop)
    }
}

Hoisting

변수 선언의 끌어올림.
프로그램에서 변수가 중간에서 선언되더라도 변수가 프로그램 첫 머리에 선언되는 것처럼 다른 문장앞에서 생성하는 것을 호이스팅.

console.log(x); // undefined
~~~
var x ;
console.log(a()); // 1
~~~
function a () {return 1;}

기존의 JS에서는 호이스팅으로 인해서 변수나 함수가 코드 하단에 선언되어있어도 코드 상단 부분에서 호출하여도 에러가 발생하지않는다. 이는 실무에서 에러를 찾아 고칠 수 없는 상황이 발생할 수 있어 문제가 발생한다.

이를 고치기 위해서 ES6에서는 기존의 var와 함수 선언문에 대해서는 그대로 유지하되
let과 const에서는 위와 같이 동작하지 않도록 하였다.

기존 var의 호이스팅

  1. 변수명만 위로 끌어 올리고
  2. undefined 할당..
(function() {
  var a = 10;
  (function() {
    console.log(a); // undefined
    var a = 20;
  })();
  console.log(a); // 20
})();
console.log(a); // ReferenceError: a is not defined

const, let의 호이스팅

TDZ(Temporal Dead Zone)(임시 사각지대)
const, let에 대해서 실제로 변수가 선언된 위치가 오기전에 해당 변수를 호출할 수 없음.
(Ecmascript에서 정의된 개념은 아님)

  1. 변수명만 위로 끌어올리고 끝...
    (호이스팅은 하되 값을 할당하지 않음...)
if(true){
    let a = 10
    if(true){
        // ReferenceError: Cannot access 'a' before initialization
        console.log(a) // 호이스팅은 하되 값을 할당하지 않음.. TDZ 영향
        const a = 20 
    }
    console.log(a)
}
console.log(a)
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 5;

전역객체의 프로퍼티 ??

var

var c = 30
console.log(window.c) // 30
console.log(c) // 30
delete c // var로 선언된 c는 전역변수 이자 전역객체이기 때문에 삭제할 수 없어 false
console.log(window.c) // 30
console.log(c) // 30

전역변수 범위에서 var로 변수 선언 시 전역 변수와 전역 객체의 프로퍼티 값으로 설정됩니다.
그래서 window.c는 전역 객체의 프로퍼티이며, c는 전역 변수 값입니다.

delete c는 delete window.c와 같은 뜻으로 전역 객체의 프로퍼티를 삭제하는 명령어입니다.
var로 선언된 c는 전역변수 이자 전역객체이기 때문에 삭제할 수 없어 false를 반환합니다.

let

전역 공간에서 let으로 선언하면 전역 변수로만 선언되고 전역 객체로 선언은 안됨.

let b = 10
console.log(window.b) // undefined
console.log(b) // 10
delete b // false b는 전역객체의 프로퍼티가 아니므로 삭제 안됨.

0개의 댓글