조아마시

쓸모 있는 상세페이지 만들기

웹개발/javascript

[자바스크립트] 스코프 (Scope) 완벽 정리

joamashi 2024. 7. 21. 18:15

1. 스코프란 무엇인가?

스코프는 변수와 함수가 유효한 범위를 정의하는 개념입니다. 즉, 어떤 코드 블록에서 어떤 변수와 함수를 사용할 수 있는지 결정합니다.

자바스크립트에는 두 가지 주요 스코프 유형이 있습니다.

  • 블록 스코프: letconst 키워드를 사용하여 선언된 변수의 유효 범위는 해당 변수가 선언된 블록 안에 국한됩니다.
  • 함수 스코프: 함수의 매개변수와 함수 내에서 선언된 변수는 해당 함수 안에서만 유효합니다.

2. 블록 스코프

letconst 키워드를 사용하여 선언된 변수는 블록 스코프를 따릅니다.

  • let 키워드: 블록 안에서 재선언 및 재할당이 가능합니다.
  • const 키워드: 블록 안에서 재선언 불가능하며, 선언 시 반드시 값을 초기화해야 합니다.
if (true) {
  let message = 'Hello!';
  console.log(message); // 'Hello!' 출력
}

console.log(message); // ReferenceError: message is not defined

위 예시에서 message 변수는 if 블록 안에서만 유효하며, 블록 외부에서는 사용할 수 없습니다.

3. 함수 스코프

함수의 매개변수와 함수 내에서 선언된 변수는 함수 스코프를 따릅니다.

  • 함수 외부에서 선언된 변수는 함수 내에서 전역 변수로 접근 가능합니다.
  • 함수 내에서 선언된 변수는 함수 외부에서는 접근 불가능합니다.
function greet(name) {
  console.log(`Hello, ${name}!`);
}

const globalMessage = 'Welcome!';

greet('Alice'); // 'Hello, Alice!' 출력
console.log(name); // ReferenceError: name is not defined

위 예시에서 name 변수는 greet 함수 내에서만 유효하며, 함수 외부에서는 사용할 수 없습니다.

4. 스코프 체인

스코프 체인은 변수를 찾는 순서를 정의하는 방식입니다. 변수를 사용할 때, 다음 순서대로 해당 변수를 찾습니다.

  1. 현재 블록: 현재 코드 블록에서 선언된 변수를 검색합니다.
  2. 외부 블록: 현재 블록의 외부 블록에서 선언된 변수를 검색합니다.
  3. 함수 스코프: 현재 함수에서 선언된 매개변수 또는 변수를 검색합니다.
  4. 전역 스코프: 전역적으로 선언된 변수를 검색합니다.

변수가 여러 블록에서 동일한 이름으로 선언된 경우, 가장 가까운 블록에서 선언된 변수를 사용합니다.

5. 스코프 관련 주의 사항

  • 블록 스코프를 사용하면 변수 오버라이딩 문제를 방지하고 코드 가독성을 향상시킬 수 있습니다.
  • 함수 스코프를 사용하면 변수 오염 문제를 방지하고 코드 재사용성을 높일 수 있습니다.
  • 스코프 체인을 이해하면 복잡한 코드에서 변수를 추적하는 데 도움이 됩니다.
  • var 키워드는 블록 스코프가 아닌 함수 스코프를 따릅니다. 새로운 코드에서는 let 또는 const 키워드를 사용하는 것이 좋습니다.

global(전역) 변수과 local(지역) 변수

function print () { // 함수 블록
 console.log(a);
}

{ // 블록
 const a = '1';
}
var x = 'global'; // 전역(스코프) 변수

function foo () { // 지역(스코프) 함수
  var x = 'function scope';
  console.log(x)
}
foo(); // function scope
console.log(x); // global
var a = 1; // 전역(스코프) 변수

function print () { // 함수(스코프) 변수
	console.log(a);
}
print(); // 1
var = 0;

{
  var y = 1
  console.log(y) // 1
}

console.log(y)  // 0
let y = 0

{
  let y = 1
  console.log(y) // 1
}

console.log(y)   // 0

스코프 체인(Scope Chain)

  • 스코프 체인은 현재 스코프 레벨에서 변수가 존재하지 않는 경우 상위 스코프에서 찾는 것
  • 이 찾는 과정은 스코프를 안에서 바깥쪽으로 단계적으로 탐색하는 과정이다. (내부 -> 외부 -> 전체)
  • 스코프가 계층적으로 연결되어있는 것
let a = 1;
function firstFunction() {
  let b = 2;
  function secondFunction() {
    let c = 3;
    console.log(a, b, c); // 1, 2, 3 (a, b, 그리고 c에 접근 가능)
  }
  secondFunction();
}
firstFunction();
var x = "global x"
var y = "global y"
 
function outer () {
  var z = "outer's local z"
  
  console.log(x)     // global x
  console.log(y)     // global y
  console.log(z)     // outer's local z

  function inner () { // 중첩 함수
    var x  = "inner's local x"

    console.log(x) // inner's local x
    console.log(y) // global y
    console.log(z) // outer's local z
  }
  inner()
}
outer()

console.log(x)         // global x
console.log(z)         // ReferenceError: z is not defined.

전역 스코프(Global scope)

var global = 'global';

function foo() {
  var local = 'local';
  console.log(global); // 'global'
  console.log(local); // 'local'
}
foo();

console.log(global); // 'global'
console.log(local); // ReferenceError: local is not defined

var : 함수 레벨 스코프(Function-level scope)

var a = 10;     // 전역변수

(function () {
  var b = 20;   // 지역변수
})();

console.log(a); // 10
console.log(b); // "b" is not defined
var x = 'global';

function foo() {
  var x = 'local';
  console.log(x);
}

foo();          // local
console.log(x); // global
var x = 'global';

function foo() {
  var x = 'local';
  console.log(x); // 'local'

  function bar () { // 내부함수
    console.log(x); // 'local'
  }
  bar();
}
foo();
console.log(x); // 'global'
var x = 10;

function foo () {
  var x = 100;
  console.log(x); // 100

  function bar () { // 내부함수
    x = 1000;
    console.log(x); // 1000
  }
  bar();
}
foo();
console.log(x); // 10

비 블록 레벨 스코프(Non block-level scope) 전역 스코프(Global scope)

if (true) {
  var x = 5;
}
console.log(x); // 5

암묵적 전역

var x = 10; // 전역 변수

function foo () {
  y = 20; // 선언하지 않은 식별자(안티패턴)
  console.log(x + y);
}
foo(); // 30
// 전역 변수 x는 호이스팅이 발생
x // undefined

// 전역 변수가 아니라 단지 전역 프로퍼티인 y는 
// 호이스팅이 발생하지 않는다.
y // ReferenceError: y is not defined

var x = 10 // 전역 변수

function foo () {
  
  y = 20 // 선언하지 않은 변수
  console.log(x + y)
}
foo() // 30
var x = 10 // 전역 변수

function foo () {
  y = 20 // 선언하지 않은 변수
  console.log(x + y)
}
foo(); // 30

console.log(window.x); // 10
console.log(window.y); // 20

delete x // 전역 변수는 삭제되지 않는다.
delete y // 프로퍼티는 삭제된다.

console.log(window.x) // 10
console.log(window.y) // undefined

최소한의 전역변수 사용 - 객체 리터럴 네임스페이스

var MYAPP = {};

MYAPP.student = {
  name: 'Lee',
  gender: 'male'
};

console.log(MYAPP.student.name); // "Lee"

즉시실행함수를 이용한 전역변수 사용 억제

(function () {
  var MYAPP = {};

  MYAPP.student = {
    name: 'Lee',
    gender: 'male'
  };

  console.log(MYAPP.student.name); // "Lee"
}());

console.log(MYAPP.student.name); // "ReferenceError: MYAPP is not defined" - MYAPP 정의되지 않았습니다
728x90