본문 바로가기
Javascript

JavaScript - Scope

by Su1993 2020. 7. 4.
반응형

JavaScript에서 scope란, '변수가 어디까지 쓰일 수 있는지'의 범위를 의미한다. (주의. 문법 아님!)

 

***is not defined라는 에러를 한 번이라도 경험했을 수 있었을 텐데, 이 에러는 변수가 아직 선언되지 않았다는 뜻이다.

변수를 선언했는데도 에러를 경험했다면, 변수를 선언한 영역에(block에) 접근할 수가 없어서 컴퓨터가 변수가 선언되었다는 사실을 알지 못해서 그랬을 것이다. 그래서 변수가 선언되지 않았다는 오류 메시지를 출력하게 되는 것이다.

 

어떤 변수는 여기저기서 쓸 수 있는 반면에, 어떤 변수는 특정 함수 내에서만 쓸 수 있다. 이런 개념이 바로 scope이다.


Block

 

scope를 알기 전에 먼저 알아야 할 개념은 block이다. block이란, 중괄호({}, curly brace)로 감싸진 것을 block라고 한다.

예를 들면,

function hi() {
  return 'i am block';
}

///////////

for (let i = 0; i < 10; i++) {
  count++;
}

///////////

if (i === 1) {
  let j = 'one';
  console.log(j);
}

 

function의 내부는 하나의 block이고, for문도 하나의 block이고, if문의 {}도 하나의 block이다.

{}(block) 내부에서 변수가 정의되면 변수는 오로지 {}(block)내부에서만 사용할 수 있다.

{}(block)내부에서 정의된 함수는 local(지역) 변수라고 부른다.


Global(전역) Scope

 

scope은 변수가 선언되고 사용할 수 있는 공간이다. scope 외부(block밖)에서는 특정 scope의 변수에 접근할 수가 없다.

block밖인 global scope에서 만든 변수를 global variable(전역 변수)라고 한다. 코드 어디서든 접근 가능해서 변숫값을 확인할 수 있다.

 

const color = 'red';
console.log(color);

function returnColor() {
  console.log(color);
  return color;
}

console.log(returnColor());

 

returnColor 함수 내에서, returnColor 함수 밖에 있는 color라는 변수를 return 해주었다. color라는 변수는 golbal 변수이기 때문에 returnColor 함수의 block에서도 접근이 가능해서 'red'를 반환한 것이다.


Scope의 오염

 

global 변수를 쓰면 여기저기서 접근하기 쉬워서 좋다고 생각할 수 있지만, 너무 남용하면 프로그램에 문제를 일으킬 수 있다.

global 변수를 선언하면, 해당 프로그램의 어디에서나 사용할 수 있는 global namespace를 갖는다. namespace라는 것은 변수 이름을 사용할 수 있는 범위라는 뜻이다. scope이라고도 하고 특히 변수 이름을 얘기할 때는 namespace라고도 한다.

global 변수는 프로그램이 종료될 때까지 계속 살아있는다. 이 말은 즉, local 변수는 {} - block이 끝나면 더 이상 변수가 살아있지 않고 쓸 수 없다는 말이다.

 

global 변수가 계속 살아있어서 변숫값이 계속 변한다면 해당 변수를 트래킹 하기도 어렵고 이 변수는 어디에서 왜 필요한지 알려면 도대체 어디에서 let, const로 선언을 했는지 찾아 나서야 한다. 

scope이 오염된 대표적인 예이다.

 

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());
console.log(stars);

 

  • stars이라는 global 변수가 있다.
  • callMyNightSky함수에서 새로운 변수를 선언하고 싶었는데 깜빡하고 let 키워드를 작성하지 않았다.
  • callMyNightSky을 호출하면 stars 변수에 "Sirius"이 할당된다.
  • global 변수였던 stars에 영향이 갔다.
  • 다른 함수에서 global 변수인 stars을 사용하고 싶은데 값이 수정된 "Sirius"으로 사용하게 된다.

앞으로 함수가 몇십 개 있을지도 모르는 상황에서 저렇게 global 변수를 남용하다가는 어디서 어떻게 값이 수정될지 알 수 없어진다.


좋은 scoping 습관

 

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

 

타이트한 scope(tightly scoping)의 변수는 코드 품질을 올려준다.

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

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


같은 이름의 변수를 사용한 scope 오염의 예를 들어보자면, 다음과 같다

 

function logSkyColor() {
  const dusk = true;
  let myColor = 'blue'; 

  if (dusk) {
    let myColor = 'pink';
    console.log(myColor); // pink
  }

  console.log(myColor); // blue 
}

console.log(myColor); // 에러!!

 

  • if문에 {}의 코드 block을 사용했다. 여기에 myColor라는 변수를 let으로 선언했다.
  • if문 내에서는 "pink"라고 할당하였고, if문 밖에서는 "blue"라고 할당했다.
  • 이 코드는 function의 block scope, if문의 block scope으로 모두 block을 잘 사용했지만 같은 같은 이름의 변수를 사용했기에 오염된 것이다.

이렇게 새로운 block에서 변수를 쓸 때는 항상 다른 이름으로 변수를 선언해야 한다는 것을 잊으면 안 된다.

반응형

'Javascript' 카테고리의 다른 글

JavaScript - Object(2)  (0) 2020.07.05
JavaScript - Class  (0) 2020.07.05
JavaScript - Object  (0) 2020.07.04
JavaScript - Number  (0) 2020.07.04
JavaScript - 날짜와 시간  (0) 2020.06.22

댓글