> For the complete documentation index, see [llms.txt](https://dahye-jeong.gitbook.io/til/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dahye-jeong.gitbook.io/til/javascript/2019-10-07-scope.md).

# SCOPE

**스코프는 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이다.** 식별자는 자신이 어디에서 선언됐는지에 의해 자신이 유효한 범위를 갖는다.

```javascript
var x = 'global';

function foo(){
  var x = 'function scope';
  console.log(x);
}
foo(); // 'function scope'
console.log(x); // global
```

이름이 같은 변수 x가 중복 선언되어있는 예시이다. 전역으로 선언된 x는 어디에서든 참조할 수 있지만 foo 함수 내부에서 선언된 x는 내부에서만 참조할 수 있고, 함수 외부에서는 참조할 수 없다. 이러한 규칙을 스코프라고 한다. 모든 변수는 스코프를 가진다.

* 전역 스코프 ( Global Scope ) : 코드 어디에서든지 참조 가능
* 지역 스코프 ( Local Scope or Function-Level Scope) : 함수 코드 블록이 만든 스코프로 함수 자신과 하위 함수에서만 참조 가능

타 언어는 블록 레벨 스코프 ( block-level scope )를 따른다. 하지만 자바스크립트는 **함수 레벨 스코프( function-level scope )** 를 따른다. 함수 레벨 스코프란 함수 코드 블록 내에서 선언된 변수는 함수 코드 블록내에서만 유효하며, 함수 외부에서는 유효하지 않다.

단, ECMAScript 6에서 도입된 `let` 키워드를 사용하면 블록 레벨 스코프를 사용할 수 있다.

```javascript
var x = 0;
{
  var x = 1;
  console.log(x); // 1
}
console.log(x);   // 1

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

전역 변수는 전역 객체(Global Object)인 `window` 의 프로퍼티이다.

```javascript
var x = 'global';

function foo(){
  var x = 'function scope';
  console.log(x);
}
console.log(window.x);  // 'global';
```

전역 변수의 사용은 변수 이름이 중복될 수 있으며, 의도치 않은 재할당에 의한 상태 변화로 코드를 예측하기 어렵게 만드므로 사용을 억제해야한다.

### Lexical Scope

**lexical scope는 함수를 어디서 호출하는지가 아니라 어디에 선언하였는지에 따라 결정**된다. 자바스크립트는 lexical scope를 따르므로 함수를 선언한 시점에 상위 스코프가 결정된다.

```javascript
var x = 1;

function foo() {
  var x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // 1
bar(); // 1
```

lexical scope를 따르므로, `foo()`, `bar()` 호출시 1이 출력되는 것을 확인할 수 있다.

### 최소한의 전역변수 사용

자바스크립트는 변수명의 중복을 허용하므로, 전역변수의 무분별한 사용은 무척 위험하다. 전역 변수를 반드시 사용해야할 이유가 없다면, 지역변수를 사용하고, 변수의 범위인 스코프는 좁을수록 좋다.

```javascript
var MYAPP = {};
MYAPP.student = {
  name: 'Faker',
  gender: 'male'
};
```

전역변수를 최소화하는 방법 중 하나는 전역변수 객체를 하나 생성해서 사용하는 것이다.

### 즉시 실행 함수

즉시 실행 함수(IIFE, Immediately-Invoked Function Expression)를 사용하면, 전역변수 사용을 억제할 수 있다.

```javascript
(function () {
  var MYAPP = {};

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

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

console.log(MYAPP.student.name);
VM1857:12 Uncaught ReferenceError: MYAPP is not defined
    at <anonymous>:12:13
```

이 방법을 사용하면 전역변수를 만들지 않으므로 라이브러리 등에서 자주 사용되며, 즉시 실행 함수는 즉시 실행되고 그 후 바로 사라진다.

## 참조 페이지

* [스코프](https://poiemaweb.com/js-scope)
