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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
|
---
title: JavaScript 재입문하기 (JS 튜토리얼)
slug: A_re-introduction_to_JavaScript
tags:
- CodingScripting
- Intermediate
- Intro
- JavaScript
- Learn
- Tutorial
translation_of: Web/JavaScript/A_re-introduction_to_JavaScript
---
<div>{{jsSidebar}}</div>
<p>어째서 재입문일까요? 왜냐하면, <a href="/ko/docs/Glossary/JavaScript">JavaScript</a>는 <a class="external" href="http://javascript.crockford.com/javascript.html">세계에서 가장 오해받고 있는 프로그래밍 언어</a>로 악명이 높기 때문입니다. 종종 장난감같다고 조롱당하기도했지만, 이 거짓말같은 단순함 아래에는 몇 가지의 강력한 언어 기능이 숨어 있습니다. Javascript는 현재 엄청나게 많은, 요즘 가장 뜨고있는 애플리케이션들에 사용되고 있어서, 웹 또는 모바일 개발자 누구에게라도 이 기술에 대한 깊은 지식이 중요한 기량이 된다는 것을 보여주고 있습니다.</p>
<p>이 이야기를 이해하는데는 이 언어의 역사를 먼저 보는 것이 도움이 됩니다. JavaScript는 1995년 Netscape의 엔지니어 Brendan Eich에 의해 만들어졌고, 1996년 초에 Netscape 2와 함께 처음 릴리즈 되었습니다. 이것은 원래 LiveScript로 불리기로 되어 있었습니다만 Sun Microsystem의 Java 언어의 성공에 편승해보려고 -두 언어 사이의 공통점이 매우 적음에도 불구하고- 불행이 예견된 마케팅 결정에 따라 이름이 바뀌게 됩니다. 이 결정은 역사상 유래가 없는 혼란의 근원이 되어버립니다.</p>
<p>몇 달 후, Microsoft는 IE3와 함께 JScript를 발표했습니다. 이 JScript는 Javascript를 정말 닮았고 호환성이 좋았습니다. 몇 달 뒤에, Netscape는 1997년에 <a href="/ko/docs/Glossary/ECMAScript">ECMAScript</a> 표준의 첫번째 판이 되는 JavaScript를 유럽 표준화 단체인 <a class="external" href="http://www.ecma-international.org/">Ecma International</a>에 보냅니다. 이 표준은 1999년에 <a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript edition 3</a>에 따라 큰 규모의 개정을 거친 후, 유례없이 아주 안정된 상태로 계속 유지되고 있습니다. <span style="line-height: 16.7999992370605px;">4번째 판은 중도 포기되었는데, 언어의 복잡성 증가에 관련한 정치적 문제 때문이었습니다. 이 4번째 판의 많은 파트들은 ECMAScript edition 5 (2009년 12월에 출간)와 6번째 개정판 규격(2015년에 출간)의 근간을 형성하고 있습니다. </span></p>
<div class="note">
<p> 이제부터는 ECMAScript를 우리에게 좀 더 친근한 말인 <span style="line-height: 16.7999992370605px;"> "</span>JavaScript"라고 부르겠습니다.</p>
</div>
<p>대부분의 프로그래밍 언어와는 달리, JavaScript 언어는 입출력 개념이 없습니다. 이 언어는 호스트 환경 아래에서 스크립트 언어로서 동작하도록 디자인 되어있고, 따라서 외부 세계와 통신하기위해 호스트 환경이 제공하는 메커니즘에 의존합니다. 대부분의 경우 일반적인 호스트 환경은 브라우저이지만 JavaScript 인터프리터는 Adobe Acrobat, Photoshop, SVG images, Yahoo! 위젯 엔진 등의 제품에서도 발견할 수 있고, <a href="http://nodejs.org/">node.js</a> 와 같은 서버 측 환경에서도 찾을 수 있습니다. 하지만 JavaScript가 사용되는 분야는 계속 더 넓혀지고 있습니다. NoSQL 데이터베이스, <a href="http://couchdb.apache.org/">Apache CouchDB</a>, 임베디드 컴퓨터, GNU/Linux OS의 가장 유명한 GUI 인 <a href="http://www.gnome.org/">GNOME</a> 과 같은 데스크톱 환경에서도 JavaScript가 사용됩니다.</p>
<h2 id=".EA.B0.9C.EC.9A.94" name=".EA.B0.9C.EC.9A.94">개요</h2>
<p>JavaScript는 유형 및 연산자, 표준 내장 객체 및 메소드가 있는 다중 패러다임, 동적 언어입니다. 구문은 Java 및 C 언어를 기반으로합니다. 이러한 언어의 많은 구조가 JavaScript에도 적용됩니다. JavaScript는 클래스 대신 객체 프로토 타입을 사용하여 객체 지향 프로그래밍을 지원합니다 (<a href="/ko//docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain">프로토 타입 상속</a> 및 ES2015 {{jsxref("Classes")}}). JavaScript는 함수형 프로그래밍도 지원합니다. 함수는 객체이며, 함수는 실행 가능한 코드를 유지하고 다른 객체와 마찬가지로 전달 될 수 있습니다.</p>
<p>어떤 언어에서라도 기초가 되는 부분인 타입을 살펴보는 것부터 시작해봅시다. JavaScript 프로그램은 값을 다루고 해당 값은 모두 타입을 가지고 있습니다. JavaScript의 타입은 다음과 같습니다:</p>
<ul>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Number">수 (Number)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/String">문자열 (String)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Boolean">부울 (Boolean)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Function">함수 (Function)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Object">객체 (Object)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Symbol">기호 (Symbol)</a> (ES2015에 새롭게 추가)</li>
</ul>
<p>... 오, 그리고 약간 특별한 타입인 정의되지 않음(Undefined) 과 널(Null) 이 있습니다. 또한 객체의 특별한 종류인 <a href="ko/Web/JavaScript/Reference/Global_Objects/Array">배열(Array) 객체</a>. 그리고 자유롭게 사용할 수 있는 <a href="ko/Web/JavaScript/Reference/Global_Objects/Date">날짜(Date) 객체</a> 와 <a href="ko/Web/JavaScript/Reference/Global_Objects/RegExp">정규식(RegExp) 객체</a>가 있습니다. 그리고 기술적으로 정확히 말해 함수(Function)는 단지 객체의 특별한 타입으로 취급됩니다. 따라서 타입 구조도를 정리해보면 다음과 같습니다:</p>
<ul>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Number">수 (Number)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/String">문자열 (String)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Boolean">부울 (Boolean)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Symbol">기호 (Symbol)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Object">객체 (Object)</a>
<ul>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Function">함수 (Function)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Array">배열 (Array)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/Date">날짜 (Date)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/RegExp">정규식 (RegExp)</a></li>
</ul>
</li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/null">널 (Null)</a></li>
<li><a href="ko/Web/JavaScript/Reference/Global_Objects/undefined">정의되지 않음 (Undefined)</a></li>
</ul>
<p>그리고 또 몇 가지 <a href="ko/Web/JavaScript/Reference/Global_Objects/Error">오류</a> 타입이 내장되어 있습니다. 그렇지만 처음 구조도를 기억하고만 있으면 다른 것들도 아주 쉽게 이해할 수 있을 것입니다.</p>
<h2 id=".EC.88.98_.28Numbers.29" name=".EC.88.98_.28Numbers.29">수 (Numbers)</h2>
<p>설계 명세서에 의하면 JavaScript에서 수는 "이중정밀도 64비트 형식 IEEE 754 값"으로 정의됩니다. 이것은 몇가지 흥미로운 결과를 가져옵니다. JavaScript에는 <strong>정수와 같은 것이 존재하지 않으므로 </strong>({{jsxref("BigInt")}} 제외), 조금 조심해야 합니다. 이 예제를 보세요:</p>
<pre class="syntaxbox notranslate">console.log(3 / 2); // 1이 아닌, 1.5
console.log(Math.floor(3 / 2)); // 1</pre>
<p><em>명백한 정수</em>는 사실 <em>암묵적으로 실수</em>입니다.</p>
<p>또한, 다음과 같은 것들을 주의하세요:</p>
<pre class="brush: js notranslate">0.1 + 0.2 = 0.30000000000000004
</pre>
<p>실제로 정수 값은 32 비트 정수로 처리되며 일부 구현은 32 비트 정수가 아닌 숫자에 유효한 명령어를 수행 할 때까지 이러한 방식으로 저장합니다. 이는 비트 단위 작업에 중요 할 수 있습니다.</p>
<p>덧셈, 뺄셈, 계수 (또는 나머지) 연산을 포함하는 표준 <a href="ko/Core_JavaScript_1.5_Reference/Operators/Arithmetic_Operators">산술 연산자</a>가 지원됩니다. 또한 앞에서 언급하는 것을 깜박 잊은 고급 수학 함수와 상수를 다루기 위한 <a href="ko/Core_JavaScript_1.5_Reference/Global_Objects/Math">수학(Math)</a>으로 불리는 내장 객체가 있습니다:</p>
<pre class="brush: js notranslate">Math.sin(3.5);
var circumference = 2 * Math.PI * r;</pre>
<p>내장 <code><a href="ko/Core_JavaScript_1.5_Reference/Global_Functions/parseInt">parseInt()</a></code> 함수를 사용하여 문자열을 정수로 변환할 수 있습니다. 이는 다음과 같이 옵션으로 주어지는 두번째 매개변수를 밑으로 하여 수행할 수 있습니다:</p>
<pre class="brush: js notranslate">parseInt('123', 10); // 123
parseInt('010', 10); // 10</pre>
<p>구형 브라우저에서 "0"으로 시작하는 문자열은 8 진수 (기수 8)로 가정되지만, 2013 년 이후에는 그렇지 않습니다. 문자열 형식이 확실하지 않으면 이전 브라우저에서 놀라운 결과를 얻을 수 있습니다.</p>
<pre class="brush: js notranslate">parseInt('010'); // 8
parseInt('0x10'); // 16</pre>
<p>이 같은 결과는 <code>{{jsxref("Global_Objects/parseInt", "parseInt()")}}</code> 함수가 0으로 시작되는 문자열을 8진수로, "0x"로 시작하는 문자열은 16진수로 취급하기 때문에 발생합니다. 16진수 표기법이 그대로 유지됩니다. 8진수는 제거되었습니다.</p>
<p>만약 이진수를 정수로 변환하고 싶다면, 밑을 바꾸기만하면 됩니다:</p>
<pre class="brush: js notranslate">parseInt('11', 2); // 3
</pre>
<p>이와 비슷하게, 내장 함수 {{jsxref("Global_Objects/parseFloat", "parseFloat()")}}를 사용하여 부동 소수점 숫자를 파싱 할 수 있습니다. {{jsxref("Global_Objects/parseInt", "parseInt()")}}과 달리 parseFloat()는 항상 10진수를 사용합니다.</p>
<p>단항 연산자 + 를 사용하여 값을 숫자로 변환 할 수도 있습니다:</p>
<pre class="brush: js notranslate">+ '42'; // 42
+ '010'; // 10
+ '0x10'; // 16</pre>
<p>문자열이 수가 아닌 경우 <code><a href="ko/Core_JavaScript_1.5_Reference/Global_Properties/NaN">NaN</a></code> ("Not a Number" (수가 아님)을 줄인 약자)로 불리는 특별한 값을 돌려줍니다:</p>
<pre class="brush: js notranslate">parseInt('hello', 10); // NaN
</pre>
<p><code>NaN</code> 는 독성을 가지고 있습니다: 어떤 수학 연산의 입력값으로써 주어지면 그 결과는 역시 <code>NaN</code>가 되기 때문입니다:</p>
<pre class="brush: js notranslate">NaN + 5; // NaN
</pre>
<p>내장 <code><a href="ko/Core_JavaScript_1.5_Reference/Global_Functions/isNaN">isNaN()</a></code> 함수를 사용해서 <code>NaN</code> 인지 여부를 검사할 수 있습니다:</p>
<pre class="brush: js notranslate">isNaN(NaN); // true
</pre>
<p>JavaScript는 또 특별한 값 <code><a href="ko/Core_JavaScript_1.5_Reference/Global_Properties/Infinity">Infinity</a></code>와 <code>-Infinity</code>를 가지고 있습니다:</p>
<pre class="brush: js notranslate"> 1 / 0; // Infinity
-1 / 0; // -Infinity</pre>
<p>내장 함수 {{jsxref("Global_Objects/isFinite", "isFinite()")}}를 사용하여 Infinity, -Infinity 및 NaN 값을 테스트 할 수 있습니다.</p>
<pre class="brush: js notranslate">isFinite(1 / 0); // false
isFinite(-Infinity); // false
isFinite(NaN); // false</pre>
<div class="note">
<p>{{jsxref("Global_Objects/parseInt", "parseInt()")}} 와 {{jsxref("Global_Objects/parseFloat", "parseFloat()")}} 함수는 숫자로 아닌 문자가 나올때까지 문자열을 파싱하고, 그 지점까지 파싱된 숫자를 반환합니다. 그런데 "+"연산자는 중간에 유효하지 않은 문자가 있으면 그대로 문자열을 <code>NaN</code> 으로 그냥 변환해버립니다. console에서 "10.2abc"를 파싱해보면 어떤점이 다른지 더 쉽게 이해할 수 있습니다.</p>
</div>
<h2 id=".EB.AC.B8.EC.9E.90.EC.97.B4_.28Strings.29" name=".EB.AC.B8.EC.9E.90.EC.97.B4_.28Strings.29">문자열 (Strings)</h2>
<p>JavaScript에서 문자열은 <a href="ko/Core_JavaScript_1.5_Guide/Unicode">유니코드 문자들</a>이 연결되어 만들어진 것입니다. 이는 국제화(i18n, internationalization) 하려하는 누구에게라도 환영받을만한 소식입니다. 좀 더 정확히 말하자면, 각각이 16비트 숫자로 표현된 UTF-16 코드 유닛이 길게 이어져있는 것입니다. 각 유니코드 문자는 1개나 2개의 코드 유닛으로 표현됩니다.</p>
<p>한 개의 문자를 나타내려면 길이가 1인 문자열을 사용하면 됩니다.</p>
<p>문자열의 길이를 알고싶다면, 해당 문자열의 <code><a href="ko/Core_JavaScript_1.5_Reference/Global_Objects/String/length">length</a></code> 속성(해당 객체가 소유하고 있는 성질을 나타내는 값)에 접근하면 됩니다:</p>
<pre class="brush: js notranslate">'hello'.length; // 5
</pre>
<p>우리의 첫 JavaScript 객체입니다! 문자열도 역시 객체로 취급된다고 언급했던적이 있죠? 다음과 같이 <a href="ko/Core_JavaScript_1.5_Reference/Global_Objects/String#Methods">메소드</a>까지 있는 확실한 녀석입니다:</p>
<pre class="brush: js notranslate">'hello'.charAt(0); // "h"
'hello, world'.replace('hello', 'goodbye'); // "goodbye, world"
'hello'.toUpperCase(); // "HELLO"</pre>
<h2 id=".EC.9D.B4.EC.99.B8.EC.9D.98_.ED.83.80.EC.9E.85.EB.93.A4" name=".EC.9D.B4.EC.99.B8.EC.9D.98_.ED.83.80.EC.9E.85.EB.93.A4">이외의 타입들</h2>
<p>JavaScript는 의도적으로 값이 없음을 가리키는 '객체' 타입의 객체인 <code>null</code>과 초기화되지 않은 값 — 아직 어떤 값도 주어지않은(할당되지않은) 변수임을 가리키는 '정의되지 않음' 타입의 객체인 <code>undefined</code>로 구분됩니다. 값에 대해서 나중에 언급할 것이지만 JavaScript에서 변수에 값을 주지않고 선언하는 것이 가능합니다. 이럴 경우, 변수의 타입은 <code>undefined</code>이 되는 것입니다.</p>
<p>JavaScript는 <code>true</code> 와 <code>false</code> 값 (둘은 모두 키워드로 예약되어있는 값)을 가질 수 있는 부울 타입을 가지고 있습니다. 다음과 같은 규칙에 따라 어떤 임의의 값을 부울값으로 변환할 수 있습니다:</p>
<ol>
<li><code>false</code>, <code>0</code>, 빈 문자열 (<code>""</code>), 수가 아님을 뜻하는 <code>NaN</code>, <code>null</code>, 와 <code>undefined</code>은 모두 <code>false</code>가 됩니다.</li>
<li>다른 모든 값은 <code>true</code>가 됩니다.</li>
</ol>
<p>이 변환은 <code>Boolean()</code> 함수를 써서 명시적으로 이 작업을 수행하실 수 있습니다:</p>
<pre class="brush: js notranslate">Boolean(''); // false
Boolean(234); // true</pre>
<p>하지만 반드시 이렇게 할 필요는 거의 없습니다. JavaScript는 이러한 변환 작업을 <code>if</code> 문 (아래를 보세요)과 같이 부울값이 필요한 경우를 만나게되면 자동으로 사용자가 모르는 사이에 처리해버리기 때문입니다. 이러한 이유로 인해 우리는 가끔 부울 타입으로 변환되었을 때, <code>true</code>와 <code>false</code>이 됨을 의미하는 값들을 각각 "참 값"과 "거짓 값"으로 부를 것입니다. 또는 각각 "참으로 취급되다"와 "거짓으로 취급되다"라는 식으로 불릴 수도 있습니다.</p>
<p>부울 연산자는 <code>&&</code> (논리적<em>와, 그리고</em> ), <code>||</code> (논리적<em>또는</em> ), 그리고 <code>!</code> (논리적<em>부정</em> )이 지원됩니다. 아래에서 다시 언급하겠습니다.</p>
<h2 id=".EB.B3.80.EC.88.98_.28Variables.29" name=".EB.B3.80.EC.88.98_.28Variables.29">변수 (Variables)</h2>
<p>JavaScript에서 새로운 변수는 <code><a href="/ko/docs/Web/JavaScript/Reference/Statements/let">let</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Statements/const">const</a></code>, <code><a href="/ko/docs/Web/HTML/Element/var">var</a></code> 키워드로 선언됩니다.</p>
<p><code>let</code>을 사용하면 블록 유효 범위 변수를 선언 할 수 있습니다. 선언 된 변수는 <em>변수가 포함 된 함수 블록</em>에서 사용할 수 있습니다.</p>
<pre class="brush: js notranslate">let a;
let name = 'Simon';</pre>
<p>아래는 let으로 선언한 변수가 가지는 유효 범위의 예제입니다. </p>
<pre class="brush: js notranslate">// myLetVariable는 여기에서 보이지 *않습니다*
for (let myLetVariable = 0; myLetVariable < 5; myLetVariable++) {
// myLetVariable는 여기에서 유효합니다
}
// myLetVariable는 여기에서 보이지 *않습니다*</pre>
<p><code>const</code>는 값이 변경되지 않는 변수를 선언 할 수 있게 합니다. 변수는 <em>변수가 선언 된 함수 블록</em>에서 사용할 수 있습니다.</p>
<pre class="brush: js notranslate">const Pi = 3.14; // 변수 Pi 설정
Pi = 1; // 상수로 설정된 변수는 변경 할 수 없기 때문에 애러 발생.</pre>
<p><code>var</code>은 가장 일반적인 변수 선언 키워드입니다. <code>let</code>, <code>const</code> 키워드가 가지는 제한을 <code>var</code>은 갖지 않습니다. 이는 자바스크립트에서 변수를 선언하는 전통적인 유일한 방법이었기 때문입니다. <code>var</code> 키워드로 선언 된 변수는 <em>변수가 선언 된 함수 블록</em>에서 사용 할 수 있습니다.</p>
<pre class="brush: js notranslate">var a;
var name = 'Simon';</pre>
<p>var로 선언한 변수의 유효 범위 예제입니다.</p>
<pre class="brush: js notranslate">// myVarVariable는 여기에서 사용 할 수 *있습니다*
for (var myVarVariable = 0; myVarVariable < 5; myVarVariable++) {
// myVarVariable는 함수 전체에서 사용 할 수 있습니다.
}
// myVarVariable는 여기에서 사용 할 수 *있습니다*</pre>
<p>변수에 값을 지정하지 않고 변수를 선언하면, 타입은 <code>undefined</code>로 지정 됩니다.</p>
<p>자바스크립트와 자바 같은 다른 언어 사이의 중요한 차이점은 자바스크립트는 블록에 범위가 없다는 것입니다. 함수에만 범위가 있습니다. 변수가 복합 문에서 (예를 들어 <code>if</code> 제어 구조 내에서) var를 사용하여 정의 된 경우 전체 함수에서 볼 수 있습니다. 그러나 ECMAScript 2015부터 <code><a href="/ko/docs/Web/JavaScript/Reference/Statements/let">let</a></code> 및 <code><a href="/ko/docs/Web/JavaScript/Reference/Statements/const">const</a></code> 선언을 사용하면 블록 범위 변수를 만들 수 있습니다.</p>
<h2 id=".EC.97.B0.EC.82.B0.EC.9E.90_.28Operators.29" name=".EC.97.B0.EC.82.B0.EC.9E.90_.28Operators.29">연산자 (Operators)</h2>
<p>JavaScript의 산술 연산자로는 <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>%</code>(나머지 연산자)가 있습니다. 값은 <code>=</code> 연산자로 할당할 수 있고, <code>+=</code> 와 <code>-=</code>처럼 다른 연산자를 같이사용해서 할당할 수 있습니다. 이렇게 쓰인 연산자는 <code>x = x<em>연산자</em> y</code>와 같은 결과를 나타냅니다.</p>
<pre class="brush: js notranslate">x += 5;
x = x + 5;
</pre>
<p><code>++</code> 와 <code>--</code> 를 각각 점진적인 증가와 감소에 사용할 수 있습니다. 이들은 또한 전처리 또는 후처리 연산자로 사용될 수 있습니다.</p>
<p><a href="ko/Core_JavaScript_1.5_Reference/Operators/String_Operators"><code>+</code> 연산자</a>는 문자열 이어붙이기도 합니다:</p>
<pre class="brush: js notranslate">'hello' + ' world'; // "hello world"
</pre>
<p>문자열에 어떤 수 (또는 다른 값)를 더하면 일단 모두 문자열로 바뀌게 됩니다. 다음 예를 보시면 무슨 말씀인지 아실 수 있을겁니다:</p>
<pre class="brush: js notranslate">'3' + 4 + 5; // "345"
3 + 4 + '5'; // "75"</pre>
<p>빈 문자열에 어떤 값을 더하는 것은 해당 값을 문자열로 바꾸는 요령입니다.</p>
<p>JavaScript에서 <a href="ko/Core_JavaScript_1.5_Reference/Operators/Comparison_Operators">비교</a>는 <code><</code>, <code>></code>, <code><=</code> 와 <code>>=</code> 를 통해 가능합니다. 이 연산자들은 문자열과 수 양쪽 모두에서 동작합니다. 상동은 약간 직관성이 떨어지는데 이중 등호 (<code>==</code>) 연산자는 서로 다른 타입을 줄 경우 타입 강제 변환을 수행하기 때문에 다음과 같이 때때로 기대하지 않은 결과를 내보내기 때문입니다:</p>
<pre class="brush: js notranslate">123 == '123'; // true
1 == true; // true
</pre>
<p>타입 강제 변환을 하지 않게 하려면, 삼중 등호 연산자 (<code>===</code>)를 사용해야합니다:</p>
<pre class="brush: js notranslate">123 === '123'; // false
1 === true; // false
</pre>
<p>이와 비슷하게 <code>!=</code> 와 <code>!==</code> 연산자가 있습니다.</p>
<p>JavaScript는 값을 <a href="ko/Core_JavaScript_1.5_Reference/Operators/Bitwise_Operators">비트로 취급하는 연산자</a>도 가지고 있습니다. 사용하고 싶을 때 언제라도 사용할 수 있도록 말이죠.</p>
<h2 id=".EC.A0.9C.EC.96.B4_.EA.B5.AC.EC.A1.B0" name=".EC.A0.9C.EC.96.B4_.EA.B5.AC.EC.A1.B0">제어 구조</h2>
<p>JavaScript는 C 계열의 다른 언어들과 비슷한 제어 구조를 가지고 있습니다. 조건문은 <code>if</code> 와 <code>else</code>를 지원하는데, 원하시는대로 얼마든지 중첩 시켜서 사용할 수 있습니다:</p>
<pre class="brush: js notranslate">var name = 'kittens';
if (name == 'puppies') {
name += ' woof';
} else if (name == 'kittens') {
name += ' meow';
} else {
name += '!';
}
name == 'kittens meow';
</pre>
<p>JavaScript는 <code>while</code> 반복문과 <code>do-while</code> 반복문도 사용할 수 있습니다. 첫번째 것은 단순 반복에 유용하게 사용할 수 있고, 두번째 것은 반복문이 반드시 적어도 한번이상 실행 되도록 하고 싶을 때 사용할 수 있습니다:</p>
<pre class="brush: js notranslate">while (true) {
// 무한루프!
}
var input;
do {
input = get_input();
} while (inputIsNotValid(input));
</pre>
<p>JavaScript의 <code>for</code> 반복문은 C 와 Java의 반복문과 같습니다. 말하자면, 반복문에 필요한 제어 정보를 한 줄에 표현할 수 있다는 이야기지요.</p>
<pre class="brush: js notranslate">for (var i = 0; i < 5; i++) {
// 내부 동작을 5번 반복합니다
}
</pre>
<p>JavaScript에는 두개의 중요한 for 반복문 또한 포함됩니다. 첫번째로 <a href="/ko/docs/Web/JavaScript/Reference/Statements/for...of">for...of</a> 입니다.</p>
<pre class="brush: js notranslate">for (let value of array) {
// value로 작업을 실행합니다
}
</pre>
<p>그리고 <a href="/ko/docs/Web/JavaScript/Reference/Statements/for...in">for ... in</a> 입니다.</p>
<pre class="brush: js notranslate">for (let property in object) {
// object의 항목(property)으로 작업을 실행합니다
}
</pre>
<p><code>&&</code> 와 <code>||</code> 연산자는 첫번째 식을 평가한 결과에 따라서 두번째 식을 평가를 실행하는 단축평가(short-circuit) 논리를 사용합니다. 이는 다음과 같이 객체에 접근하기 전에 null 객체인지, 아닌지를 검사하는데 유용하게 사용될 수 있습니다:</p>
<pre class="brush: js notranslate">var name = o && o.getName();
</pre>
<p>또는 (틀린값이 유효하지 않은 값일때) 캐싱 값에 대해서도 사용합니다.:</p>
<pre class="brush: js notranslate">var name = cachedName || (cachedName = getName());
</pre>
<p>JavaScript는 한줄로 조건문을 쓸 수 있게 해주는 삼중 연산자도 가지고 있습니다:</p>
<pre class="brush: js notranslate">var allowed = (age > 18) ? "yes" : "no";
</pre>
<p><code>switch</code> 문은 숫자나 문자열을 기반으로 다중 분기되는 문장을 작성하는데 사용될 수 있습니다:</p>
<pre class="brush: js notranslate">switch(action) {
case 'draw':
drawIt();
break;
case 'eat':
eatIt();
break;
default:
doNothing();
}
</pre>
<p><code>break</code> 문장을 추가하지 않았다면, 다음 단계로 "넘어가서" 실행합니다. 이렇게 되는 것을 기대하는 것은 매우 드문경우 입니다. 실은 디버깅하는데 용이하도록 하기위해 주석으로서 일부러 붙여놓은 넘어가기 이름표 입니다:</p>
<pre class="brush: js notranslate">switch(a) {
case 1: // fallthrough
case 2:
eatIt();
break;
default:
doNothing();
}
</pre>
<p>default 구문의 적용은 선택사항입니다. switch와 case 부분에서 둘다 표현식을 사용할 수도 있습니다. switch부분과 case 부분의 표현식은 <code>===</code> 연산자로 비교됩니다.</p>
<pre class="brush: js notranslate">switch(1 + 3){
case 2 + 2:
yay();
break;
default:
neverhappens();
}
</pre>
<h2 id=".EA.B0.9D.EC.B2.B4_.28Objects.29" name=".EA.B0.9D.EC.B2.B4_.28Objects.29">객체 (Objects)</h2>
<p>JavaScript 객체는 간단히 이름-값 쌍(name-value pairs)의 모임입니다. 그렇기 때문에, JavaScript의 객체의 모임은 다음과 비슷하다고 할 수 있습니다:</p>
<ul>
<li>Python의 Dictionaries</li>
<li>Perl 과 Ruby의 Hashes</li>
<li>C 와 C++ 의 Hash tables</li>
<li>Java 의 HashMaps</li>
<li>PHP의 Associative arrays</li>
</ul>
<p>이 데이터 구조가 매우 광범위하게 사용된다는 사실은 활용 방도가 다양함을 입증합니다. JavaScript내 모든 것 (코어 타입들은 제외)은 객체로 취급되기 때문에 어떤 JavaScript 프로그램도 기본적으로 해쉬 테이블을 검색하는데 필요한 출중한 성능을 가지고 있습니다. 매우 빠르기 때문에 장점이 됩니다!</p>
<p>값은 객체를 포함하여 아무 JavaScript 값이 될 수 있는 반면, "이름" 부분은 JavaScript 문자열 입니다. 이는 무작위적인 복잡성을 가지는 데이터 구조를 만들 수 있도록 해줍니다.</p>
<p>빈 객체를 생성하는데 두가지 방법이 있습니다:</p>
<pre class="brush: js notranslate">var obj = new Object();
</pre>
<p>와:</p>
<pre class="brush: js notranslate">var obj = {};
</pre>
<p>이들은 의미적으로 동치입니다. 두번째 방법은 객체 리터럴 구문이라고 부르며 더 편리합니다. 객체 리터럴 구문은 JSON 구문의 핵심이며 이 방법을 사용한 코드를 더 많이 볼 수 있습니다.</p>
<p>객체 리터럴 구문으로 객체의 전체적인 구조를 초기화 할 수 있습니다:</p>
<pre class="brush: js notranslate">var obj = {
name: "Carrot",
"for": "Max",
details: {
color: "orange",
size: 12
}
}
</pre>
<p>속성에 연속적으로 접근할 수 있습니다:</p>
<pre class="brush: js notranslate">obj.details.color; // orange
obj["details"]["size"]; // 12
</pre>
<p>아래 예제는 객체 프로토타입(<code>Person</code>)과 프로토타입의 인스턴스(<code>you</code>)를 생성합니다.</p>
<pre class="brush: js notranslate">function Person(name, age) {
this.name = name;
this.age = age;
}
// 객체를 정의한다
var you = new Person('You', 24);
// "You"라는 이름의 24세인 새로운 사람을 생성중이다.
</pre>
<p><strong>일단 생성되면</strong>, 객체의 속성에 다음의 두가지 방법들 중 한가지로 접근할 수 있습니다:</p>
<pre class="brush: js notranslate">// dot 표기법
obj.name = "Simon"
var name = obj.name;
</pre>
<p>그리고...</p>
<pre class="brush: js notranslate">// bracket 표기법
obj["name"] = "Simon";
var name = obj["name"];
// key를 정의하기 위해 변수도 쓸수 있습니다.
var user = prompt('what is your key?')
obj[user] = prompt('what is its value?')
</pre>
<p>이들은 의미적으로 역시 같습니다. 두번째 방법은 속성의 이름이 실행시간(run-time)에 계산될 수 있는 문자열로 주어집니다. 하지만 이방법을 사용하면 일부 JavaScript엔진과 압축기 최적화(minifier optimizations)를 적용할수 없습니다.또한 <a href="ko/Core_JavaScript_1.5_Reference/Reserved_Words">예약된 단어(키워드)</a>로 되어있는 이름으로 객체의 속성을 설정하거나 얻어낼 수 있습니다:</p>
<pre class="brush: js notranslate">obj.for = "Simon"; // 구문 오류, for 가 예약된 단어(키워드)이기 때문에
obj["for"] = "Simon"; // 정상 동작
</pre>
<div class="blockIndicator note">
<p>ECMAScript 5 이래로, 예약어는 객체 항목의 이름으로 "덧붙임없이" 사용할수도 있습니다. 이말은 객체 리터럴을 정의할때 따옴표로 "둘러쌀" 필요가 없다는 의미입니다. ES5 <a href="http://es5.github.io/#x7.6.1">Spec</a>을 참고해 보십시오.</p>
</div>
<p>객체나 프로토타입에 대한 좀더 상세한 내용은 <a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype">Object.prototype</a> 을 참조하십시오. 객체 프로토타입과 객체 프로토타입 체인에 대한 설명은 <a href="/ko/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">상속과 프로토타입 체인</a> 을 참조하십시오.</p>
<div class="blockIndicator note">
<p>ECMAScript 2015 이래로, 객체의 key는 생성시의 대괄호 표기법(bracket notation)으로 정의될수 있습니다. 그냥 <code>var userPhone = {}; userPhone[phoneType] = 12345</code>. 처럼 표기하는 방법 대신 <code>{[phoneType]: 12345}</code> 와 같은 사용법도 가능합니다.</p>
</div>
<h2 id=".EB.B0.B0.EC.97.B4_.28Arrays.29" name=".EB.B0.B0.EC.97.B4_.28Arrays.29">배열 (Arrays)</h2>
<p>JavaScript에서 배열은 실제로는 특별한 타입의 객체입니다. (숫자로 나타낸 속성은 자연스럽게 [] 구문만을 사용해서 접근하게 되므로) 일반 객체와 많이 비슷하게 동작하지만, 이 객체는 '<code>length</code>'라는 한가지 마법적인 속성을 가집니다. 이는 항상 배열에서 가장 큰 인덱스보다 하나 더 큰 값으로 존재합니다.</p>
<p>배열을 생성하는 예전 방법은 다음과 같습니다:</p>
<pre class="brush: js notranslate">var a = new Array();
a[0] = "dog";
a[1] = "cat";
a[2] = "hen";
a.length // 3
</pre>
<p>한가지 더 편리한 배열 표현 방법은 배열 리터럴을 사용하는 것입니다:</p>
<pre class="brush: js notranslate">> var a = ["dog", "cat", "hen"];
> a.length
3
</pre>
<p>배열 리터럴 끝에 콤마(",")를 꼬리로 남겨두는 것은 브라우저마다 다르게 처리하므로 그렇게 하지는 마시기 바랍니다.</p>
<p><code>array.length</code> 는 배열에 들어있는 항목의 수를 반드시 반영하지는 않는다는 점을 주의하시기 바랍니다. 다음과 같은 경우를 고려해보겠습니다:</p>
<pre class="brush: js notranslate">> var a = ["dog", "cat", "hen"];
> a[100] = "fox";
> a.length
101
</pre>
<p>기억해두세요 - 배열의 length 속성은 최대 인덱스에 하나를 더한 값일 뿐입니다.</p>
<p>존재하지 않는 배열 인덱스를 참조하려고하면 다음과 같이 <code>undefined</code> 을 얻게됩니다:</p>
<pre class="brush: js notranslate">> typeof(a[90])
undefined
</pre>
<p><code>[]</code> 와 <code>length</code>에 관한 위의 사항들을 감안하면 배열을 <code>for</code> 반복문으로 처리할 때 다음과 같은 방법으로 처리하실 수 있을 것입니다:</p>
<pre class="brush: js notranslate">for (var i = 0; i < a.length; i++) {
// a[i] 로 뭔가를 수행
}
</pre>
<p>ES2015는 배열과 같은 이터러블 객체를 위해 좀더 간결한 for...of 루프를 소개했습니다.</p>
<pre class="brush: js notranslate">for (const currentValue of a) {
// currentValue 로 뭔가를 수행
}</pre>
<p>또한 for...in 루프를 이용하여 배열에 루프를 돌릴수도 있지만, 이 방법은 배열 요소를 반복하는게 아니라 배열 인덱스를 반복합니다. 뿐만 아니라, 누군가 <code>Array.prototype</code>에 새로운 속성을 추가하면, 그 속성들 또한 이런 루프로 반복됩니다. 따라서 이런 반복 형태는 배열에는 추천되지 않습니다.</p>
<p>배열에 대한 또다른 반복방법은 ECMAScript 5에 추가된 <a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach">forEach()</a> 입니다:</p>
<pre class="brush: js notranslate">['dog', 'cat', 'hen'].forEach(function(currentValue, index, array) {
// currentValue나 array[index]로 뭔가를 수행
}
</pre>
<p>배열에 항목 하나를 추가하길 원한다면 이렇게 하면 됩니다:</p>
<pre class="brush: js notranslate">a.push(item);</pre>
<p>배열은 몇가지 메서드가 제공됩니다. <a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Array">배열 메서드에 대한 전체 문서</a>를 참조하십시오.</p>
<table>
<thead>
<tr>
<th scope="col">메서드 이름</th>
<th scope="col">설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>a.toString()</code></td>
<td>각 항목에 대한 <code>toString()</code>의 출력이 콤마로 구분된 한개의 문자열을 반환합니다.</td>
</tr>
<tr>
<td><code>a.toLocaleString()</code></td>
<td>각 항목에 대한 <code>toLocaleString()</code>의 출력이 콤마로 구분된 한개의 문자열을 반환합니다.</td>
</tr>
<tr>
<td><code>a.concat(item1[, item2[, ...[, itemN]]])</code></td>
<td>item들이 덧붙여진 한개의 배열을 반환합니다.</td>
</tr>
<tr>
<td><code>a.join(sep)</code></td>
<td>배열의 값들을 <code>sep</code> 인자로 구분하여 합친 한개의 문자열로 변환합니다.</td>
</tr>
<tr>
<td><code>a.pop()</code></td>
<td>배열의 마지막 항목을 반환하면서 제거합니다.</td>
</tr>
<tr>
<td><code>a.push(item1, ..., itemN)</code></td>
<td>배열의 끝에 item들을 덧붙입니다.</td>
</tr>
<tr>
<td><code>a.shift()</code></td>
<td>배열의 첫번째 항목을 반환하면서 제거합니다.</td>
</tr>
<tr>
<td><code>a.unshift(item1[, item2[, ...[, itemN]]])</code></td>
<td>배열의 앞쪽에 item들을 덧붙입니다.</td>
</tr>
<tr>
<td><code>a.slice(start[, end])</code></td>
<td>배열의 일부분을 새배열로 반환합니다.</td>
</tr>
<tr>
<td><code>a.sort([cmpfn])</code></td>
<td>옵션으로 비교용도의 함수를 입력받습니다.</td>
</tr>
<tr>
<td><code>a.splice(start, delcount[, item1[, ...[, itemN]]])</code></td>
<td>배열의 일부분을 제거하고 다른 항목으로 대체하여 배열을 변경합니다..</td>
</tr>
<tr>
<td><code>a.reverse()</code></td>
<td>배열의 순서를 거꾸로 배열합니다.</td>
</tr>
</tbody>
</table>
<h2 id=".ED.95.A8.EC.88.98_.28Functions.29" name=".ED.95.A8.EC.88.98_.28Functions.29">함수 (Functions)</h2>
<p>객체와 마찬가지로, 함수는 JavaScript를 이해하는데 핵심이 되는 컴포넌트입니다. 가장 기본적인 함수의 예는 다음과 같습니다:</p>
<pre class="brush: js notranslate">function add(x, y) {
var total = x + y;
return total;
}
</pre>
<p>이 예는 기본 함수에 대해 알아야 할 모든 것을 보여주고 있습니다. JavaScript 함수는 0 이상의 이름이 있는 매개변수를 가질 수 있습니다. 함수의 본체는 갯수 제한없이 구문을 포함할 수 있고 해당 함수에 지역적으로 변수를 보유하도록 선언할 수 있습니다. <code>return</code> 문은 언제나 값을 돌려주고 함수의 실행을 끝내는데 사용될 수 있습니다. 리턴 문이 없으면 (혹은 값이 없는 리턴이 사용되면), JavaScript는 <code>undefined</code>을 돌려줍니다.</p>
<p>이름 붙여진 매개변수들은 다른 어떤 것보다도 해당 함수가 어떤 함수인지 설명해주는 좋은 역할을 할 수 있습니다. 해당 함수가 원하는 매개변수를 주지않고 함수를 호출할 수 있지만 그럴 경우 해당 변수들은 <code>undefined</code>로 설정됩니다.</p>
<pre class="brush: js notranslate">add(); //NaN
// undefined에 대해 덧셈을 수행할 수 없습니다
</pre>
<p>함수가 기대하는 원래의 매개변수보다 많은 매개변수를 넘겨줄 수도 있습니다:</p>
<pre class="brush: js notranslate">add(2, 3, 4); // 5
// 처음의 두 수가 더해집니다. 4는 무시됨
</pre>
<p>이 예는 조금 어리석어 보이지만, 함수는 추가적으로 주어진 매개변수를 함수 내부에서 접근할수 있습니다. 이 객체는 <a href="ko/Core_JavaScript_1.5_Reference/Functions/arguments"><code>arguments</code></a>라고 하며, 해당 함수에 매개변수로 넘겨진 모든 값을 가지고 있는 배열과 비슷한 객체입니다. 우리가 원하는만큼 값을 취하는 add 함수를 다시 써보겠습니다:</p>
<pre class="brush: js notranslate">function add() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum;
}
add(2, 3, 4, 5); // 14
</pre>
<p>확실히 <code>2 + 3 + 4 + 5</code>를 직접쓰는 것보다 유용한 함수는아닙니다. 평균계산 함수를 만들어 보겠습니다:</p>
<pre class="brush: js notranslate">function avg() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum / arguments.length;
}
avg(2, 3, 4, 5); // 3.5
</pre>
<p>이건 매우 유용합니다만, 좀 번잡해보입니다. 코드 크기를 다소 줄이기 위해, arguments 배열의 사용을 <a href="/ko/docs/Web/JavaScript/Reference/Functions/rest_parameters">Rest 파라미터 문법</a>으로 대체해볼 필요가 있습니다. 이 방법으로, 코드 크기는 최소한으로 유지 하면서, 갯수 제한없이 함수로 인자를 전달할수 있습니다. <strong>Rest 파라미터 연산자</strong>는 다음과 같은 포맷(<strong>...variable</strong>)으로 함수 파라미터 목록에 사용됩니다. 이 varaible 인자는 함수가 호출될때 전달되는 모든 인자를 포함합니다. variable 인자에서 반환되는 값을 사용하기 위해 위 코드에서 <strong>for</strong> 루프를 <strong>for..of</strong> 루프로 변경합니다.</p>
<pre class="brush: js notranslate">function avg(...args) {
var sum = 0;
for (let value of args) {
sum += value;
}
return sum / arr.length;
}
avg(2, 3, 4, 5); // 3.5
</pre>
<div class="blockIndicator note">
<p>위 코드에서,변수 <strong>args</strong> 는 함수로 전달된 모든 값을 가지고 있습니다.<br>
<br>
rest 파라미터 연산자가 함수 선언의 어느곳에 위치하든 선언 위치<em> 이후</em>에 모든 인자를 저장하는것이며, 이전이 아니라는 것이 중요합니다. 즉 ,<em> function</em> <em>avg(</em><strong>firstValue, </strong><em>...args)</em><strong> </strong>에서 함수로 전달된 첫번째 값은 <strong>firstValue </strong>변수에 저장되며, 남은 변수들은 <strong>args</strong>에 저장됩니다.</p>
</div>
<p>이건 또다른 유용한 언어 특성입니다만 우리를 새로운 문제점으로 인도합니다. <code>avg()</code> 함수는 콤마로 구분된 인자목록을 받지만, 배열의 평균을 알고싶은 경우라면요? 함수를 다음과 같이 재작성 하면 됩니다 :</p>
<pre class="notranslate">function avgArray(arr) {
var sum = 0;
for (var i = 0, j = arr.length; i < j; i++) {
sum += arr[i];
}
return sum / arr.length;
}
avgArray([2, 3, 4, 5]); // 3.5</pre>
<p>하지만 우리가 이미 만든 함수를 다시 사용할 수 있다면 좋을 것입니다. 운이 좋게도 JavaScript는 함수 객체라면 모두 가지게 되는 <a href="ko/Core_JavaScript_1.5_Reference/Global_Objects/Function/apply"><code>apply()</code></a> 메소드를 사용해서 임의의 매개변수 배열을 함수에 넘겨줄 수 있습니다.</p>
<pre class="brush: js notranslate">> avg.apply(null, [2, 3, 4, 5])
3.5
</pre>
<p><code>apply()의 </code>두번째 매개변수는 '매개변수들'로 사용하고자 하는 배열입니다. 첫번째 매개변수는 나중에 설명하도록 하겠습니다. 이는 함수가 역시 객체임을 명확히 해주는 사실입니다.</p>
<div class="blockIndicator note">
<p>함수 호출시 <a href="/ko/docs/Web/JavaScript/Reference/Operators/Spread_operator">전개 연산자(spread operator)</a> 를 이용하여 똑같은 결과를 얻을수 있습니다.</p>
<p>예를 들면: <code>avg(...numbers)</code></p>
</div>
<p>JavaScript는 익명의 함수를 만들 수 있도록 허용하고 있습니다.</p>
<pre class="brush: js notranslate">var avg = function() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum / arguments.length;
}
</pre>
<p>이것은 의미적으로 <code>function avg()</code> 형식과 같습니다. 이 특징은 매우 강력한데, 일반적인 표현식(expression)을 사용할 수있는 어디에서나 완전한 함수 정의를 넣을 수 있도록 허용하는 것이기 때문입니다. 이 특징은 다양한 요령을 부릴 수 있게합니다. 다음 예는 C에서 블록 유효 범위를 적용 시킨 것 처럼 지역 변수를 "숨기는" 요령을 보여줍니다:</p>
<pre class="brush: js notranslate">var a = 1;
var b = 2;
(function() {
var b = 3;
a += b;
})();
a; // 4
b; // 2
</pre>
<p>JavaScript는 재귀적으로 함수를 부를 수 있습니다. 이는 브라우저 DOM 등에서 볼수 있는 트리 구조를 다루는데 유용합니다.</p>
<pre class="brush: js notranslate">function countChars(elm) {
if (elm.nodeType == 3) { // TEXT_NODE
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++) {
count += countChars(child);
}
return count;
}
</pre>
<p>다음의 예는 익명 함수를 사용함에 있어 잠재적인 문제점을 보여줍니다: 이름이 없으면 어떻게 재귀적으로 부를 수 있을까요? JavaScript는 함수 표현식을 이렇게 이름붙이도록 지원합니다. 이름붙은 IIFEs (Immediately Invoked Function Expressions: 즉시 실행 함수 표현) 를 다음과 같이 사용할 수 있습니다:</p>
<pre class="brush: js notranslate">var charsInBody = (function counter(elm) {
if (elm.nodeType == 3) { // TEXT_NODE
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++) {
count += counter(child);
}
return count;
})(document.body);
</pre>
<p>위와 같이 함수 표현식에 제공된 이름은 함수 자체 범위에서만 유효합니다. 이 특징은 엔진에 의한 최적화뿐만 아니라 코드 가독성을 높이는데 도움을 줍니다. 이 이름은 디버거와 스택 추적에서도 나타나므로 디버깅시간을 줄일수 있게합니다.</p>
<p>JavaScript 함수는 - JavsScript 내의 다른 모든 것들과 마찬가지로 - 그 자체가 객체이며, 객체 섹션에서 이미 확인한 것처럼, 속성을 추가하거나 변경할수 있다는 점을 명심하십시오</p>
<h2 id=".EC.82.AC.EC.9A.A9.EC.9E.90_.EC.A0.95.EC.9D.98_.EA.B0.9D.EC.B2.B4" name=".EC.82.AC.EC.9A.A9.EC.9E.90_.EC.A0.95.EC.9D.98_.EA.B0.9D.EC.B2.B4">사용자 정의 객체</h2>
<div class="blockIndicator note">
<p>JavaScript에서 객체 지향 프로그래밍에 대한 더 자세한 논의는 <a href="/ko/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript">객체 지향 JavaScript 소개</a>를 참조하십시오.</p>
</div>
<p>고전 객체지향 프로그래밍에서 객체는 데이터와 해당 데이터들을 다루는 메소드의 집합이었습니다. JavaScript는 프로토타입 기반 언어로, C++ 이나 Java에서 발견할 수 있는 class 구문이 없습니다(이런 이유로 class 구문에 익숙한 프로그래머들이 때때로 혼란을 경험합니다). 그 대신, JavaScrip는 function을 class로 사용합니다. 이름과 성을 필드로 가지고 있는 'person' 객체를 고려해보도록 합시다. 이름을 표시하는 두가지 방법이 있을 수 있습니다. 예를 들어, "이름 성" 또는 "성, 이름" 이런 식으로 말이죠. 이전에 다룬 함수와 객체를 사용해서 이를 표현하면 다음과 같습니다:</p>
<pre class="brush: js notranslate">function makePerson(first, last) {
return {
first: first,
last: last
}
}
function personFullName(person) {
return person.first + ' ' + person.last;
}
function personFullNameReversed(person) {
return person.last + ', ' + person.first
}
var s = makePerson("Simon", "Willison");
personFullName(s); // "Simon Willison"
personFullNameReversed(s); // "Willison, Simon"
</pre>
<p>이렇게 하면 작동하긴 하지만, 보기 안좋습니다. 이런 방법이라면 전역 이름공간(global namespace)에 관련 함수가 너무 많아집니다. 정말 우리에게 필요한 것은 객체에 함수를 붙여놓는 것입니다. 함수는 객체이기 때문에 이건 별로 어렵지 않습니다.</p>
<pre class="brush: js notranslate">function makePerson(first, last) {
return {
first: first,
last: last,
fullName: function() {
return this.first + ' ' + this.last;
},
fullNameReversed: function() {
return this.last + ', ' + this.first;
}
};
}
var s = makePerson('Simon', 'Willison');
s.fullName(); // "Simon Willison"
s.fullNameReversed(); // "Willison, Simon"
</pre>
<p><code><a href="ko/Core_JavaScript_1.5_Reference/Operators/Special_Operators/this_Operator">this</a></code> 키워드에 주목해 주십시오. 함수 안쪽에서 사용되면서, <code>this</code>는 현재 객체를 참조합니다. 그것이 실제로 의미하는 바는 당신이 부른 바로 그 함수를 지정하는 것입니다. 객체에서 <a href="ko/Core_JavaScript_1.5_Reference/Operators/Member_Operators">dot 표기법이나 bracket 표기법</a>을 사용해서 부른 경우, 해당 객체는 <code>this</code>가 됩니다. 해당 호출에서 dot 표기법을 사용하지 않은 경우, <code>this</code>는 전역 객체를 참조하게 됩니다.</p>
<p><code>this</code>가 실수의 잦은 원인이 된다는 것을 명심하십시오 . 예를 들면:</p>
<pre class="brush: js notranslate">var s = makePerson('Simon', 'Willison');
var fullName = s.fullName;
fullName(); // undefined undefined
</pre>
<p><code>s.fullName()</code>을 이용하지 않고 <code>fullName()</code>을 단독으로 호출하면, '<code>this</code>'는 전역 객체로 묶이게(bind) 됩니다. <code>first</code> 또는 <code>last</code> 로 명명된 전역 변수가 없기 때문에, 각각에 대해 <code>undefined</code> 결과를 얻게됩니다.</p>
<p><code>makePerson</code> 함수를 개선하는데 '<code>this</code>' 키워드의 이점을 취할 수 있습니다:</p>
<pre class="brush: js notranslate">function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = function() {
return this.first + ' ' + this.last;
};
this.fullNameReversed = function() {
return this.last + ', ' + this.first;
};
}
var s = new Person('Simon', 'Willison');
</pre>
<p>여기서 <code><a href="ko/Core_JavaScript_1.5_Reference/Operators/Special_Operators/new_Operator">new</a></code>라는 또다른 키워드를 도입했습니다. <code>new</code>는 <code>this</code>와 깊게 연관되어 있습니다. 새로운 빈 객체를 만든 다음 지정된 함수를 불러 새로운 객체를 <code>this</code> 에 설정합니다. <code>this</code>로 지정된 함수는 값을 반환하지 않고 단지 <code>this</code> 객체를 수정한다는 것을 명심하세요. <code>this</code> 객체를 호출하는 곳으로 반환하는 것은 <code>new</code> 입니다. '<code>new</code>' 에 의해 호출되도록 설계된 함수는 컨스트럭터 함수라고 불립니다. 일반적으로 이러한 함수의 첫자를 대문자로 써서 <code>new</code>로 불릴 컨스트럭터 함수임을 나타냅니다.</p>
<p>개선된 함수는 여전히 <code>fullName()</code> 을 단독으로 호출할 때의 함정이 존재합니다.</p>
<p>우리의 person 객체가 점점 개선되고 있지만, 아직 좀 보기 안좋은 면이 있습니다. 매번 person 계열의 객체를 만들 때마다 내부에서 2개의 새로운 함수 객체를 만들고 있습니다. 이 코드가 객체간에 공유된다면 더 낫지 않을까요?</p>
<pre class="brush: js notranslate">function personFullName() {
return this.first + ' ' + this.last;
}
function personFullNameReversed() {
return this.last + ', ' + this.first;
}
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = personFullName;
this.fullNameReversed = personFullNameReversed;
}
</pre>
<p>더 좋아 보이네요: 메소드 함수를 한번만 만들고, 컨스트럭터 내에 해당 메소드들을 참조하도록 할당합니다. 이보다 더 개선 할 수 있을까요? 네, 그렇게 할 수 있습니다:</p>
<pre class="brush: js notranslate">function Person(first, last) {
this.first = first;
this.last = last;
}
Person.prototype.fullName = function() {
return this.first + ' ' + this.last;
};
Person.prototype.fullNameReversed = function() {
return this.last + ', ' + this.first;
};
</pre>
<p><code>Person.prototype</code>은 모든 <code>Person</code> 인스턴스들간에 공유되는 객체입니다. 이는 lookup(찾아보기) 체인의 한 부분을 이룹니다. (이건 "prototype chain"이라는 특수한 이름을 따로 가지고 있습니다) 다시 말해, <code>Person</code> 객체의 설정되지 않은 속성에 접근을 시도할 때마다, 그것의 대체용도로 JavaScript는 <code>Person.prototype</code>에 그 속성이 존재하는지 살펴봅니다.그 결과, <code>Person.prototype</code>에 할당된 모든 것은 <code>this</code> 객체를 통해 해당 컨스트럭터에 속한 모든 인스턴스들간에 사용 가능하게 됩니다.</p>
<p>이것은 정말 강력한 도구입니다. JavaScript에서는 임의의 prototype을 프로그램 내에서 언제든 변형할 수 있습니다. 이미 존재하는 객체에 추가적인 메소드를 실시간으로 추가가할 수 있다는 이야기입니다:</p>
<pre class="brush: js notranslate">var s = new Person("Simon", "Willison");
s.firstNameCaps(); //TypeError on line 1: s.firstNameCaps is not a function
Person.prototype.firstNameCaps = function() {
return this.first.toUpperCase()
};
s.firstNameCaps(); // "SIMON"
</pre>
<p>흥미롭게도, JavaScript의 빌트인 객체의 prototype에도 뭔가를 더 추가할 수 있습니다. <code>String</code> 객체에 문자열 순서를 거꾸로 배열하여 돌려주는 메소드를 추가해 봅시다.</p>
<pre class="brush: js notranslate">var s = "Simon";
s.reversed(); // TypeError on line 1: s.reversed is not a function
String.prototype.reversed = function() {
var r = "";
for (var i = this.length - 1; i >= 0; i--) {
r += this[i];
}
return r;
};
s.reversed(); // nomiS
</pre>
<p>우리가 추가한 새로운 메소드는 심지어 문자열 상수에서도 동작합니다!</p>
<pre class="brush: js notranslate">"This can now be reversed".reversed(); // desrever eb won nac sihT
</pre>
<p>기존에 언급한 바와같이, prototype은 체인의 한 부분을 이룹니다. 해당 체인의 루트는 <code>Object.prototype</code> 이며 <code>toString()</code> 메소드를 포함합니다. 이 메소드는 객체를 문자열로 나타내려할 때 호출됩니다. 이 메소드는 우리의 <code>Person</code> 객체의 디버깅에 유용합니다:</p>
<pre class="brush: js notranslate">var s = new Person("Simon", "Willison");
s.toString(); // [object Object]
Person.prototype.toString = function() {
return '<Person: ' + this.fullName() + '>';
}
s.toString(); // "<Person: Simon Willison>"
</pre>
<p><code>avg.apply()</code>의 첫번째 매개변수가 null 이었던걸 기억해봅시다. <code>apply()</code>에 적용되는 첫번째 인자는 당연히 `<code>this</code>'로 간주되는 객체입니다. 여기에 <code>new</code> 의 간단한 구현을 보시죠:</p>
<pre class="brush: js notranslate">function trivialNew(constructor, ...args) {
var o = {}; // 빈 객체를 생성
constructor.apply(o, args);
return o;
}
</pre>
<p>이것은 prototype 체인을 설정하지 않으므로 <code>new</code>의 완벽한 대체물이 될 수 없습니다.(이 부분은 설명하기 어렵습니다). 이 내용은 자주 사용하지는 않겠지만 알아두면 좋습니다. 이 부분에서 <code>...args</code> (생략 부호를 포함해서)는 "<a href="/ko/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest arguments</a>" 라고 불립니다. 이름이 암시하는 것처럼 매개변수의 나머지를 포함합니다.</p>
<p>그러므로 이렇게 호출하는 것은</p>
<pre class="notranslate">var bill = trivialNew(Person, 'William', 'Orange');</pre>
<p>아래와 거의 동일합니다.</p>
<pre class="notranslate">var bill = new Person('William', 'Orange');</pre>
<p><code>apply()</code> 와 비슷하게 <code>this</code>를 다시 설정할 수 있게 하는, <a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/call"><code>call</code></a>이라는 이름의 자매 함수가 있는데, 인자로 단일 배열이 아니라 확장된 인자 목록을 입력받습니다.</p>
<pre class="brush: js notranslate">function lastNameCaps() {
return this.last.toUpperCase();
}
var s = new Person('Simon', 'Willison');
lastNameCaps.call(s);
// 위의 구문은 다음과 같습니다:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();
</pre>
<h3 id=".EB.82.B4.EC.9E.A5_.ED.95.A8.EC.88.98" name=".EB.82.B4.EC.9E.A5_.ED.95.A8.EC.88.98">내장 함수 (Inner functions)</h3>
<p>다른 함수의 내부에서 JavaScript 함수를 선언할 수 있습니다. 우리는 <code>makePerson()</code> 함수 초기 버전에서 이것을 한번 본적이 있습니다. JavaScript에서 중첩 함수(nested functions)의 중요한 세부사항은 부모 함수 범위의 변수에 접근할 수 있다는 사실입니다:</p>
<pre class="brush: js notranslate">function parentFunc() {
var a = 1;
function nestedFunc() {
var b = 4; // parentFunc은 사용할 수 없는 변수
return a + b;
}
return nestedFunc(); // 5
}
</pre>
<p>좀 더 유지관리가 쉬운 코드를 작성하고자 할때 이 특성이 굉장히 유용합니다. 한개 혹은 두개의 정도의 함수에서만 호출되며 전체 코드중 다른 부분에서는 사용처가 없는 함수라면 그 함수내에 해당 함수를 중첩시키는 것이 좋습니다. 이렇게 전역 범위 함수의 갯수를 늘리지 않도록 하는 것은 언제나 좋은 습관입니다.</p>
<p>이것은 또한 전역 변수에 대한 유혹을 뿌리칠 수 있는 좋은 대안이 됩니다. 복잡한 코드를 쓸 때, 다양한 함수들간에 값을 공유할 수 있도록 전역 변수를 사용하고 싶어집니다 - 전역 변수는 코드 유지 보수를 어렵게 만듭니다. 중첩 함수는 그 부모 함수의 범위에서 변수를 공유할 수 있으므로, 이 방법을 사용하면 전역 변수 이름공간을 건드리지 않고도 적절한 경우에 함수들을 연동시킬수 있습니다. - '지역 전역'이라고 불러도 괜찮겠네요. 이 기술을 사용할 때는 주의를 요하겠지만, 반드시 알아둬야할 유용한 기술입니다.</p>
<h2 id=".ED.8F.90.ED.8F.AC_.28Closures.29" name=".ED.8F.90.ED.8F.AC_.28Closures.29">클로져 (Closures)</h2>
<p>클로져 (역자주: 글자 그대로 한국어로 해석하면 닫힌 주머니)는 JavaScript가 제공해야만 하는 가장 막강한 추상 개념으로 우리를 이끕니다 - 하지만 동시에 잠재적으로 가장 혼란스럽기도 합니다. 다음 함수는 무엇을 하는 걸까요?</p>
<pre class="brush: js notranslate">function makeAdder(a) {
return function(b) {
return a + b;
};
}
var add5 = makeAdder(5);
var add20 = makeAdder(20);
add5(6); // ?
add20(7); // ?
</pre>
<p><code>makeAdder</code> 함수의 이름은 다음과 같은 과정을 거쳐 반드시 없어집니다: 해당 함수가 한 매개변수를 받아 호출됐을 때, 생성될 때 주어진 매개변수를 더하는 새 'adder' 함수를 생성합니다.</p>
<p>여기서 일어나는 일은 다른 함수의 내에 정의된 어떤 함수가 외부 함수의 변수에 액세스한다는 점에서 앞에 언급한 내장 함수에서 일어나는 일과 매우 비슷합니다. 한가지 다른 점은 외부 함수가 리턴 된다는 점인데, 상식적으로 그것에 들어 있는 변수는 사라진다고 볼 수 있습니다. 하지만 그들은 여전히<em>존재합니다</em> - 그렇지 않으면 adder 함수는 동작하지 않겠지요. 게다가, <code>makeAdder</code> 지역 변수의 서로 다른 두 "복사본"이 존재합니다 - 하나의 <code>a</code>는 5이고, 다른 하나의 <code>a</code>는 20이죠. 따라서 해당 함수를 부른 결과는 다음과 같습니다:</p>
<pre class="brush: js notranslate">x(6) // 11을 돌려줌
y(7) // 27을 돌려줌
</pre>
<p>이건 실제로 일어나는 일입니다. JavaScript 함수가 실행될 때는 언제나, '범위' 객체가 생성되어 해당 함수내에서 생성된 지역 변수를 여기에 저장하고 있습니다. 함수 매개변수로서 넘겨진 어떤 변수라도 여기에 초기값으로 저장하고 있습니다. 이것은 모든 전역 변수와 함수가 들어있는 전역 객체와 비슷하지만, 두가지 중요한 차이점이 있습니다. 첫번째로, 함수가 실행될 때마다 새로운 범위 객체가 생성된다는 점과, 두번째로, (브라우저에서 window로 접근가능한) 전역 객체와 달리 범위 객체는 JavaScript 코드에서 직접적으로 액세스할 수 없다는 점입니다. 예를 들자면 현재 범위 객체의 속성에 반복 접근할 수 있는 수단이 없습니다.</p>
<p>따라서 <code>makeAdder</code> 가 호출되면, 범위 객체는 <code>makeAdder</code> 함수에 매개변수로 넘겨진 하나의 속성 <code>a</code>를 가진 상태로 생성됩니다. 일반적으로 JavaScript의 가비지 컬렉터가 이때 <code>makeAdder</code>에 의해 생성된 범위 객체를 청소해야겠지만, 리턴된 함수가 여전히 범위 객체를 참조하고 있습니다. 결과적으로 범위 객체는 <code>makeAdder</code>에 의해 리턴된 함수 객체가 더는 참조되지 않을 때까지 가비지 컬렉터에 의해 정리되지 않게됩니다.</p>
<p>범위 객체는 JavaScript 객체 체계에서 사용되는 prototype 사슬과 비슷한 범위 사슬이라고 불리는 사슬을 형성합니다.</p>
<p>클로져는 함수와 함수에 의해 생성되는 범위 객체를 함께 지칭하는 용어입니다.</p>
<p>또한 클로져는 상태를 저장할 수 있도록 허용합니다 - 그렇기 때문에, 객체의 내부에서 자주 사용될 수 있는 것입니다.</p>
<h3 id=".EB.A9.94.EB.AA.A8.EB.A6.AC_.EB.88.84.EC.B6.9C" name=".EB.A9.94.EB.AA.A8.EB.A6.AC_.EB.88.84.EC.B6.9C">메모리 누출</h3>
<p>클로져의 부작용은 Internet Explorer에서 심각하지는 않지만 쉽게 메모리 누출이 된다는 것입니다. JavaScript는 가비지 컬렉트를 하는 언어 입니다. 객체가 생성됨에 따라서 메모리가 할당되고, 사용하고난 메모리는 더 참조하는 다른 객체가 없을 때 되돌아가는 방식으로 동작하는 언어란 말이죠. 호스트 환경에서 제공되는 객체들은 해당 환경에 의해 다뤄집니다.</p>
<p>브라우저 호스트는 HTML 페이지에 <a href="ko/DOM">DOM</a> 객체로서 표현되어있는 많은 수의 객체를 다뤄야 합니다. 이 객체들을 어떻게 할당하고 다시 거둬들일지는 브라우저 책임이죠.</p>
<p>Internet Explorer는 이를 위해 자신만의 고유한, JavaScript의 그것과는 다른 가비지 컬렉션 방식을 사용합니다. 두 언어간에 상호작용이 일어날 수 있고 이 과정에서 메모리 누출이 발생할 수 있습니다.</p>
<p>IE에서 메모리 누출은 JavaScript 객체와 고유 객체간에 참조하는 중 자기 자신을 참조 (circular reference, 순환 참조)하게 되는 일이 발생할 경우라면 언제든지 발생하게 됩니다. 다음을 고려해 보도록 합시다:</p>
<pre class="brush: js notranslate">function leakMemory() {
var el = document.getElementById('el');
var o = { 'el': el };
el.o = o;
}
</pre>
<p>위의 코드는 순환 참조로서 메모리 누출을 일으킵니다. IE는 완전히 다시 시작되기 전까지는 <code>el</code>와 <code>o</code>에 의해 사용되는 메모리를 반환하지 못합니다.</p>
<p>위의 경우는 알아채지 못하고 지나갈 확률이 높습니다. 메모리 누출은 사실 오랫동안 실행되거나 큰 데이터 구조나 반복, 순환에 의해 누출된는 메모리 양이 많은 경우에서 실질적으로 고려할만한 가치가 생깁니다.</p>
<p>누출이 이처럼 명확한 경우는 드뭅니다. 누출을 일으키는 데이터 구조는 수차례에 걸친 참조 구조를 가지고 있어서 순환 참조를 하고있는지 명확하지 않은 경우가 더 많습니다.</p>
<p>클로져는 그렇게 되도록 하지않아도 간단하게 메모리 누출을 일으킬 수 있습니다. 다음을 고려해 봅시다:</p>
<pre class="brush: js notranslate">function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
this.style.backgroundColor = 'red';
}
}
</pre>
<p>위의 코드는 클릭했을때 배경색이 빨강으로 바뀌는 엘레멘트를 설정합니다. 그리고 메모리 누출도 일으킵니다. 어째서냐고요? <code>el</code>을 참조하면 의도와는 달리 익명 내부 함수 때문에 생성된 클로져 내에 붙잡혀 있게 되기 때문입니다. 이는 JavaScript 객체 (내부 함수)와 원시 객체 (<code>el</code>)간에 순환 참조를 만듭니다.</p>
<p>이 문제를 피할 수 있는 많은 방법이 있습니다. 가장 간단한 건 이겁니다:</p>
<pre class="brush: js notranslate">function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
this.style.backgroundColor = 'red';
}
el = null;
}
</pre>
<p>이렇게 하면 순환 참조 고리를 끊을 수 있습니다.</p>
<p>놀랍게도, 클로져에 의해 발생된 순환 참조를 고리를 끊기 위한 한 요령은 또다른 클로져를 추가하는 것입니다:</p>
<pre class="brush: js notranslate">function addHandler() {
var clickHandler = function() {
this.style.backgroundColor = 'red';
}
(function() {
var el = document.getElementById('el');
el.onclick = clickHandler;
})();
}
</pre>
<p>내부 함수는 실행되고 바로 사라지므로서, <code>clickHandler</code>와 함께 생성된 클로져로부터 그 내용을 숨깁니다.</p>
<p>클로져를 피할 수 있는 또다른 좋은 요령은 <code>window.onunload</code> 이벤트가 발생하는 동안 순환 참조를 끊는 것입니다. 많은 이벤트 라이브러리가 이렇게 동작합니다. 주의할 것은 그렇게 하도록하면 <a href="ko/Using_Firefox_1.5_caching">Firefox 1.5의 bfcache</a>를 비활성화 하게 되므로, 별 다른 이유가 없다면 Firefox에서 <code>unload</code> listener를 등록해서는 안 된다는 것입니다.</p>
<div class="originaldocinfo">
<h2 id=".EC.9B.90.EB.B3.B8_.EB.AC.B8.EC.84.9C_.EC.A0.95.EB.B3.B4" name=".EC.9B.90.EB.B3.B8_.EB.AC.B8.EC.84.9C_.EC.A0.95.EB.B3.B4">원본 문서 정보</h2>
<ul>
<li>저자: <a class="external" href="http://simon.incutio.com/">Simon Willison</a></li>
<li>최근 갱신 날짜: March 7, 2006</li>
<li>저작권: © 2006 Simon Willison, contributed under the Creative Commons: Attribute-Sharealike 2.0 license.</li>
<li>추가 정보: For more information about this tutorial (and for links to the original talk's slides), see Simon's <a class="external" href="http://simon.incutio.com/archive/2006/03/07/etech">Etech weblog post</a>.</li>
</ul>
</div>
<div class="noinclude"></div>
<p>{{ languages( { "en": "en/A_re-introduction_to_JavaScript", "fr": "fr/Une_reintroduction_a_JavaScript", "it": "it/Una_re-introduzione_a_Javascript", "ja": "ja/A_re-introduction_to_JavaScript", "pl": "pl/JavaScript/Na_pocz?tek", "zh-cn": "cn/A_re-introduction_to_JavaScript" } ) }}</p>
|