본문 바로가기
프로그래밍 개발/JS ES6+

Javascript ES6+ Block Scope

by Jinseok Kim 2020. 12. 7.
반응형

 

 

 

Block Scope

 

  • 함수 스코프는 함수의 인해서 생기는 범위, 변수의 유효범위를 뜻하지만 블록 스코프(Block Scope)는 블락 '{}' 에 인해서 생기는 유효범위라고 말할 수 있다.
  • 즉 { }에 인해서 변수의 유효범위가 결정된다.

 

 

 

 

 

{}의 범위

{
  let a = 10
  {
    let a = 20
    console.log(a)
  }
  console.log(a)
}
console.log(a)

 

  • 위의 결과를 보면 첫 번째와 두 번째 a의 값은 정의되어있다는 것을 알 수 있다. 즉 첫 번째와 두 번째로 a를 호출한 범위가 {} 블록 안에서 있기 때문에 정의될 수 있다.
  • 하지만 세 번째 a호출은 {}블락 범위 안에 있지 않고 외부에 있기 때문에 a가 정의되지 않아 에러가 발생한다. 이점이 ES5와 ES6+의 다른점이라고 볼 수 있다.

 

 

 

 

 

 

var와 let, const의 {}블록 범위

function hasValue (p) {
  console.log(v)
  if (p) {
    var v = 'blue'
    console.log(v)
  } else {
    var v = 'red'
    console.log(v)
  }
  console.log(v)
}
hasValue(10)

  • ES6+에서 {} 블록이라는 개념이 생겨도 var로 변수를 지정하면 원래 기능은 그대로 실현되도록 나두었다.
  • 그래서 위의 코드 결과를 보면 마지막 v 호출이 {} 블록 밖에 있어도 blue라는 값이 호출된다.

 

 

 

function hasValue (p) {
  console.log(v)
  if (p) {
    let v = 'blue'
    console.log(v)
  } else {
    let v = 'red'
    console.log(v)
  }
  console.log(v)
}
hasValue(10)

 

  • 하지만 ES6+에서 나온 새로운 변수 let으로 하면 {} 블락 범위가 그대로 실행되어 마지막 v 호출은 {} 블락 범위 내에 없으므로 결과가 오류로 등장한다. const로 변수를 지정해도 똑같은 결과가 나온다.
  • 즉 블록 스코프는 let과 const 라는 변수에서만 작동한다고 볼 수 있다.

 

 

 

 

 

 

블록 스코프와 HOISTING

 

if (true) {
  let a = 10
  if (true) {
    console.log(a) // TDZ 존
    const a = 20
  }
  console.log(a)
}
console.log(a)

  • 자바스크립트 언어 중 값, 식, 문으로 나뉠 수 있는데 이때 문은 if문 for문 swich문이 있을 수 있다. 이때 블록{} 범위는 if문의 if(){}의 {} 또한 블록 범위로 적용된다는 것을 알아야 한다. 
  • 위 코드에서 만약 외부함수 if문안에 들어있는 if문 내부함수에서 호출한 a가 Hoisting이 된다면 a는 아직 a가 변수로 선언되지 않았기 때문에 undefined가 뜨고 Hoisting이 안된다면 a는 자기가 있는 지역 변수에 없다는 것을 외부함수에서 a 변수를 찾기에 a는 10이 등장할 것이다. 
  • 하지만 위의 결과는 레퍼런스 오류가 등장한다. 이것을 TDZ(Temporal Dead Zone 임시 사망 지역)이라고 불린다. 즉 {}블록 안에서 let, const로 변수를 지정하면  let, const 변수로 선언하기 전 위치에 오기전까지는 undefined을 할당하지 않고 바로 변수를 호출할 수 없다는 레퍼런스 오류가 나오는 규칙이 존재하는 것이다.
  • 만약 옛날 버전인 var로 변수를 선언하였다면 레퍼런스 오류가 나오지 않고 그냥 undefined가 할당되어 실제 실무에서 눈치를 못챌 수도 있다.
  • ES6+는 과거 ES5에서 변수 선언과 호출의 위치에 따라 오류가 발생하는 암묵적인 규칙을 없애기 위하여 이러한 규칙으로 보안하였다고 볼 수 있다.

 

 

 

 

 

 

 

 

this와 블록 스코프

 

 

var value = 0
var obj = {
  value: 1,
  setValue: function () {
    this.value = 2; // 메소드 안에 들어있는 this는 메소드를 포함 시킨 obj다.
    (function () {
      this.value = 3 //이 this는 메소드안이 아니라 함수안에 들어있어 전역객체 window다. 
                       대신 a.call(this)을 넣어주면 obj을 this로 쓸 수 있다.
    })();
  }
}
obj.setValue()
console.log(value)
console.log(obj.value)

위 코드와 같이 메소드가 아닌 함수 안의 this는 window 전역 객체를 가르킨다는 문제가 있어 번거롭다.

 

 

 

 

 

let value = 0
let obj = {
  value : 1,
  setValue : function () {
    let a = 10;
    this.value = 2
    {
      let a = 20;
      this.value = 3
    }
  }
}
obj.setValue()
console.log(value)
console.log(obj.value)

하지만 블록 범위를 주면 블록 범위 안에있는 this는 자동으로 바로 위의 외부 함수의 this 범위를 가져와서 사용한다.

 

 

 

 

 

 

 

 

 

for 문과 블록 스코프

 

var sum = 0
for (let i = 1 ; i <= 10 ; i++) {
  sum += i
}
console.log(sum)
console.log(i)

 

  • 위의 코드 중 for문의 인자 중에 let i =1; 이라는 변수를 주었는데 이때 특별한 경우로 let i = 1;은 {}블록으로 감싸있지 않아도 저 for문 안에서만 유효범위를 갖는다.
  • i를 호출한 것은 에러가 뜨는데 이는 let i 변수가 for문 안에서만 유효하다는 것을 알수 있는 거다.
반응형

댓글