1. Scope?


scope는 JS 문법이 아니다. 쉽게 말하자면 scope는 “변수가 어느 영역까지 쓰일 수 있는가”의 범위, 혹은 “변수가 선언되고 사용할 수 있는 공간”을 말한다. let, const, var 등으로 변수를 선언했다 하더라도 해당 변수가 block으로 막혀 있다면 “is not defined” error message가 뜬다. 왜냐하면 변수는 모두 제각각 범위가 다른데, 영역을 자유롭게 넘나드는 변수가 있는 반면 어떤 것들은 특정 범위 내에서만 쓰일 수 있기 때문이다.

💡 block은 중괄호{}(=curly brace)로 감싸진 것을 밀한다.

예를 들어 function, if, for문의 내부는 하나의 block이다. block 내부에서 정의된 변수local variable이라 하는데, 이는 block 내부에서만 쓰일 수 있다.

function getResult() {
  let result = 10;
  
  return result;
}
// JavaScript Error
// getResult 내부의 scope에 접근할 수 없다
console.log(result);

위와 같은 예시처럼 console.log(result)는 block 내부로 접근할 수 없기 때문에 result변수 존재를 인식할 수 없다. 즉, 오류가 출력된다.





2. Global Scope (전역변수)


Global Scope(젼역변수)란, block 밖에서 만들어진 변수를 뜻한다. 이는 local variable과 달리 코드 어디든 접근이 가능하다.

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

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

console.log(returnColor());

위 예시의 color 변수는 global variable이기 때문에 returnColor 함수의 block에도 접근이 가능하다. 때문에 console.log(returnColor())는 error 없이 ‘red’를 반환한다.

color 변수는 global variable이기 때문에 returnColor 함수의 block에서도 접근 가능하기 때문에 'red' 가 반환된 것이다.





3. Scope의 오염


global variable의 접근 방식이 유용하겠지만, 남용된다면 프로그램에 문제를 일으킬 수 있다. global variable를 선언하면 해당 프로그램 어디서든 사용될 수 있는 global namespace를 갖게 된다. 여기서 namespace변수 이름을 사용할 수 있는 범위를 뜻한다. scope로 지칭되지만 변수 이름을 얘기할 때는 namespace라고도 한다.

global variable은 프로그램이 종료될 때까지 살아있다. local variable이 block 내부가 종료되면 함께 종료되는 것과 상반된다. 하지만 global variable이 종료되지 않아 변수 값이 계속 변한다면 해당 변수를 트래킹하기에 어려움이 많아진다. 또한 해당 변수가 어디에서 왜 필요한지를 알기 위해 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()); // "Night Sky: The Moon, Sirius, The Milky Way"
console.log(stars); // "Sirius"

let stars = 'North Star'; callMyNightSky 함수 내부의 stars는 let으로 선언되지 않았기 때문에 global variable인 상위 stars가 재할당된다. 즉, North Star가 아닌 Sirius로 출력되는 것이다.

만약 callMyNightSky의 stars가 만약 let stars로 선언됐다고 가정한다면, global variable인 상위 라인의 let star는 ‘North Star’ 값을 유지한다, 즉, 이 때엔 console.log(callMyNightSky())는 전과 같이"Night Sky: The Moon, Sirius, The Milky Way"를 그대로 출력하지만 console.log(stars)는 global variable인 let stars의 “North Star”를 출력한다.





4. Scoping의 활용


위의 scope 오염 예시와 같이 global variable가 여기 저기서 영향을 끼치면 안되기에 변수들은 늘 최대한 block 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); // ReferenceError
console.log(logSkyColor()) // "pink" "blue"

사실 이 코드는 function 의 block, scope, if 문의 block, scope로 모두 block 을 잘 사용 하였음에도 scope namespace가 오염됐다. 왜냐하면 이름이 동일한 변수를 사용했기 때문이다. 새로운 block에서 변수를 쓸 때는 항상 다른 변수명으로 변수를 선언해야한다는 점을 유의해야 한다.

  1. 타이트한 scope(tightly scoping)의 변수는 코드 품질을 올려준다.
  2. 코드가 block으로 명확히 구분되면 가독성이 향상된다.
  3. 차후 코드를 수정할 때에도 block으로 구분된 코드는 유지보수가 쉽다.
  4. globak variable은 프로그램이 종료될 때까지 기능을 하기에 메모리의 다수 공간을 차지하게 된다. 이를 block으로 나눠 local variable이 block과 함께 적재적소로 종료된다면 메모리 또한 절약될 수 있다.

정리하자면, global variable은 최대한 쓰지 않도록 노력해야 하며, block {} 내에서 letconst 을 사용해 local variable를 활용하는 것을 지향해야 한다.

profile
helloworld

0개의 댓글