상세 컨텐츠

본문 제목

함수 레벨 스코프와 블록 레벨 스코프의 비교와 클로저

Front-End/Javascript

by devloper-jun 2024. 9. 19. 13:45

본문

1. 함수 레벨 스코프 ( function level scope) 

 - var 

 

2. 블록 레벨 스코프 (block level scope)

 - let, const

 - ECMA 2015 (ECMA6) 이 후 도입되었으며, 이전 버전에서는 블록문 스코프가 없었음.

 

3. 차이점

3.1. 변수 선언

 - var: 실행 맥락에 따라 지역 및 전역 변수를 선언하는데 모두 사용되며 선언되지 않은 전역변수를 생성할 수 있으므로 의도되지 않은 동작을 생성할 수 있음.

 - let, const:  지역 변수를 선언하는데 사용될 수 있음.

3.2. 변수 할당

 - 지정된 초기값 없이 var, let 문을 사용해서 선언된 변수는 undefined 값을 갖으며, 선언되지 않은 변수에 접근할 경우 ReferenceError 발생.

var a;
console.log("a : " + a) // a : undefined

console.log("b : " + b) // b : undefined
var b;

let x;
console.log("x : " + x) // x : undefined

console.log("y : " + y) // y : Uncaught ReferenceError: y is not defined
let y;

 

3.3. 변수 스코프

 - 함수 바깥에 변수를 선언하면 현재 문서의 다른코드에서 해당 변수를 사용할 수 있기에 전역 변수라 하며, 함수 내부에 선언 했을 경우 오직 해당 함수 안에서만 사용할 수 있기에 지역 변수라 함.

 - ECMA2015(ECMA6) 이전에서는 블록문 scope가 없으므로, 오히려 블록 내에 선언된 변수는 그 블록내에 존재하는 함수에 지역적임.

if(true) {
	var x = 5;
}
console.log("x: " + x); // x: 5

if(true) {
	let y = 5;
}
console.log(y); // ReferenceError: y is not defined

 

3.4. 변수 호이스팅

 - var: 변수가 함수나 문의 최상단으로 올려지는 것이며, 끌어올려진 변수는 undefined 값을 반환하므로, 해당 변수를 사용 혹은 참조한 후에 선언 및 초기화 하더라도 undefined를 반환함.

// Example 1-1
console.log(x === undefined); //true
var x = 3;

// Example 1-2 (Example 1-1과 동일) 
var y;
console.log(y === undefined); //true
y = 3

// Example 2-1
var me = "me"
(function () {
	console.log(me); // undefined
	var me = "local"
})()

// Example 2-2 (Example 2-1과 동일)
var my = "my"
(function () {
	var my;
    console.log(my) // undefined
    my = "local"
})

 

- let, const: 변수를 블록의 상단으로 끌어올리지만 초기화하지 않으며, 변수가 선언되기 전에 temporal dead zone에 위치하기 때문에 블록안의 변수를 참조하게 되면 ReferenceError를 발생.

console.log(x); // ReferenceError
let x = 3;

 

3.5. 함수 호이스팅

 - 함수 선언으로는 호이스팅 되지만 함수 표현식으로는 호이스팅 되지 않음.

// 함수 선언
foo(); // foo
function foo () {
	console.log("foo")
}

//함수 표현식
bar();	// TypeError: bar is not a function
var bar() = function () {
	console.log("bar")
}

 

3.6. 변수 스코프와 클로저

/* 0부터 1초 간격으로 0 ~ 4 까지 출력하는 함수 예제 */
// Example 1 (전역 변수에 따른 오류)
for (var i = 0; i < 5; i++) {
	setTimeout (function() {
 		console.log(i)   
    }, i * 1000)
}
/* 
 4초 뒤에 5만 출력 5번 출력
 i가 전역 변수로 for문을 순회한 이후 테스트 큐데 있는 setTimeout을 실행하려고 했을 때 전역 i는 5로 설정.
*/

// Example 2 (블록 레벨로 변수 설정)
for (let x = 0; x < 5; x++) {
	setTimeout (function() {
 		console.log(x)   
    }, x * 1000)
}
/*
 let은 기보적으로 블록 레벨 스코프를 가지게 되므로 x가 for문을 순회하면서 각각의 스코프를 갖게 되므로 setTimeout이 
 실행되는 시점에서도 유효배해 각 콜백에 x 값을 바라보게 함.
*/

// Example3 (클로저 함수의 활용)
for(var y = 0; i < 5; i++) {
	setTimeout(
        (function(sec) {
              return function () {
                console.log(sec)
              }
        })(y), 
        y * 1000
  	)
}
/*
 for문 내부에 즉시 실행 익명 함수를 선언. 이 함수는 y를 인수로 받으며, 함수 내부에서는 이를 sec 인수에 저장 후
 setTimeout의 콜백 함수에 넘긴다. setTimeout의 콜백 함수가 바라보는 클로저는 즉시 실행 익명 함수가 되며, 
 각 for 문마다 생성되고 실행되기를 반복하며, 각각의 함수는 고유한 스코프, 즉 고유한 sec를 가지게 된다.
*/

- 클로저의 기본 개념인 '함수와 함수가 선언된 어휘적 환경의 조합'을 주의 깊게 살펴봐야 클로저를 제대로 활용할 수 있다.

- 주의점으로는 클로저를 사용하는 데는 비용이 듬. 생성될 때마다 선언적 환경을 기억해야 하므로 추가적인 비용이 발생.

 

2024.09.19 - [Front-End/Javascript] - 클로저 비용

'Front-End > Javascript' 카테고리의 다른 글

(1) 싱글 스레드와 비동기 통신  (0) 2024.09.19
클로저 비용  (0) 2024.09.19
클로저  (0) 2024.04.22
클래스와 함수의 관계  (0) 2024.04.21
클래스란?  (0) 2024.04.21

관련글 더보기