:ledger: 스코프(scope)에 대해서 알아보자.

:one: 스코프(scope)란?

  • 스코프(scope)는 프로그램에서 변수나 함수가 참조될 수 있는 유효 범위를 의미함
  • 스코프는 변수가 어디서 접근할 수 있는지 결정하며, 코드의 가독성과 유지보수성을 높이는데 중요함
  • 스코프는 크게 전역 스코프, 함수 스코프, 블록 스코프로 나뉨

:two: 전역 스코프

:pushpin: 2-1) 정의

함수나 블록 밖에서 선언된 변수는 전역 스코프를 가지며, 프로그램 전체에서 접근이 가능하다. 예) 전역 변수

:pushpin: 2-2) 특징

어디에서나 접근이 가능하지만, 전역 변수가 많아지면 의도치 않게 재선언이 되어 유지보수가 어려울 수 있음
그렇기에 전역 변수는 재선언이 불가능하게 let으로 선언하자!

  • 어디에서나 접근 가능
  • var로 선언한 전역 변수는 재선언이 가능하여 변수가 재선언되어 유지보수가 어려워질 수 있음
  • let으로 선언한 전역 변수는 재선언이 불가능하여 변수가 덮어씌어지는 걸 방지할 수 있음

:pushpin: 2-3) 전역 스코프 예시

let globalLet = "Hello World"; // 전역 변수 선언
function test01() {
  // 함수 안에서도 찾을 수 있음
  console.log(globalLet); // "Hello World"
}
test01();
console.log(globalLet); // "Hello World"

:two: 함수 스코프

:pushpin: 정의

함수 내에서 선언된 변수는 해당 함수 내에서만 유효함

:pushpin: 3-1) 특징

함수가 종료되면 변수는 더 이상 접근할 수 없으며 함수 내부에서 선언하지 않고 사용하면 암묵적으로 전역 변수가 될 수 있음 (var)
유지보수 측면에서 var는 사용하지 않는게 좋다!

  • 함수가 종료되면 변수는 더 이상 접근할 수 없음
    • 함수가 호출되며 생성된 변수는 함수가 종료되면 메모리에서 해제되어 더 이상 접근이 불가함
  • 함수 내부에서 변수를 선언하지 않고 사용하면 암묵적으로 전역 변수가 될 수 있음
    • JavaScript에서 var를 사용할 때, 변수 선언 없이 값을 할당하면 암묵적으로 전역 변수가 될 수 있음
  • 변수 var는 쓰지 말자!

:pushpin: 3-2) 함수 스코프 예시

function test02_01() {
  let num = 1;
  console.log(num); // 1
}
test02_01();
console.log(num); // num을 찾을 수 없음

function test02_02() {
  var num = 2;
  if (true) {
    var num = "hi"; // 같은 함수 스코프 내에서 num가 재선언되고 재할당된다. (고로 var은 쓰지말자)
    console.log(num); // "hi"
  }
  console.log(num); // "hi"
}
test02_02();

:page_facing_up: 함수 외부에서 접근

함수 스코프의 변수는 함수가 종료되면 더 이상 접근이 불가능하지만 접근하는 방법이 무엇인지 궁금해서 찾아보았는데, 함수 반환 값과 클로저가 있었다.

:page_facing_up: 함수 반환 값 (return)

함수 반환 값은 함수가 시행된 후 반환하는 결과값을 의미하며 함수가 호출하면, 함수 내부의 return문을 통해 외부로 값을 전달한다.

  • 단순한 데이터 반환: 함수가 실행된 후 계산된 값을 반환함
  • 명시적 반환: 함수가 반환하는 값은 함수 호출 시 명시적으로 반환됨
  • 상태 유지 불가: 반환된 값은 함수의 실행이 완료되면 그 상태를 유지하지 않으며 함수가 종료된 후, 반환된 값은 외부에서 사용되지만 함수 내의 상태를 기억하지 않음
// 예시 1
function createNum() {
  let num = 0; // 함수 내에서만 유효한 변수
  return function () {
    num += 1;
    return num;
  };
}
const number = createNum();
console.log(number()); // 1
console.log(number()); // 2

// 예시 2
function add(x, y) {
  return x + y;
}

const sum = add(3, 5); // sum은 8
console.log(sum); // 8

:page_facing_up: 클로저(Closure)

클로저는 함수가 다른 함수의 내부 변수를 기억하는 함수이며 내부 함수가 외부 함수의 변수에 접근할 수 있도록 해줌

  • 상태 유지: 클로저는 외부 함수의 변수를 기억하고, 외부 함수가 실행된 후에도 그 변수를 유지함
  • 함수의 반환값으로 사용: 클로저는 내부 함수로서 외부 함수의 변수에 접근할 수 있는 함수다. 내부 함수가 외부 함수의 스코프를 기억함
function test() {
  let a = "Hello";
  function innerFunc() {
    console.log(a); // "Hello" (외부 함수의 변수 접근)
  }
  return innerFunc();
}
const inner = test();
inner(); // "Hello" 함수 외부에서 내부 변수에 접근함

:page_facing_up: 함수 반환 값과 클로저의 차이점

  1. 목적
  • 함수 반환 값: 함수가 실행된 후 특정 값을 반환하여 외부에서 사용할 수 있도록함.
  • 클로저: 함수가 외부 함수의 변수를 기억하고, 해당 변수에 대한 상태를 유지하며 외부 함수가 종료된 후에도 계속 접근할 수 있게함
  1. 상태 유지
  • 함수 반환 값: 반환된 값은 함수 종료 후에 상태를 유지하지 않음. 함수 실행이 끝나면 함수 내부의 상태는 잃어버림
  • 클로저: 클로저는 외부 함수의 변수에 대한 참조를 유지하며 함수가 종료된 후에도 해당 변수의 상태를 유지하고 수정할 수 있음
  1. 사용 방식
  • 함수 반환 값: 계산된 값을 외부로 전달하기 위해 사용
  • 클로저: 내부 함수가 외부 함수의 상태를 유지하고, 특정 데이터나 상태를 캡처하여 관리하기 위해 사용

:page_facing_up: 결론

  • 함수 반환 값은 단순히 계산된 값을 외부로 전달할 때 사용된다. 상태 유지가 필요 없고, 함수의 결과를 단순히 전달하면 되는 경우에 적합함
  • 클로저는 함수가 내부 상태를 유지하며 외부 함수의 변수에 접근할 필요가 있을 때 사용됨

:three: 블록 스코프

:pushpin: 3-1) 정의

블록({}) 내에서 선언된 변수는 해당 블록 내에서만 유효함

:pushpin: 3-2) 특징

  • 블록이 종료되면 더 이상 접근할 수 없음
  • 상위 블록에서 선언된 변수는 하위 블록에서 사용 가능함
  • 상위 블록에서 선언한 변수를 하위 블록에서 선언하면 새로운 변수로 인식함

:pushpin: 3-3) 함수 스코프 예시

if (true) {
  let x = 1;
  console.log(x); // 1
}
console.log(x); // x를 찾을 수 없음

let y = 1; // 상위 블록
if (true) {
  y = 2;
  console.log(y); // 2
}
console.log(y); // 2;

for (let i = 0; i < 10; i++) {
  console.log(i); // 0,1,2,3...
}
console.log(i); // i를 찾을 수 없음

:four: 주의할점

:pushpin: 블록 스코프

  • 변수를 블록 밖에서 사용하려면 블록 밖에서 전역으로 선언해야함
  • 블록 내에서 변수를 재선언하면 블록 내에서만 새로운 변수로 인식됨

:pushpin: 함수 스코프

  • 함수 내에서 변수를 선언하지 않고 사용하면 암묵적으로 전역 변수가 될 수 있음 (var)
  • 함수 내 변수는 함수가 종료되면 더 이상 접근이 불가능함
  • 접근이 가능하게 하려면 함수 반환값과 클로저를 이해하고 사용해야함

:fire: 마무리

스코프는 변수나 함수 유효 범위를 결정하기에 각 스코프를 이해하고 올바르게 사용할 수 있어야겠다.
그렇지 않을 경우 코드의 가독성,유지보수,안정성이 모두 떨어지는 결과를 초래할 것이며 지켜진다면 효율적인 코드를 작성할 수 있을 것 같다.
함수 반환값과 클로저는 조금 더 이해해보도록 공부해봐야겟다.