aboutsummaryrefslogtreecommitdiff
path: root/files/ko/web/javascript/reference/statements/let/index.html
blob: 3d02a34fba619c5e6a63fa3e098cb3b6d154779a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
---
title: let
slug: Web/JavaScript/Reference/Statements/let
translation_of: Web/JavaScript/Reference/Statements/let
---
<div>{{jsSidebar("Statements")}}</div>

<p><strong><code>let</code></strong> 구문은 블록 유효 범위를 갖는 지역 변수를 선언하며, 선언과 동시에 임의의 값으로 초기화할 수도 있다.</p>

<div>{{EmbedInteractiveExample("pages/js/statement-let.html")}}</div>



<h2 id="Syntax">Syntax</h2>

<pre class="brush: js">let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];</pre>

<h3 id="Parameters">Parameters</h3>

<dl>
 <dt><code>var1</code>, <code>var2</code>, …, <code>varN</code></dt>
 <dd>변수명. 유효한 식별자이면 가능하다.</dd>
 <dt><code>value1</code>, <code>value2</code>, …, <code>valueN</code></dt>
 <dd>변수의 초기값. 유효한 표현식이면 가능하다.</dd>
</dl>

<h2 id="Description">Description</h2>

<p><strong><code>let</code></strong>은 변수가 선언된 블록, 구문 또는 표현식 내에서만 유효한 변수를 선언한다. 이는 <strong><a href="/en-US/docs/JavaScript/Reference/Statements/var"><code>var</code></a></strong> 키워드가 블록 범위를 무시하고 전역 변수나 함수 지역 변수로 선언되는 것과 다른 점이다.</p>

<p>"<strong>let</strong>"을 사용해야 하는 이유에 대해서는 이어지는 <a href="https://stackoverflow.com/questions/37916940/why-was-the-name-let-chosen-for-block-scoped-variable-declarations-in-javascri">링크</a>를 참조하시오.</p>

<h3 id="유효_범위_규칙">유효 범위 규칙</h3>

<p><strong><code>let</code></strong> 으로 선언된 변수는 변수가 선언된 블록 내에서만 유효하며, 당연하지만 하위 블록에서도 유효하다. 이러한 점에서는 <strong><code>let</code></strong><strong><a href="/en-US/docs/JavaScript/Reference/Statements/var"><code>var</code></a></strong>는 유사하지만, <strong><a href="/en-US/docs/JavaScript/Reference/Statements/var"><code>var</code></a></strong>는 함수 블록 이외의 블록은 무시하고 선언된다는 점이 다르다.</p>

<pre class="brush:js">function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // 상위 블록과 같은 변수!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // 상위 블록과 다른 변수
    console.log(x);  // 2
  }
  console.log(x);  // 1
}
</pre>

<p id="Scoping_rules">프로그램이나 함수의 최상위에서는 <strong><code>let</code></strong><strong><a href="/en-US/docs/JavaScript/Reference/Statements/var"><code>var</code></a></strong>은 서로 다르게 행동한다. <strong><code>let</code></strong>은 전역 객체의 속성 값을 생성하지 않는다.</p>

<pre class="brush:js">var x = 'global';
let y = 'global';
console.log(this.x); // "global" 전역 객체의 속성 x를 생성
console.log(this.y); // undefined 전역 객체의 속성 y를 생성하지 않음
</pre>

<h3 id="비공개_변수_모사">비공개 변수 모사</h3>

<p><a href="/en-US/docs/Glossary/Constructor">생성자</a>와 함께 사용하여 <a href="/en-US/docs/Web/JavaScript/Closures">클로저</a>를 사용하지 않고 비공개 변수를 만들고 접근할 수 있다.</p>

<pre class="brush:js">var Thing;

{
  let privateScope = new WeakMap();
  let counter = 0;

  Thing = function() {
    this.someProperty = 'foo';

    privateScope.set(this, {
      hidden: ++counter,
    });
  };

  Thing.prototype.showPublic = function() {
    return this.someProperty;
  };

  Thing.prototype.showPrivate = function() {
    return privateScope.get(this).hidden;
  };
}

console.log(typeof privateScope);
// "undefined"

var thing = new Thing();

console.log(thing);
// Thing {someProperty: "foo"}

thing.showPublic();
// "foo"

thing.showPrivate();
// 1
</pre>

<h3 id="임시적인_사각_지역과_오류">임시적인 사각 지역과 오류</h3>

<p>같은 변수를 같은 함수나 블록 범위 내에서 재선언하면 {{jsxref("SyntaxError")}}가 발생한다.</p>

<pre class="brush: js example-bad">if (x) {
  let foo;
  let foo; // SyntaxError thrown.
}</pre>

<p>ECMAScript 2015에서는<strong><code>let</code></strong><strong>선언 끌어올리기</strong>의 적용을 받지 않습니다.  이는 <strong><code>let</code></strong> 선언이 현재 실행되는 구간의 최상위로 옮겨지지 않는다는 것을 의미합니다. 따라서 변수가 초기화(선언)되기 전에 참조할 경우 <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/ReferenceError">ReferenceError</a></code>가 발생합니다.(<strong><a href="/en-US/docs/JavaScript/Reference/Statements/var"><code>var</code></a></strong>로 선언된 변수는 undefined 값을 가지는 것과는 대조적입니다.) "임시적인 사각 지역"은 블록 시작 부분부터 변수 선언이 실행되기 전까지 입니다.</p>

<p>(<strong><code>let</code></strong>들의 정의가 평가되기까지 초기화가 되지 않는다는 의미이지. 호이스팅이 되지않아 정의가 되지 않는다는 의미와는 다르다고 생각함_헷갈리면 안된다.)</p>

<pre class="brush: js example-bad">function do_something() {
  console.log(bar); // undefined
  console.log(foo); // ReferenceError
  var bar = 1;
  let foo = 2;
}</pre>

<p><a href="/en-US/docs/JavaScript/Reference/Statements/switch"><code>switch</code></a> 구문을 사용할 때는 실제 블록이 하나 뿐이므로 중복 선언 오류가 발생하기 쉽습니다.</p>

<pre class="brush: js example-bad">let x = 1;
switch(x) {
  case 0:
    let foo;
    break;

  case 1:
    let foo; // 재선언에 의한 SyntaxError.
    break;
}</pre>

<p>하지만 case 조건을 새로운 블록으로 감싸면 위의 코드와는 다르게 재선언 오류가 발생하지 않습니다.</p>

<pre class="brush: js">let x = 1;

switch(x) {
  case 0: {
    let foo;
    break;
  }
  case 1: {
    let foo;
    break;
  }
}</pre>

<h3 id="임시적인_사각_지역과_typeof">임시적인 사각 지역과 <code>typeof</code></h3>

<p>선언되지 않은 변수와 <code>undefined</code> 값을 지닌 변수와는 다르게, 임시적인 사각 지역에 있는 변수에 변수형 확인을 위해 <code>typeof</code>을 사용하면 <code>ReferenceError</code>가 발생합니다:</p>

<pre class="brush: js">// 'undefined' 출력
console.log(typeof undeclaredVariable);
// 'ReferenceError' 발생
console.log(typeof i);
let i = 10;</pre>

<h3 id="정적_유효_범위와_결합된_임시적인_사각_지역_예시">정적 유효 범위와 결합된 임시적인 사각 지역 예시</h3>

<p>정적 유효 범위로 인해, 표현 <code>(foo + 55)</code> 내부의 "<strong>foo</strong>"는 33을 값으로 가지는 <u>상위 블록의 foo</u>가 아니라 <u>if 블록의 foo</u>로 해석됩니다. 해당 행에서 <u>if 블록의 "foo"</u>는 이미 정적 유효 범위에 생성되었지만, 선언의 초기화가 완료(선언 구문의 <strong>종료</strong>)되지 않았습니다. 따라서 여전히 임시적인 사각 지역에 해당됩니다.</p>

<pre class="brush: js example-bad">function test(){
   var foo = 33;
   if (true) {
      let foo = (foo + 55); // ReferenceError
   }
}
test();</pre>

<p>이 현상은 다음과 같은 상황에서 혼란을 유발할 수 있습니다. 지시 구문  <code>let n of n.a</code>은 이미 for loop 블록에 속해 있으며, 구문자 "<strong>n.a</strong>"는 속성 'a'를 지시 구문 자기자신의 앞부분에 위치한 객체 'n'에서 참조하려 합니다. 해당 객체 'n'은 위와 마찬가지로 선언이 <strong>종료</strong>되지 않았기에 임시적인 사각 지역에 해당합니다.</p>

<pre class="brush: js example-bad">function go(n) {
  // 정의되어 있는 n!
  console.log(n); // Object {a: [1,2,3]}

  for (let n of n.a) { // ReferenceError
    console.log(n);
  }
}

go({a: [1, 2, 3]});
</pre>

<h2 id="그_외_상황들">그 외 상황들</h2>

<p>블록을 사용할 때, <strong><code>let</code></strong>은 변수의 유효 범위를 블록으로 제한합니다. 함수 내 또는 전역을 유효 범위로 가지는 <code><strong>var</strong></code>와의 차이점을 숙지하세요.</p>

<pre class="brush: js">var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // 전역 변수
  let b = 22; // if 블록 변수

  console.log(a);  // 11
  console.log(b);  // 22
}

console.log(a); // 11
console.log(b); // 2</pre>

<h2 id="Specifications">Specifications</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Specification</th>
   <th scope="col">Status</th>
   <th scope="col">Comment</th>
  </tr>
  <tr>
   <td>{{SpecName('ES2015', '#sec-let-and-const-declarations', 'Let and Const Declarations')}}</td>
   <td>{{Spec2('ES2015')}}</td>
   <td>Initial definition. Does not specify let expressions or let blocks.</td>
  </tr>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-let-and-const-declarations', 'Let and Const Declarations')}}</td>
   <td>{{Spec2('ESDraft')}}</td>
   <td></td>
  </tr>
 </tbody>
</table>

<h2 id="Browser_compatibility">Browser compatibility</h2>



<p>{{Compat("javascript.statements.let")}}</p>

<h2 id="See_also">See also</h2>

<ul>
 <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/var"><code>var</code></a></li>
 <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/const"><code>const</code></a></li>
 <li><a href="https://hacks.mozilla.org/2015/07/es6-in-depth-let-and-const/">ES6 In Depth: <code>let</code> and <code>const</code></a></li>
 <li><a href="https://blog.mozilla.org/addons/2015/10/14/breaking-changes-let-const-firefox-nightly-44/">Breaking changes in <code>let</code> and <code>const</code> in Firefox 44</a></li>
 <li><a href="https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch3.md">You Don't Know JS: Scope &amp; Closures: Chapter 3: Function vs. Block Scope</a></li>
 <li><a href="https://stackoverflow.com/a/33198850/1125029">StackOverflow: What is the Temporal Dead Zone. </a></li>
 <li><a href="https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var-to-declare-a-variable">StackOverflow: What is the difference between using let and var?</a></li>
</ul>