4. 스코프 역활을 하는 블록
JS에서 함수가 가장 보편적이고 널리 퍼진 디자인 접근법 이지만,
다른 스코프 단위도 존재하며 이를 이용하면 더 깔끔한 코드를 작성할 수 있다.
예를 들어 블록 스코프를 보자.
JS는 지원하지 않지만 아래의 코드같은 모습은 많이 봤다.
for(let i = 0; i < 10; i++){
...
}
변수 i를 for 반복문의 시작부에 선언하는 이유는
i를 오직 for 반복문과 관련해서 사용하려하기 때문이다.
블록 스코프의 목적은 변수를 최대한 사용처 가까이에서 최대한 작은 유효 범위를 갖도록 선언하는 것이다.
위의 코드에서는 그 목적을 제대로 반영하는 것 같다.
4.1. with
with은 사용하게 되면 동작 속도가 저하되지만,
블록 스코프의 형태를 보여주는 한 예로 with 문안에서 생성된 객체는
바깥 스코프에 영향을 주는 일 없이 with문이 끝날 때까지만 존재한다.
4.2. try / catch
ES3에서 try / catch 문 중 catch부분에서 선언된 변수는 catch 블록 스코프에 속한다.
try{
...
}
catch (err) {
console.log(err);
}
console.log(err); // ReferenceError: 'err' not found
같은 스코프 내에 같은 확인자 이름으로 오류 변수를 선언한 catch 문이 둘 이상 있을 경우 경고를 보낸다.
4.3. let
키워드 let은 선언된 변수를 둘러싼 아무 블록(주로 {})의 스코프에 붙인다.
var a = true;
if(a) {
let b = a * 2;
b = func1( b );
console.log( b );
}
console.log(b); // ReferenceError
코드를 작성하며 블록을 왔다 갔다할 때 주의 하지 않으면,
변수가 어느 블록 스코프에 속한 것인지 착각하기 쉽다.
위의 문제는 블록 스코프에 사용하는 블록을 명시적으로 생성하면 이런 문제를 해결할 수 있다.
변수가 어느 블록에 속했는지 훨씬 더 명료해지기 때문이다.
var a = true;
if(a) {
{
let b = a * 2;
b = func1( b );
console.log( b );
}
}
console.log(b); // ReferenceError
if문 안에 명시적인 블록을 만들었다.
위와 같이 블록을 만들어주면 추후 리펙토링 하면
if 문의 위치나 의미를 변화시키지 않고도 전체 블록을 옮기기가 쉬워진다.
호이스팅은 선언문이 어디에서 선언됐든 속하는 스코프 전체에서 존재하는 것처럼 취급되는 작용이다.
하지만, let을 사용한 선언문은 속하는 스코프에서 호이스팅 효과를 받지 않는다.
let으로 선언된 변수는 실제 선언문 전에는 명백하게 존재하지 않는다.
{
console.log(b); // ReferenceError!
let b = 2;
}
가비지 콜렉션
블록 스코프가 유용한 또 다른 이유는 메모리를 회수하기 위한 클로저 그리고 가비지 콜렉션과 관련이 있다.
명시적으로 블록을 선언해서 변수의 영역을 한정하는 것은 효과적인 코딩 방식이므로 익혀두자
const func1 = (a) => {
// work something
}
{
let bigData = {...};
func(bigData);
}
...
위의 코드에서는 블록 스코프가 엔진에게 bigData가 더는 필요없다는 것을 명료하게 알려준다.
let 반복문
let은 for 반복문에서 유용하게 사용된다.
for(let i = 0; i < 10; i++){
...
}
let은 i를 for 반복문에 묶었을 뿐만 아니라
반복문이 돌 때마다 변수를 다시 묶어서 이전 반복의 결과값이 제대로 들어가게 한다.
let 선언문은 둘러싼 함수(또는 글로벌) 스코프가 아니라 가장 가까운 임의의 블록에 변수를 붙인다.
따라서 이전에 var 선언문을 사용해 작성된 코드는 함수 스코프와 연계가 있을 수 있기에
리팩토링시 var를 let으로 바꾸는 것 이상의 주의가 필요하다.
리팩토링 전
var a = true, b = 10;
if(a){
var c = 3;
if(b > c){
console.log(b);
}
...
}
리팩토링 후
var a = true, b = 10;
if(a){
let c = 3;
if(b > c){
console.log(b);
}
...
}
const
키워드 const 역시 블록 스코프를 생성하지만, 선언된 값은 고정된다.
3.5 정리하기
1. JS에서 함수는 스코프를 이루는 가장 흔한 단위이다.
다른 함수 안에서 선언된 변수와 함수는 본질적으로 다른 스코프로부터 숨겨진 것이다.
2. 함수는 결코 유일한 스코프 단위가 아니다.
3. 블록 스코프는 함수만이 아니라 임의의 코드 블록에 변수와 함수가 속하는 개념이다.
4. try / catch 구조의 catch 부분은 블록 스코프를 갖는다.
5. let은 임의의 코드 블록 안에 변수를 선언할 수 있다.
6. 블록 스코프는 var 함수 스코프를 완전히 대체할 수 없으며
두 기능은 공존하며 함수 스코프와 블록 스코프 기술을 같이 사용할 수 있어야한다.
(상황에 따라 두 기술을 적절한 곳에 사용해야 한다.)
'JavaScript > You Don't know JS' 카테고리의 다른 글
I don't know JS YET) 호이스팅 (0) | 2022.12.23 |
---|---|
I don't know JS YET) 함수 vs 블록 스코프 - 1 (1) | 2022.12.21 |
I don't know JS YET) 렉시컬 스코프 (0) | 2022.12.16 |
I don't know JS YET) 스코프란 무엇인가 (0) | 2022.12.15 |
JS 복습 1주차 / 4. 강제 변환 Coercion (0) | 2022.11.07 |