JavaScript 스코프

seul_velog·2021년 12월 20일
0

JavaScript

목록 보기
18/25
post-thumbnail

✍️ 스코프에 대해서 조금 더 알아보자.


📍 1. 스코프(Scope, 유효범위)란?

Scope는 우리말로 번역하면 ‘범위’라는 뜻이다. 즉, 스코프란 ‘변수에 접근할 수 있는 범위’라고 할 수 있다.

  • 참조 대상 식별자(변수, 함수명 등 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이며, 자바스크립트는 이 규칙대로 식별자를 찾는다.

  • 대부분의 프로그래밍 언어는 블록 레벨 스코프(Block-level scope)를 따르지만 자바스크립트는 함수 레벨 스코프(Function-level scope)를 따른다.

식별자 결정 과정 : 어떠한 변수를 참조할 것인지 결정하는 과정




2. 스코프의종류

함수 레벨 스코프와 블록 레벨 스코프

👉 1) 함수 레벨 스코프(Function-level scope)
함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다.


2) 블록 레벨 스코프(Block-level scope)
모든 코드 블록(함수, if 문, for 문, while 문, try/catch 문 등) 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. 즉, 코드 블록 내부에서 선언한 변수는 지역 변수이다.




전역스코프와 지역스코프

  • 자바스크립트에서 스코프는 2가지 타입 'global(전역)'과 'local(지역)' 이 있다.

1) 전역 스코프 (Global scope)
코드 어디에서든지 참조할 수 있다. 변수가 함수 외부나 중괄호 {} 외부에 선언되었다면, 전역 스코프에 정의된다고 한다.

2) 지역 스코프 (Local scope or Function-level scope)
함수 코드 블록이 만든 스코프로 함수 자신과 하위 함수에서만 참조할 수 있다.




전역변수와 지역변수

  • 모든 변수는 스코프를 갖는다. 변수의 관점에서 스코프를 구분하면 다음과 같이 2가지로 나눌 수 있다.

1) 전역 변수 (Global variable)
전역에서 선언된 변수이며 어디에든 참조할 수 있다.

2) 지역 변수 (Local variable)
지역(함수) 내에서 선언된 변수이며 그 지역과 그 지역의 하부 지역에서만 참조할 수 있다.




3. 스코프의 동작과정

Scope의 규칙

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

  • 함수 내부에서 변수를 먼저 찾는다.
  • 함수 내부에 없다면, 함수 외부에서 찾는다.

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

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

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

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




Scope의 동작 과정

var lscope = 'global';

function fscope(){
  console.log(lscope);
}

fscope();  // global
  • 함수 내부에 없는 lscope 변수를 불러오는 경우
    1) 식별자 결정 과정을 통해서 함수 내부에서 먼저 해당 변수를 찾는다.
    2) 함수 내부에 해당 변수가 없을 경우 외부에서 해당 변수 lscope 를 찾아 온다.
var lscope = 'global';

function fscope(){
  var lscope = 'local';
  console.log(lscope);
}

fscope();  // local
  • 함수 내부의 lscope 변수를 불러오는 경우
    : fscope 라는 함수 안에 lscope 변수가 선언 되어있기 때문에 console.log(lscope) 는 자기 자신에게 가까운 쪽에서 선언되어있는 것을 가리키게 되어 local 을 출력한다.
    즉 같은 함수내에서 먼저 찾고, 그 다음 함수 밖에서 찾게된다.




Function-Level Scope의 동작과정

  • block-level scope란 code block({ … })내에서 유효한 scope를 의미한다.

  • 자바스크립트는 function-level-scope를 사용하는데, 함수 코드 블럭 내에서 선언된 변수는 함수 코드 블럭 내에서만 유효하고 함수 외부에서는 유효하지 않다(참조할 수 없다)는 것이다.

  • ❗️ CMAScript 6에서 도입된 let keyword를 사용하면 block-level scope를 사용할 수 있다.

// var 키워드 사용 ▼
var x = 0;
{
  var x = 1;
  console.log(x); // 1
}
  console.log(x); // 1


// let 키워드 사용 ▼
let y = 0;
{
  let y = 1;
  console.log(y); // 1
}
  console.log(y); // 0




4. 렉시컬 스코핑

정적 유효범위

자바스크립트는 함수가 선언된 시점에서의 유효범위를 갖는다. 이러한 유효범위의 방식을 정적 유효범위(static scoping), 혹은 렉시컬(lexical scoping)이라고 한다.

  • 함수가 호출된 위치는 스코프 결정에 아무런 의미를 주지 않는다.
var i = 5;
 
function a(){
    var i = 10;
    b();
}
 
function b(){
    document.write(i);
}
 
a();

변수 i 는 전역변수이다.
함수 a 는 변수 i 를 지역변수로 가지고 있으며 다시 함수 b 를 호출한다.
함수 b 는 변수 i 를 출력한다.

1) 함수 a 를 호출한다. → 함수 내부 i 값=10 이되며, 그 후 함수 b 를 출력한다.
2 ) i 는 먼저 함수 b 내부에 i 지역변수를 찾는다.
3 ) 지역변수가 없다면 전역 변수를 찾는다.
이때, b 를 호출하고 있는 함수 a 의 지역변수 VS 함수b 가 현재 정의된 시점에서의 전역변수 중 어느것을 따라갈까?

→ 답은 i = 5 이다.
함수 b 가 선언된 시점에서 i 의 전역변수가 사용된다. 함수b 가 호출된 시점은 영향을 주지 못한다.
즉 '사용될 때' 가 아닌 '정의될 때' 사용된다. 이것을 정적 유효범위, 렉시컬 스코핑 이라고 한다.




5. 지역변수와 let을 사용해야 하는 이유

변수명 중복 허용

글로벌 영역에 변수를 선언하면 이 변수는 어느 곳에서든지 참조할 수 있는 global scope를 갖는 전역 변수가 된다. 전역 변수는 전역 객체(Global Object) window의 프로퍼티이다.

  • 예시를 통해 변수명 중복이 허용될 때 발생하는 문제에 대해 알아보자.
// x.js
function foo() {
  // var i = 0;
  i = 0;
  // ...
}

// y.js
for (var i = 0; i < 5; i++) {
  foo();
  console.log(i);
}
  • x.jsy.js , 2개의 파일로 분리된 JS 코드를 불러온다. 두 개의 파일 안에는 의도하지않은 변수 i 가 중복으로 존재한다.

  • HTML에서 이 2개의 자바스크립트 파일을 로드하면 변수 i는 중복된다.

  • x.js 의 변수 ivar 키워드를 사용하지 않았으므로 암묵적으로 전역 변수화 되었고, y.js 의 변수 i 는 전역변수이다.

  • 이때 자바스크립트는 변수명의 중복이 허용되므로 에러메시지를 발생시키지는 않지만, 무한 반복 상태에 빠질 수 있게된다.

  • 코드가 길어지면 변수명의 중복이 발생하기 쉬워지게되고, 예기치 못한 이상 동작의 원인이 되기 쉬우며 오류를 해결하는 데에도 시간이 많이 들게 된다.

암묵적 전역 변수
: var 키워드를 생략한 변수는 암묵적으로 전역 변수가 되며, 이것을 암묵적 전역 변수(implicit global)라고 한다.


✍️ 이처럼 개발자의 의도와는 상관없이 동작하는 (1) '전역변수' 그리고 (2) '암묵적 전역 변수' 는 오류 발생 원인이 될 가능성이 크다.

따라서, 전역변수를 반드시 사용하여야 할 이유가 없다면 (1) '지역변수' 를, 그리고 (2) 'let' 을 사용하는 것이 좋다. 또한 변수의 범위인 스코프는 좁을수록 좋다.


📌 추가)

호이스팅은 변수 선언이 스코프의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 말한다.




reference
devyj-scope
JS-scope
JS-static scoping
medium-scope

profile
기억보단 기록을 ✨

0개의 댓글