Skip to content

Commit a5a2af3

Browse files
committed
chapter 14 업로드
1 parent 6701c93 commit a5a2af3

1 file changed

Lines changed: 214 additions & 0 deletions

File tree

book/이용우/chapter_14.md

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
# Chapter 14 - 전역 변수의 문제점
2+
전역 변수의 무분별한 사용은 위험하다.
3+
해당 챕터에서는 전역 변수의 문제점과 전역 변수의 사용을 억제할 수 있는 방법에 대해 기술한다.
4+
5+
<br><br><hr>
6+
7+
### 변수의 생명 주기
8+
#### 지역 변수의 생명 주기
9+
변수는 생성되고 소멸되는 생명 주기(life cycle)가 있다.
10+
변수에 생명 주기가 없다면, 한번 선언된 변수는
11+
프로그램을 종료하지 않는 한 영원히 메모리 공간을 점유하게 된다.
12+
13+
``` js
14+
function foo() {
15+
let x = 'local';
16+
console.log(x);
17+
return x;
18+
}
19+
20+
foo();
21+
console.log(x); // ReferenceError: x is not defined
22+
```
23+
24+
지역 변수 x는 foo 함수가 호출되기 이전까지는 생성되지 않고,
25+
변수 스코프 규칙에 따라 foo 함수 안에서만 존재하게 된다.
26+
이는 <font color='orange'>지역 변수의 생명 주기가 함수의 생명 주기와 일치한다는 말과 동일시 할 수 있다. </font>
27+
28+
다만, 함수 내부에서 선언된 지역 변수가 함수보다 조금 더 오래 생존하는 경우도 있다.
29+
30+
변수는 하나의 값을 저장하기 위해 확보한 메모리 공간 또는 그 메모리 공간을 식별하기 위해 붙인 이름이다.
31+
따라서 변수의 생명 주기는 메모리 공간이 확보(allocate)된 시점부터 메모리 공간이 해제(release)되어
32+
가용 메모리 풀(memory pool)에 반환되는 시점 까지이다.
33+
34+
함수 내부에서 선언된 지역 변수는 함수가 생성한 스코프에 등록된다.
35+
<font color='orange'>함수가 생성한 스코프는 렉시컬 환경이라 부르는 물리적인 실체가 있다.</font>
36+
따라서 변수는 자신이 등록된 스코프가 소멸(메모리 해제)될 때 까지 유효하다.
37+
38+
할당된 메모리 공간은 더 이상 누구도 참조하지 않을 때,
39+
가비지 콜렉터에 의해 해제되어 가용 메모리 풀에 반환된다.
40+
즉, 누군가 메모리 공간을 참조하고 있으면 해제되지 않고 확보된 상태로 남아있게 된다.
41+
이는 스코프에도 동일하게 적용된다.
42+
43+
<font color='orange'>누군가 스코프를 참조하고 있으면 스코프는 소멸하지 않고 생존하게 된다.</font>
44+
45+
> 일반적으로 함수가 종료되면 함수가 생성한 스코프도 소멸되지만,
46+
> 누군가 스코프를 참조하고 있다면 스코프는 해제되지 않고 생존하게 된다.
47+
> 이에 대해서는 24장 "클로저"에서 다루게 된다.
48+
49+
50+
<br><br>
51+
52+
53+
#### 전역 변수의 생명 주기
54+
함수와 달리 전역 코드는 명시적인 호출 없이 실행된다.
55+
다시 말해, 전역 변수는 함수 호출과 같이 전역 코드를 실행하는 특별한 진입점 없이
56+
코드가 로드되자마자 곧바로 해석되고 실행된다.
57+
58+
함수는 함수 몸체의 마지막 문 또는 반환문이 실행되면 종료된다.
59+
하지만 <font color='orange'>전역 코드에는 반환문을 사용할 수 없으므로 마지막 문이 실행되어
60+
더 이상 실행할 문이 없을 때 종료된다.</font>
61+
> 전역 변수는 전역 객체의 프로퍼티가 된다.
62+
63+
※ 전역 객체(global object)
64+
전역 객체는 코드가 실행되기 이전 단계에 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체이다.
65+
전역 객체는 클라이언트 사이드 환경(브라우저)에서는 `window`, 서버 사이드 환경(Node.js)에서는 `global` 객체를 의미한다.
66+
환경에 따라 전역 객체를 가리키는 다양한 식별자(`window`, `self`, `this`, `frames`, `global`)가 존재했으나 ES11에서 `globalThis`로 통일되었다.
67+
전역 객체는 표준 빌트인 객체(`Object`, `String`, `Number`, `Function`, `Array`, ....)와 환경에 따른 호스트 객체, 그리고 `var` 키워드로 선언한 전역 변수와 전역 함수를 프로퍼티로 갖는다.
68+
69+
<br>
70+
71+
``` js
72+
var x = 'global';
73+
74+
function foo() {
75+
var x = 'local';
76+
console.log(x);
77+
return x;
78+
}
79+
80+
foo();
81+
console.log(x);
82+
```
83+
84+
<br><br><hr>
85+
86+
### 전역 변수의 문제점
87+
#### 암묵적 결합
88+
전역 변수는 모든 코드가 참조하고 변경이 가능한 암묵적 결합(implict coupling)을 허용한다.
89+
변수의 유효 범위가 크면 클 수록 코드의 가독성이 나빠지고 의도치 않게 상태가 변경될 수 있는 위험성도 높아진다.
90+
91+
<br>
92+
93+
#### 긴 생명 주기
94+
전역 변수는 생명 주기가 길다.
95+
따라서 메모리 리소스도 오랜 기간 소비하게 된다.
96+
97+
더욱이 var 키워드는 변수의 중복 선언을 허용하므로
98+
생명 주기가 긴 전역 변수는 변수 이름이 중복될 가능성이 있다.
99+
100+
변수 이름이 중복되면 의도치 않은 재할다잉 이루어진다.
101+
102+
<br>
103+
104+
#### 스코프 체인 상에서 종점에 존재
105+
전역 변수는 스코프 체인 상에서 종점에 존재한다.
106+
이는 변수를 검색할 때 전역 변수가 가장 마지막에 검색된다는 것을 말한다.
107+
108+
**즉, 전역 변수의 검색 속도가 가장 느리다.**
109+
110+
<br>
111+
112+
#### 네임스페이스 오염
113+
자바 스크립트의 문제점 중 하나는 파일이 분리되어 있다고 해도 하나의 전역 스코프를 공유한다는 것이다.
114+
따라서 다른 파일 내에서 동일한 이름으로 명명된 전역 변수나 전역 함수가 같은 스코프 내에 존재할 경우
115+
예상치 못한 결과를 가지고 올 수 있다.
116+
117+
<br><br><hr>
118+
119+
### 전역 변수의 사용을 억제하는 방법
120+
전역 변수를 사용해야 할 이유를 말할 수 없다면,
121+
지역 변수를 사용하는 것이 좋다. 변수의 스코프는 좁을 수록 좋다.
122+
123+
전역 변수의 사용을 억제할 수 있는 방법 몇 가지에 대해 다뤄보자.
124+
125+
#### 즉시 실행 함수
126+
함수 정의와 동시에 호출되는 즉시 실행 함수는 단 한번만 호출된다.
127+
모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 된다.
128+
129+
``` js
130+
(function () {
131+
var foo = 10; // 즉시 실행 함수의 지역 변수
132+
}());
133+
134+
console.log(foo); // ReferenceError: foo is not defined
135+
```
136+
137+
이 방법을 사용하면 전역 변수를 생성하지 않으므로 라이브러리 등에 자주 사용된다.
138+
139+
<br>
140+
141+
#### 네임스페이스 객체
142+
전역에 네임스페이스 역할을 담당할 객체를 생성하고 전역 변수처럼 사용하고 싶은 변수를 프로퍼티로 추가하는 방법이다.
143+
144+
``` js
145+
let MYAPP = {}; // 전역 네임스페이스 객체
146+
147+
MYAPP.name = 'Lee';
148+
console.log(MYAPP.name); // Lee
149+
```
150+
151+
> 전역 객체 안에서 관리
152+
153+
식별자 충돌을 방지하는 효과는 있지만 네임스페이스 객체 자체가 전역 변수이기에 주의해야 한다.
154+
155+
<br>
156+
157+
#### 모듈 패턴
158+
모듈 패턴을 클래스를 모방해서
159+
관련이 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈을 만든다.
160+
**이는 자바스크립트의 강력한 기능인 클로저를 기반으로 동작한다.**
161+
162+
모듈 패턴의 특징은 전역 변수의 억제는 물론 캡슐화까지 구현할 수 있다는 것이다.
163+
164+
<br>
165+
166+
``` js
167+
var Counter = (function () {
168+
// private 변수
169+
var num = 0;
170+
171+
// 외부로 공개할 데이터나 메소드를 프로퍼티로 추가한 객체를 반환한다.
172+
return {
173+
increase() {
174+
return ++num;
175+
},
176+
decrease() {
177+
return --num;
178+
}
179+
}
180+
});
181+
182+
// private 변수는 외부로 노출되지 않는다.
183+
console.log(Counter.num); // undefined
184+
185+
console.log(Counter.increase()); // 1
186+
console.log(Counter.increase()); // 2
187+
console.log(Counter.decrease()); // 1
188+
console.log(Counter.decrease()); // 0
189+
```
190+
191+
<br>
192+
193+
#### ES6 모듈
194+
ES6 모듈부터는 더는 전역 변수를 사용하지 못하게 막는다.
195+
ES6 모듈은 파일 자체의 독자적인 모듈 스코프를 제공한다.
196+
197+
따라서 모듈 내에서 `var` 키워드로 선언한 변수는 더는 전역 변수가 아니며
198+
`window` 객체의 프로퍼티도 아니다.
199+
200+
<br>
201+
202+
모던 브라우저에서는 ES6 모듈을 사용할 수 있다.
203+
`script` 태그에 `type="module"` 어트리뷰트를 추가하면 로드된 자바스크립트 파일은 모듈로서 동작한다.
204+
모듈의 파일 확장자는 `mjs`를 권장한다.
205+
206+
``` js
207+
<script type="module" src="lib.mjs"></script>
208+
<script type="module" src="app.mjs"></script>
209+
```
210+
211+
ES6 모듈은 IE를 포함한 구형 브라우저에서는 동작하지 않으며,
212+
브라우저의 ES6 모듈 기능을 사용하더라도 트랜스파일링이나 번들링이 필요하기 때문에
213+
아직까지는 브라우저가 지원하는 ES6 모듈 기능보다는 Webpack 등의 모듈 번들러를 사용하는 것이 일반적이다.
214+

0 commit comments

Comments
 (0)