자바스크립트

스코프 (유효범위)

데이터_박과장 2023. 11. 15. 22:33

스코프 (유효범위)

Scope의 정의 📋

  • 자신이 선언된 위치에 의해 다른 코드가 식별자 자신을 참조할 수 있는 유효범위
  • 자바스크립트 엔진이 식별자를 검색할 때 사용하는 규칙

Scope의 구분 ⚖️


자바스크립트에서 스코프는 변수와 함수의 유효 범위를 나타냅니다. 스코프는 변수와 함수가 어디에서 접근 가능한지를 결정합니다. 스코프는 전역 스코프(Global Scope)와 지역 스코프(Local Scope)로 나뉩니다.


전역 스코프(Global Scope):

전역 스코프는 코드 어디에서나 접근 가능한 스코프입니다. 전역 스코프에서 선언된 변수와 함수는 프로그램의 어느 곳에서나 접근할 수 있습니다.

 

var globalVariable = 10;

function globalFunction() {
    console.log("This is a global function");
}



지역 스코프(Local Scope)
:

지역 스코프는 특정한 블록(함수) 내에서 선언된 변수와 함수가 해당 블록 내부에서만 접근 가능한 스코프입니다.


function localScopeExample() {
    var localVariable = 20;

    function localFunction() {
        console.log("This is a local function");
    }
}

 

위의 예제에서 localVariable과 localFunction은 localScopeExample 함수 내에서만 접근할 수 있습니다.



스코프는 또한 스코프 체인(Scope Chain)을 형성합니다. 이는 내부 함수가 외부 함수의 변수에 접근할 수 있지만, 외부 함수는 내부 함수의 변수에 접근할 수 없다는 것을 의미합니다. 이러한 스코프 체인은 Lexical Scope라고도 불립니다.

 

function outerFunction() {
    var outerVariable = 30;

    function innerFunction() {
        console.log(outerVariable); // innerFunction이 outerFunction의 변수에 접근 가능
    }

    innerFunction();
}

outerFunction();


여기서 innerFunction은 외부 함수인 outerFunction의 변수인 outerVariable에 접근할 수 있지만, outerFunctioninnerFunction의 변수에 접근할 수 없습니다.


 



 

 

Scope의 특징 🙌

  • var 키워드로 선언된 변수는 함수 레벨 스코프를 따름
  • 함수 레벨 스코프 (Function-level scope)
    • 함수 내에서 선언된 지역 변수는 함수 내에서만 유효
    • 함수 외부에서는 참조 불가
  • let,const 키워드로 선언된 변수는 블록 레벨 스코프를 따름
  • 블록 레벨 스코프 (Block-level scope)
    • 코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효, 코드 블록 외부에서는 참조 불가
    • 코드 블록 내부에서 선언한 변수는 지역 변수

 

 

 

 

 

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

함수 스코프(Function Scope): 함수 스코프는 변수나 상수의 유효 범위가 함수 내부로 제한됩니다. 즉, 함수 내에서 선언된 변수는 함수 내부에서만 접근할 수 있고, 외부에서는 접근할 수 없습니다. 이는 전통적인 자바스크립트의 스코프 규칙입니다.

 

예를 들어보겠습니다.

function functionScopeExample() {
    var x = 10;
    console.log(x); // 함수 내부에서 x를 사용 가능
}

console.log(x); // 에러: x는 함수 외부에서 접근 불가

 

 

아래는 추가적인 예시입니다

var x = 1;

if (true) {
  // x는 전역 변수, 이미 선언된 전역 변수 x가 있어 x 변수는 중복 선언
  var x = 10;
}

console.log(x); // 10
  • var 키워드로 선언한 변수는 함수의 코드 블록만을 지역 스코프로 인정
  • 함수 외부에서 var키워드로 선언한 변수는 코드 블록 내에서 선언해도 모두 전역변수가 됨
var i = 10;

// var 키워드로 for 문에서 선언한 변수 i는 전역변수
// 이미 선언한 전역 변수 i가 있으므로 중복 선언
for(var i = 0; i < 5; i++) {
  console.log(i) // 0 1 2 3 4 5
}

// 의도치 않게 변수와 값이 변경
console.log(i) // 5
  • for문의 변수 선언문에서 var키워드로 선언한 변수도 전역 변수가 됨

예시로 알아보는 함수 레벨 스코프 1

var x = 'global';

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

foo();            // local
console.log(x);   // global
  • 전역변수 x와 지역변수 x가 중복 선언
  • 전역 영역에서는 전역변수만이 참조 가능
  • 함수 내 지역 영역에서는 전역, 지역 변수 모두 참조 가능
  • 변수명이 중복된 경우, 지역변수를 우선하여 참조

예시로 알아보는 함수 레벨 스코프 2

var x = 'global';

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

foo();
console.log(x);	// global
  • 내부함수는 자신을 포함하고 있는 외부함수의 변수에 접근 가능
  • 함수 bar에서 참조하는 변수 x는 함수 foo에서 선언된 지역변수
    → 실행 컨텍스트의 스코프 체인에 의해 참조 순위에서 전역변수x가 뒤로 밀림

스코프 체인: 스코프가 계층적으로 연결된 것

예시로 알아보는 함수 레벨 스코프 3

var x = 10;

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

foo();
console.log(x);     // 100
  • 함수(지역) 영역에서 전역변수 참조가능
     전역변수의 값 변경가능
  • 내부 함수의 경우, 전역변수는 물론 상위 함수에서 선언한 변수에 접근/변경이 가능

예시로 알아보는 함수 레벨 스코프 4

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
  • 중첩 스코프는 가장 인접한 지역을 우선하여 참조

예시로 알아보는 함수 레벨 스코프 5

var foo = function () {
  var a = 3;
  var b = 5;
  
  console.log(a, b);            // a:3, b:5
  var bar = function (){
    var b = 7;
    var c = 11;
    
    console.log(a, b, c);       //  a:3, b:7, c:11
    a += b + c;
    console.log(a, b, c);       // a:21, b:7, c:11
  };
    
  bar();
};

foo();

 

블록 스코프(Block Scope): 블록 스코프는 변수나 상수의 유효 범위가 중괄호({})로 둘러싸인 블록 내부로 제한됩니다. 주로 if 문, for 문, while 문 등의 블록 내에서 변수를 선언할 때 사용됩니다. 이전에는 자바스크립트에 블록 스코프가 없었지만, ECMAScript 6(ES6)부터 도입되었습니다.

 

예를 들어보겠습니다.

 

if (true) {
    var y = 20; // 블록 내에서 선언된 변수
    let z = 30; // 블록 스코프를 가지는 변수 (ES6 이후)
    const w = 40; // 블록 스코프를 가지는 상수 (ES6 이후)
    console.log(y); // 20 출력
    console.log(z); // 30 출력
}

console.log(y); // 20 출력 (var는 함수 스코프를 따르지만, 블록 내에서도 접근 가능)
console.log(z); // 에러: z는 블록 외부에서 접근 불가 (let으로 선언된 변수는 블록 스코프를 가짐)
console.log(w); // 에러: w는 블록 외부에서 접근 불가 (const로 선언된 상수는 블록 스코프를 가짐)

 

 

여기서 y는 var 키워드로 선언되었으므로 함수 스코프를 따르지만, 블록 내에서도 접근 가능합니다. 반면에 z와 w는 let과 const 키워드로 선언되어 블록 스코프를 가지므로 블록 외부에서 접근할 수 없습니다.

 

함수 스코프는 함수가 유효 범위를 제한하고, 블록 스코프는 블록 내에서 유효 범위를 제한합니다. 이러한 스코프의 차이를 이해하면 변수를 적절히 사용하여 코드를 작성할 수 있습니다.

 

 

렉시컬 스코프(Lexical Scope)

함수가 어디에서 호출되는지가 아니라, 어디에 선언되는지에 따라 변수의 유효 범위가 결정되는 것을 말합니다. 다시 말해, 함수의 스코프는 함수를 선언할 때 정적으로 결정되며, 함수가 호출될 때 동적으로 결정되는 것이 아니라는 것입니다.

렉시컬 스코프는 중첩된 함수가 있는 경우에도 동작합니다. 내부 함수는 외부 함수의 스코프에 접근할 수 있습니다. 이러한 구조에서 내부 함수는 외부 함수의 변수와 외부 함수가 선언된 위치에 따라 자신의 스코프를 참조합니다.

 

function outerFunction() {
    var outerVariable = 'I am outer';

    function innerFunction() {
        console.log(outerVariable); // innerFunction이 outerFunction의 변수에 접근
    }

    innerFunction();
}

outerFunction(); // 'I am outer'가 출력됨

 


여기서 innerFunction은 outerFunction 내부에 선언되었으므로, innerFunction은 outerFunction의 변수인 outerVariable에 접근할 수 있습니다. 이는 렉시컬 스코프의 개념을 따르는 것입니다.

렉시컬 스코프는 함수를 정의할 때 코드의 구조가 어떻게 되는지에 따라 스코프가 정해지므로 예측 가능하고 이해하기 쉬운 코드를 작성하는 데 도움이 됩니다. 함수가 어디에 선언되었는지에 따라 그 함수가 어떤 변수에 접근할 수 있는지를 쉽게 판단할 수 있습니다.

 

암묵적 전역 변수 🤫

function foo() {
  x = 10;
}

foo();
console.log(x);	// 10
  • 함수 foo내에 선언되지 않은 변수 x에 값 10을 할당
  • 변수 x의 참조를 찾아야 변수 x에 값을 할당할 수 있음
    → 자바스크립트 엔진이 스코프 체인에서 변수 x를 검색하기 시작
  • foo 함수의 스코프에서 변수 x를 검색
    • foo 함수의 스코프에는 변수 x에 대한 변수 선언이 없으므로 검색에 실패
    • foo 함수의 상위 컨텍스트(위 예제의 경우 전역 스코프)에서 변수 x를 검색
  • 전역 스코프에도 변수 x가 존재하지 않기 때문에 ReferenceError를 발생시킬 것 같지만 __전역 변수x를 암묵적으로 생성하고 값을 할당
  • var 키워드를 생략한 변수는 암묵적으로 전역 변수
    → 이러한 변수를 암묵적 전역 변수(implicit global)라 함

개발자의 의도와는 상관없이 동작하는 암묵적 전역 변수는 오류의 발생 원인이 될 가능성이 크기 때문에 변수를 선언할 때는 반드시 let 키워드를 사용

변수 이름의 중복 🛠

// x.js
function foo() {
  // var i = 0;
  i = 0;
  // ...
}

// y.js
for (var i = 0; i < 5; i++) {
  foo();
  console.log(i);
}
  • x.js와 y.js에 모두 의도하지 않은 변수 i가 존재
  • HTML에서 이 2개의 자바스크립트 파일을 로드하면 변수 i는 중복됨
  • x.js의 변수 i는 var키워드를 사용하지 않았으므로 암묵적으로 전역 변수화
  • y.js의 변수 i는 전역변수
  • 자바스크립트는 변수명의 중복을 허용
    → 어떠한 에러 메시지도 발생시키지 않음
     무한 반복상태에 빠지게 됨.

전역변수의 무분별한 사용은 위험하다. 전역변수를 반드시 사용하여야 할 이유를 찾지 못한다면 지역변수를 사용하여야 하며 변수의 범위인 스코프는 좁을수록 좋다.



Scope의 규칙 🔏

Scope는 함수를 호출할 때가 아니라 선언할 때 생긴다.

1. 함수 내부에서 변수를 참조할 경우

  • 함수 내부에서 변수를 먼저 찾음
  • 함수 내부에 X → 함수 외부에서 찾음

2. 함수 내부, 외부에 동일한 변수명이 존재할 경우

  • 함수에서는 내부의 변수를 우선시 함

3. 함수 내부, 외부에서의 규칙

  • var의 경우, 내부/ 외부를 판별하는 기준은 함수
  • 함수 내부에서 선언된 변수? 함수 외부에서 참조 불가
  • 함수 외부에서 선언된 변수? 함수 내부에서 참조 가능



최소한의 전역변수 사용하는 방법 📚

1. 전역변수 객체를 만들어서 사용하기

var MYAPP = {};

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

console.log(MYAPP.student.name);

2. 즉시실행함수를 이용하여 사용하기

(function () {
  var MYAPP = {};

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

  console.log(MYAPP.student.name);
}());

console.log(MYAPP.student.name);
  • 즉시 실행 함수(IIFE, Immediately-Invoked Function Expression)를 사용하면 전역변수를 만들지 않음
  • 즉시 실행 함수는 즉시 실행되고 그 후 전역에서 바로 사라진다.

'자바스크립트' 카테고리의 다른 글

원시타입, 참조타입  (0) 2023.11.15
호이스팅 (Hoisting)  (0) 2023.11.15
자바스크립트 - ECMA스크립트 버전소개  (0) 2023.11.04
자바스크립트 - Ajax  (0) 2023.10.26
자바스크립트 - 비동기식 처리모델  (0) 2023.10.26