Scope의 정의

 

 

 

scope란 '변수가 어디까지 쓰일 수 있는지에 대한 범위'를 의미한다.

 

 

 

 

Block

 

block이란 중괄호{ }로 감싸진 것을 말한다.

 

function hello() {} //함수

if (true) {} //if문

for(let i = 0; i < 0; i++) {}//for문

function,if,for의 내부는 하나의 block이다.

 

블록{} 내부에 변수가 정의되면 그 변수는 블록 내부에서만 사용할 수 있다.

 

그래서 블록 내부에서 정의된 변수를 local(지역) 변수라고 부른다.

 

 

 

 

Block Scope

 

 

let, const를 사용한 변수는 블록(block) scope를 가진다.

 

var를 사용한 변수는 함수(function) scope를 가진다고 한다.

 

 

이 둘의 차이점은 무엇일까?

 

 

 

<let, const>

function test () {
  if (true) {
    let var1 = "사과"
  }
  
  return var1;
}

consol.log(test())

위의 코드를 실행하면 ReferenceError: var1 is not defined라는 오류가 나온다.

 

if문 block안에 let으로 선언한 var1은  let이 블록 범위만을 가지기 때문에 function에서는 사용할 수 없는 것이다.

 

let을 const로 바꿔도 똑같은 결과가 나온다.

 

 

 

 

<var>

function test () {
  if (true) {
    var var1 = "사과"
  }
  
  return var1
}

console.log(test()) //사과

var를 사용할 시 console.log(test())는 "사과"라는 값이 정상적으로 출력된다.

 

왜냐하면 if문 block안에 선언을 했다고 하지만 var는 함수 범위를 가지기 때문이다.

 

 

 

function test () {
  if (true) {
    if (true) {
      var var1 = "사과"
    }
  }
  
  return var1
}

console.log(test())

 

다음과 같이 if문을 더 깊이 중첩해서 var를 선언해도 함수 범위이기 떄문에 정상적으로 출력된다.

 

 

function test () {
  if (true) {
    if (true) {
      var var1 = "사과"
    }
  }
  
  return var1
}

console.log(var1)

물론 함수를 벗어나서 console.log(var1)을 하면 ReferenceError: var1 is not defined오류가 나온다.

var는 전역 스코프(global scope)가 아니기 때문이다. 

 

 

 

 

 

Global(전역) Scope

 

scope은 변수가 선언되고 사용할 수 있는 공간이다.

 

block밖인 global scope에서 만든 변수를 global variable(전역변수)라고 한다.

 

이때는 let, const, var 모두 global Scope를 가진다.

 

코드 어디서든 접근해서 변수 값을 확인할 수 있다.

 

const color = 'red'; // let, var넣어도 똑같다.
 
function returnColor() {

  return color;
}
 
console.log(returnColor()); //red

 

 

 if (true) {
   if (true) {
     var var1 = "사과"
   }
  }
  
console.log(var1)

단, var는 원래 함수 scope이기 떄문에 function의 block안에 있지 않는 위의 경우에서도 var1은 Global Scope를 가진다.

 

 

 

 

 

재선언,재할당

 

let fruit = "사과"

//fruit = "애플" <- 가능(재할당)
// let fruit = "애플" <- 불가능(재선언)

function test () {
  let fruit = "바나나"
  return fruit
}

console.log(test())

본래라면 let으로 fruit = "사과"라고 선언하면 let은 값의 재할당은 가능하지만 재선언은 불가능하다.

 

하지만 그건 같은 scope범위에 있을 때의 이야기다.

 

함수 block안에서의  let fruit전역스코프에 있는 let fruit하고 아예 다른 변수인 것이다.

즉, Scope가 다르기 때문에 오류가 일어나지 않고 잘 작동하는 것이다.

 

const도 마찬가지로 오류가 일어나지 않는다.

 

 

var의 경우는 애초에 재선언,재할당이 가능하다.

물론, 함수인 경우 block안에 있는 var fruit과 전역스코프에 있는 var fruit는 아예다른 변수인 것은 똑같다.

 

 

 

 

 

 

 

 

Scope 오염

 

 

<예제1>

const satellite = 'The Moon';
const galaxy = 'The Milky Way';
let stars = 'North Star';

const callMyNightSky = () => {
   stars = 'Sirius'; //오염발생!
  
	return 'Night Sky: ' + satellite + ', ' + stars + ', ' + galaxy;
};

console.log(callMyNightSky()); //Night Sky: The Moon, Sirius, The Milky Way
console.log(stars); //Sirius

 

실수로 callMyNightsky 함수에서 let stars = 'Sirius';를 하지 않고  stars = 'Sirius';라고 해버렸다.

 

그래서 전역스코프에 있는 stars의 값이 'Sirius'로 변해버렸다. <- Scope오염이 발생...! 

 

console.log(stars)를 하면 이제 값이 North Star가 아니라 Sirius로 출력된다.

 

 

 

 

<예제2>

function logSkyColor() {
  const dusk = true;
  let myColor = 'blue'; 
  if (dusk) {
    let myColor = 'pink';
    console.log(myColor); // pink 오염발생!
  }
  console.log(myColor); // blue 
}

logSkyColor()

함수 안에 myColor변수를 사용했고 if문 안에서도 myColor변수를 사용했다.

물론 이렇게해도 서로 다른 변수이기 때문에 작동하는데 전혀 문제가 없지만 

 

이런식으로 같은 변수 이름을 사용하는 것은 Scope(namespace)를 오염시키는 것이다.

 

(원래 함수 블록스코프의 myColor만 있었는데  if문 블록스코프에 같은 이름을 가진 myColor가 나타났다.

그래서 myColor라는 변수의 namespace가 오염된 것이다.)

 

//////////////////////////////////////////////////////////////////////////////////

 

namespace라는 것은 변수 이름을 사용할 수 있는 범위라는 뜻입니다.

scope라고도 하고 특히 변수이름을 얘기할 때는 namespace라고도 합니다.

 

///////////////////////////////////////////////////////////////////////////////////

 

 

 

 

 

 

 

 

좋은 Scoping 습관

 

 global 변수가 여기저기서 수정되면 안되기 때문에 변수들은 block scope으로 최대한 나눠놔야 합니다.

  • 타이트한 scope(tightly scoping)의 변수는 코드 품질을 올려줍니다!
  • 코드가 block 으로 명확하게 구분되기 때문에 코드 가독성이 올라갑니다.
  • 코드가 한줄 한줄 쭉 나열된 것이 아니라 각각의 기능별로 block을 나누면 코드가 이해하기 쉬워집니다.
  • 나중에 코드를 수정할 일이 있을 때, 코드를 오랜만에 보더라도 잘 나뉘어 있어서 유지보수가 쉬워집니다.
  • 프로그램이 끝날때까지 변수가 살아있는 것이 아니라서(block이 끝나면 local 변수의 삶이 끝나서) 메모리 절약도 됩니다.

즉, 한마디로 요약하면 global 변수는 쓰지 않도록 노력해야 하고, 최대한 {} 내에서 let, const 을 사용하여 변수를 새로 만들어서 쓰자는 말입니다.

 

 

 

 

 

 

 

'JScript > Today I learned' 카테고리의 다른 글

formData의 값을 console.log로 볼 수 없는 원인  (0) 2021.07.25
TIL#11 Array.reduce()함수  (0) 2021.07.11
TIL#09 UI vs API  (0) 2021.05.09
TIL#08 라이브러리와 프레임워크  (0) 2021.05.09
TIL#07 객체  (0) 2021.05.09

+ Recent posts