본문 바로가기

언어(JS,TS)/JavaScript

JavaScript [스코프 : 함수스코프 vs 블록스코프]

스코프(scope)

  • 변수에 접근할 수 있는 범위
  • 전역 스코프(global)는 어디에서든 해당 변수에 접근 가능한 걸 의미한다. (전역변수)
  • 지역 스코프(local)의 경우, 한정적인 범위에서 해당 변수에 접근이 가능하다. (지역변수)
    • 지역 스코프에는 함수 스코프 블록 스코프가 있음

변수에 접근할 수 있는 범위

컨텍스트(context)

this 키워드 값이 무엇인지를 나타내는 용어

현재 실행 컨텍스트 내에서 어떤 객체를 참조하고 있는지를 의마한다. 컨텍스트는 객체를 기반으로 한 용어이다.

 

# 함수스코프

  • 자바스크립트는 기본적으로 함수 스코프를 따르는 언어
  • 새로운 함수가 생성될때마다 새로운 스코프 형성
    - 함수 안에 선언한 변수는 해당 함수 안에서만 접근할 수 있음
if(ture) {
	var variable = '1';
}
console.log(variable)// '1'
  • 위 코드에서는 함수가 선언되어 있지 않기 때문에 새로운 환경, 새로운 스코프가 형성되지 않는다.
  • 스코프가 형성되지 않으므로 동일한 실행 컨텍스트 내에서 존재하는 것이다.
  • 그렇기때문에 어디에서나 variable변수에 대한 접근이 가능하다.
function a() {
	var variable = '1';
}
console.log(variable); //ReferenceError

a()
console.log(variable); //ReferenceError
  • 이 경우는 함수 생성과 동시에 a함수에 대한 새로운 실행 컨텍스트가 생성되고,
    이 실행 컨텍스트 내부에 존재하는 변수환경(variable environment)에 secret변수가 저장
  • 따라서 함수 외부에서 variable에 접근하려고 할 경우 스코프가 다르기 때문에 해당 변수에 접근이 불가능(실행시켜도 마찬가지)
  • 함수외부는 global scope이고, 함수 내부는 a함수의 scope인데 부모스코프는 자식스코프에서 간섭할 수 없기 떄문에 접근이 불가능하다.

# 블록 스코프

  •  블록 {}이 생성될 때마다 새로운 스코프가 형성
  • 원래 자바스크립트는 함수 스코프를 따르지만, 
    let과 const 키워드의 등장으로 블록 스코프를 형성하는 것도 가능
function loop() {
	for(var i = 0; i < 5; i++) {
		console.log(i);
	}
	console.log('final:',i);
}
loop();
/*
	0
	1
	2
	3
	4
	final: 5
*/

console.log(i); // ReferenceError
  • 이 코드를 보면, for문 안에서 변수 i를 var 키워드로 초기화 해줬다.
  • 이 경우에는 블록 스코프가 아닌 함수 스코프를 따르게 되는데,
    for문 안쪽과 바깥 쪽에서 모두 변수 i에 접근해서 console.log를 하고 있다.
  • 이 때는 어차피 loop이라는 함수 스코프 안에 둘 모두 존재하기 때문에
    문제 없이 for문 안이든 밖이든 문제없이 i에 접근해서 값을 출력한다.
function  loop() { 
	for (let i = 0; i < 5; i++) { 
		console.log(i); 
	} 
	console.log('final', i);  // ReferenceError
} 
loop(); /* ReferenceError: i is not defined */
  • let으로 선언한 순간, 변수i는 for문 내에서만 종속되며, for문 외부에서는 i에 접근할 수가 없다.
  • 블록 스코프 그렇다.

## 요약

스코프란?

  • 변수에 접근할 수 있는 범위
  • 함수 실행컨텍스트 내부의 변수 환경

var와 let,const를 함수스코프, 블록스코프??

  • var => 함수스코프
  • let, const => 블록스코프

 

## 스코프가 달라서 생기는 특이점

let

(function () {
  for (let i = 0; i < 5; i++) {
    setTimeout(() => {
      console.log('i:', i);
    }, i * 1000);
  }
})();

/*
    i: 0
    i: 1
    i: 2
    i: 3
    i: 4
*/

var

(function () {
  for (var i = 0; i < 5; i++) {
    setTimeout(() => {
      console.log('i:', i);
    }, i * 1000);
  }
})();

/*
    i: 5
    i: 5
    i: 5
    i: 5
    i: 5
*/