forked from BonsaiDen/JavaScript-Garden
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1539 lines (1072 loc) · 92.7 KB
/
index.html
File metadata and controls
1539 lines (1072 loc) · 92.7 KB
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
<!DOCTYPE html><html lang="ja"><head><title>JavaScript Garden</title><meta charset="utf-8"><meta name="description" content="JavaScriptの奇妙さと欠陥についてのガイドライン"><link rel="stylesheet" href="../style/garden.css" media="all"><link rel="stylesheet" href="../style/print.css" media="print"><!--[if lt IE 9]>
<script src="javascript/html5.js"></script>
<![endif]-->
</head><body><!-- Navigation--><nav id="nav_main"><div><ul><li><a href="/JavaScript-Garden/pl" title="JavaScript Garden - ogród JavaScript po polsku">pl</a></li><li><a href="/JavaScript-Garden/" title="JavaScript Garden in English">en</a></li><li><a href="/JavaScript-Garden/ru" title="JavaScript Гарден по-русски">ru</a></li><li><a href="/JavaScript-Garden/zh" title="JavaScript Garden 中文翻译">zh</a></li><li><a href="/JavaScript-Garden/tr" title="JavaScript Garden Türkçe">tr</a></li><li><a href="/JavaScript-Garden/es" title="JavaScript Garden es Español">es</a></li><li class="active"><a href="/JavaScript-Garden/ja" title="JavaScript Garden in Japanese">ja</a></li><li><a href="/JavaScript-Garden/ko" title="JavaScript Garden">ko</a></li><li><a href="/JavaScript-Garden/fi" title="JavaScript-puutarha suomeksi">fi</a></li></ul><a id="top" href="#intro" title="Back to top">#top</a><a id="hide_menu" class="tablet">Hide Menu</a></div><ul><li class="nav_intro"><h1><a href="#intro">前書き</a></h1><ul></ul></li><li class="nav_object"><h1><a href="#object">オブジェクト</a></h1><ul><li><a href="#object.general">オブジェクトの使用法とプロパティ</a></li><li><a href="#object.prototype">プロトタイプ</a></li><li><a href="#object.hasownproperty"><code>hasOwnProperty</code></a></li><li><a href="#object.forinloop"><code>for in</code>ループ</a></li></ul></li><li class="nav_function"><h1><a href="#function">関数</a></h1><ul><li><a href="#function.general">関数の宣言と式</a></li><li><a href="#function.this"><code>this</code>はどのように動作するのか</a></li><li><a href="#function.closures">クロージャと参照</a></li><li><a href="#function.arguments">オブジェクトの<code>arguments</code></a></li><li><a href="#function.constructors">コンストラクタ</a></li><li><a href="#function.scopes">スコープと名前空間</a></li></ul></li><li class="nav_array"><h1><a href="#array">配列</a></h1><ul><li><a href="#array.general">配列の繰り返しとプロパティ</a></li><li><a href="#array.constructor"><code>Array</code>コンストラクター</a></li></ul></li><li class="nav_types"><h1><a href="#types">型</a></h1><ul><li><a href="#types.equality">等価と比較</a></li><li><a href="#types.typeof"><code>typeof</code>演算子</a></li><li><a href="#types.instanceof"><code>instanceof</code>オペレーター</a></li><li><a href="#types.casting">型変換</a></li></ul></li><li class="nav_core"><h1><a href="#core">コア</a></h1><ul><li><a href="#core.eval">なぜ、<code>eval</code>を使ってはいけないのか</a></li><li><a href="#core.undefined"><code>undefined</code>と<code>null</code></a></li><li><a href="#core.semicolon">セミコロン自動挿入</a></li></ul></li><li class="nav_other"><h1><a href="#other">その他</a></h1><ul><li><a href="#other.timeouts"><code>setTimeout</code>と<code>setInterval</code></a></li></ul></li></ul></nav><!-- Mobile navigation--><nav id="nav_mobile"><a id="nav_prev_section" href="#">prev section<span class="nav_section_name">section name</span></a><a id="nav_next_section" href="#">next section<span class="nav_section_name">section name</span></a><a id="show_menu">show menu</a></nav><!-- Sections--><section id="intro"><!-- Introduction--><header id="intro.intro"><h1>前書き</h1><div><p><strong>JavaScript Garden</strong> はJavaScriptというプログラム言語の一番奇妙な部分についてのドキュメント集です。
このドキュメントはJavaScriptという言語に慣れていないプログラマーがこの言語について深く知ろうとする際に遭遇する、良くある間違い・小さなバグ・パフォーマンスの問題・悪い習慣などを避ける為のアドバイスを与えます。</p>
<p>JavaScript GardenはJavaScriptを教える事を<strong>目的にしていません</strong>。このガイドの項目を理解する為には、この言語に対する前提知識がある事を推奨します。この言語の基礎部分についてはMozilla Developer Networkの<a href="https://developer.mozilla.org/en/JavaScript/Guide">ガイド</a> がオススメです。 </p>
<h2>著者</h2>
<p>このガイドは愛すべき<a href="http://stackoverflow.com/">Stack Overflow</a>の2人のユーザー<a href="http://stackoverflow.com/users/170224/ivo-wetzel">Ivo Wetzel</a>
(執筆)と<a href="http://stackoverflow.com/users/313758/yi-jiang">Zhang Yi Jiang</a> (デザイン)によって作られました。</p>
<h2>貢献者</h2>
<ul>
<li><a href="https://github.com/caio">Caio Romão</a> (スペル校正)</li>
<li><a href="https://github.com/blixt">Andreas Blixt</a> (言語校正)</li>
</ul>
<h2>ホスティング</h2>
<p>JavaScript GardenはGitHubでホスティングされていますが、<a href="http://cramerdev.com/">Cramer Development</a>が<a href="http://javascriptgarden.info/">JavaScriptGarden.info</a>というミラーサイトを作ってくれています。</p>
<h2>ライセンス</h2>
<p>JavaScript Gardenは<a href="https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE">MIT license</a>の下で公開されており、<a href="https://github.com/BonsaiDen/JavaScript-Garden">GitHub</a>でホスティングされています。もしもエラーやtypoを見つけたら<a href="https://github.com/BonsaiDen/JavaScript-Garden/issues">file an issue</a>に登録するかリポジトリにプルリクエストを送ってください。
またStack Overflowチャットの<a href="http://chat.stackoverflow.com/rooms/17/javascript">JavaScript room</a>に私達はいます。</p></div></header><!-- Articles--></section><section id="object"><!-- Introduction--><header id="object.intro"><h1>オブジェクト</h1></header><!-- Articles--><article id="object.general"><h2>オブジェクトの使用法とプロパティ</h2><div><p>JavaScriptの全ての要素は2つの例外を除いて、オブジェクトのように振る舞います。
その2つとは<a href="#core.undefined"><code>null</code></a>と<a href="#core.undefined"><code>undefined</code></a>です。</p>
<pre><code>false.toString() // 'false'
[1, 2, 3].toString(); // '1,2,3'
function Foo(){}
Foo.bar = 1;
Foo.bar; // 1
</code></pre>
<p>良くありがちな誤解として、数値リテラルがオブジェクトとして使用できないというものがあります。この理由としては、JavaScriptパーサーが浮動小数点のドットを<em>ドット記法</em>として解釈しようとしてしまうからです。</p>
<pre><code>2.toString(); // シンタックスエラーが発生する
</code></pre>
<p>数値リテラルをオブジェクトとして使用する為の回避策がいくつかあります。</p>
<pre><code>2..toString(); // 2つ目のドットが正しく解釈される
2 .toString(); // ドットの左隣のスペースがポイント
(2).toString(); // 2が一番最初に評価される
</code></pre>
</div><div><h3>オブジェクトはデータタイプ</h3>
<p>JavaScriptのオブジェクトは<a href="http://en.wikipedia.org/wiki/Hashmap"><em>ハッシュマップ</em></a>としても使用されます。これは名前付きのプロパティと値として構成されています。</p>
<p>オブジェクトリテラル(<code>{}</code>記法)を使用すると、オブジェクトそのものを作る事ができます。この方法で作られたオブジェクトは<code>Object.prototype</code>から<a href="#object.prototype">継承</a>され、<a href="#object.hasownproperty">own properties</a>が何も設定されてない状態になります。</p>
<pre><code>var foo = {}; // 新しい空のオブジェクト
// 12という値の'test'というプロパティを持った新しいオブジェクト
var bar = {test: 12};
</code></pre>
</div><div><h3>プロパティへのアクセス</h3>
<p>オブジェクトのプロパティには2通りのアクセス方法があります。1つはドット記法によるアクセス、もう1つはブラケット記法です。</p>
<pre><code>var foo = {name: 'Kitten'}
foo.name; // kitten
foo['name']; // kitten
var get = 'name';
foo[get]; // kitten
foo.1234; // シンタックスエラー
foo['1234']; // 動作する
</code></pre>
<p>どちらの記法も働きとしての違いは無いですが、唯一の違いとしてブラケット記法は通常のプロパティ名と同様に動的にプロパティを設定する事ができます。これ以外で動的にプロパティを設定しようとするとシンタックスエラーになります。</p>
</div><div><h3>プロパティの削除</h3>
<p>実際にオブジェクトからプロパティを削除する唯一の方法は<code>delete</code>演算子を使う事です。プロパティに<code>undefined</code>や<code>null</code>をセットしても、プロパティ自身ではなく、<em>キー</em>に設定された<em>値</em>を削除するだけです。</p>
<pre><code>var obj = {
bar: 1,
foo: 2,
baz: 3
};
obj.bar = undefined;
obj.foo = null;
delete obj.baz;
for(var i in obj) {
if (obj.hasOwnProperty(i)) {
console.log(i, '' + obj[i]);
}
}
</code></pre>
<p>上記の例では、<code>baz</code>は完全に削除されて出力がされていませんが、それ以外の2つ<code>bar undefined</code>と<code>foo null</code>はどちらも出力されてしまっています。</p>
</div><div><h3>キーの記法</h3>
<pre><code>var test = {
'case': 'I am a keyword so I must be notated as a string',
delete: 'I am a keyword too so me' // シンタックスエラーが起こる
};
</code></pre>
<p>オブジェクトのプロパティは普通の文字か文字列として記述する事が出来ます。JavaScriptパーサーの設計ミスが原因ですが、ECMAScript5以前では上記のコードは<code>シンタックスエラー</code>を表示するでしょう。</p>
<p>このエラーは<code>delete</code>が<em>予約語</em>になっているのが原因なので、古いJavaScriptエンジンに正しく解釈させる為には<em>文字リテラル</em>を使って記述する事を推奨します。</p></div></article><article id="object.prototype"><h2>プロトタイプ</h2><div><p>JavaScriptはクラスベース継承モデルは実装されておらず、この代わりに<em>プロトタイプ</em>を用いています。</p>
<p>プロトタイプモデルを使っている事が、JavaScriptの弱点の一つになっていると良く考えられがちですが、プロトタイプ継承モデルはクラスベース継承モデルよりパワフルだというのは事実です。この事はちょっとしたものでもクラスベースの継承で実装しようとすると、プロトタイプベースの継承よりも作業が難しくなるという事でも分かります。</p>
<p>JavaScriptはプロトタイプベースが採用されている唯一の広範に使用されている基本的なプログラミング言語という現実があるので、プロトタイプベースとクラスベースの違いを時々調整しないとなりません。</p>
<p>最初の大きな違いはJavaScriptの継承は<em>プロトタイプチェーン</em>と呼ばれるもので実行されているという事です。</p>
<aside>
<p><strong>注意:</strong> 単に<code>Bar.prototype = Foo.prototype</code>を使った場合、両方のオブジェクトは、
<strong>同じ</strong>プロトタイプを共有する事になります。その為、片方のオブジェクトのプロトタイプの変更は
もう一方のオブジェクトに影響します。大部分の場合、このような影響を及ぼしたく無いと思います。</p>
</aside>
<pre><code>function Foo() {
this.value = 42;
}
Foo.prototype = {
method: function() {}
};
function Bar() {}
// BarのプロトタイプをFooの新しいインスタンスとしてセットする
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';
// Barを実際のコンストラクタとして確実にする為に代入する
Bar.prototype.constructor = Bar;
var test = new Bar() // 新しくbarインスタンスを作成
// プロトタイプチェーンの結果
test [instance of Bar]
Bar.prototype [instance of Foo]
{ foo: 'Hello World' }
Foo.prototype
{ method: ... }
Object.prototype
{ toString: ... /* その他 */ }
</code></pre>
<p>上記では<code>test</code>は<code>Bar.prototype</code>と<code>Foo.prototype</code>の2つのオブジェクトより継承されます。その為<code>Foo</code>の中で設定された<code>method</code>関数にアクセスできるようになります。また、<code>Foo</code>のプロトタイプとしてのインスタンス<strong>それ自体</strong>の<code>value</code>プロパティにもアクセスが可能です。<code>new Bar()</code>は<code>Foo</code>のインスタンスを新しく作ら<strong>ない</strong>という事は非常に注目されるべき点ですが、それ自身のプロトタイプを再利用しています。従って全ての<code>Bar</code>インスタンスは<strong>同じ</strong><code>value</code>プロパティを共有します。</p>
<aside>
<p><strong>注意:</strong> <code>Bar.prototype = Foo</code>のような使い方は<strong>しない</strong>で下さい。<code>Foo</code>はそのプロトタイプではなく、
関数オブジェクト<code>Foo</code>自体を指しているからです。
プロトタイプチェーンは<code>Foo.prototype</code>ではなく<code>Function.prototype</code>まで遡るので、
<code>method</code>はプロトタイプチェーン上に出現しなくなります。</p>
</aside>
</div><div><h3>プロパティ探索</h3>
<p>オブジェクトのプロパティにアクセスする時には、JavaScriptはプロトタイプチェーンを要求された名前を見つけるまで<strong>遡って</strong>探索します。</p>
<p>チェーンの先頭(すなわち<code>Object.prototype</code>)に到達した際に、まだ指定されたプロパティが見つからなければ、代わりに<a href="#core.undefined">undefined</a>という値を返します。</p>
</div><div><h3>プロトタイププロパティ</h3>
<p>プロトタイププロパティはJavaScriptの中でプロトタイプチェーンを構築する為に使われていますが、<strong>任意</strong>の値を代入する事も可能になっています。この時プロトタイプに代入されている値は単に無視されるだけです。</p>
<pre><code>function Foo() {}
Foo.prototype = 1; // 効果無し
</code></pre>
<p>割り当てられているオブジェクトは上記の例で示されている通りに動作し、動的にプロトタイプチェーンを作ります。</p>
</div><div><h3>パフォーマンス</h3>
<p>プロトタイプチェーンの上位にあるプロパティを探索する時間はコードの実行パフォーマンスに重大な悪影響を与えます。特に存在しないプロパティにアクセスしようとすると、プロトタイプチェーンの全てのプロパティを探索してしまいます。</p>
<p>また、オブジェクトのプロパティに対して<a href="#object.forinloop">反復</a>処理をすると、プロトタイプチェーン上の<strong>全て</strong>のプロパティを列挙してしまいます。</p>
</div><div><h3>既存のプロトタイプの拡張</h3>
<p>元々組み込まれてるプロトタイプや<code>Object.prototype</code>を拡張するのは、良くありがちなイケていない実装方法になります。</p>
<p>このテクニックは<a href="http://en.wikipedia.org/wiki/Monkey_patch">monkey patching</a>と呼ばれるもので<em>カプセル化</em>を壊してしまいます。このテクニックは<a href="http://prototypejs.org/">Prototype</a>のようなフレームワークにより広まりましたが、<em>非標準</em>の機能を持っている組み込み型のオブジェクトの乱立という点でも推奨されません。</p>
<p><strong>唯一</strong>組み込みのプロトタイプを拡張しても良い理由としては、JavaScriptエンジンに将来実装されるであろう機能の移植だけです。
例えば<a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach"><code>Array.forEach</code></a>などが、それに当たります。</p>
</div><div><h3>終わりに</h3>
<p>ここまでがプロトタイプベース継承モデルを使って複雑なコードを書く前に<strong>必ず</strong>理解すべき事です。また、プロパティチェーンの長さを観察して、もしパフォーマンスに悪影響を及ぼすのを防ぐ為ならば、これを分割をしなければなりません。さらに組み込みのプロトタイプは新しいJavaScriptの機能と互換性が無い限りは<strong>絶対</strong>に拡張してはいけません。</p></div></article><article id="object.hasownproperty"><h2><code>hasOwnProperty</code></h2><div><p>オブジェクトは<em>自分自身</em>と<strong>自分以外</strong>のどちらで定義されたプロパティかを<a href="#object.prototype">prototype chain</a>のどこかでチェックしなくてはなりません。これは<code>Object.prototype</code>から継承される全てのオブジェクトの<code>hasOwnProperty</code>メソッドを使う必要があります。</p>
<aside>
<p><strong>注意:</strong> この方法はプロパティが<code>undefined</code>かどうかを調べるには十分では<strong>無い</strong>方法です。
プロパティは、ほとんどのオブジェクトで存在しているはずの物ではありますが、<code>undefined</code>が
値に設定される事態は起こり得ます。</p>
</aside>
<p><code>hasOwnProperty</code>はJavaScriptで唯一プロトタイプチェーン内を<strong>遡らず</strong>にプロパティを扱う事が出来ます。</p>
<pre><code>// Object.prototype汚染
Object.prototype.bar = 1;
var foo = {goo: undefined};
foo.bar; // 1
'bar' in foo; // true
foo.hasOwnProperty('bar'); // false
foo.hasOwnProperty('goo'); // true
</code></pre>
<p><code>hasOwnProperty</code>だけが、正しく期待した結果を出すでしょう。これはあらゆるオブジェクトのプロパティの繰り返し処理をする時必須の事です。オブジェクト<em>自身</em>に定義されておらず、プロトタイプチェーンのどこかには定義されているというプロパティを除外する手段が他に<strong>ありません</strong>。</p>
</div><div><h3>プロパティとしての<code>hasOwnProperty</code></h3>
<p>JavaScriptはプロパティ名として<code>hasOwnProperty</code>を保護して<strong>いません</strong>。;従って、この名前のプロパティを持ったオブジェクトが存在する事がありえます。正しい結果を得る為には<em>外部</em>の<code>hasOwnProperty</code>を使う必要があります。</p>
<pre><code>var foo = {
hasOwnProperty: function() {
return false;
},
bar: 'Here be dragons'
};
foo.hasOwnProperty('bar'); // 常にfalseを返す
// 他のオブジェクトのhasOwnPropertyを使い、fooの'this'にセットして呼び出す
({}).hasOwnProperty.call(foo, 'bar'); // true
</code></pre>
</div><div><h3>終わりに</h3>
<p>オブジェクトのプロパティの存在判定をする時は、<code>hasOwnProperty</code>が<strong>唯一</strong>のメソッドになります。
また、<strong>全て</strong>の<a href="#object.forinloop"><code>for in</code> ループ</a>内で<code>hasOwnProperty</code>を使う事を推奨します。
そうする事により組み込みの<a href="#object.prototype">prototypes</a>の拡張が原因のエラーを避ける事が出来ます。</p></div></article><article id="object.forinloop"><h2><code>for in</code>ループ</h2><div><p><code>in</code>オペレーターは単に、<code>for in</code>ループの中でオブジェクトのプロパティをプロトタイプチェーンの中で繰り返し遡る為にあるものです。</p>
<aside>
<p><strong>注意:</strong> <code>for in</code>ループは<code>列挙</code>される属性が<code>false</code>にセットされているプロパティを反復処理<strong>しません</strong>。;
例えば、配列の<code>length</code>プロパティなどがそれに当たります。</p>
</aside>
<pre><code>// Object.prototype汚染
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
console.log(i); // barとmooが両方とも表示される
}
</code></pre>
<p><code>for in</code>ループそれ自体の動作を変更する事は不可能ですが、ループ内にある要らないプロパティをフィルタリングする必要があります。そんな時は<code>Object.prototype</code>の<a href="#object.hasownproperty"><code>hasOwnProperty</code></a>メソッドを使うと解決します。</p>
<aside>
<p><strong>注意:</strong> <code>for in</code>は常にプロトタイプチェーンを完全に遡ります。これにより
オブジェクトに追加されている継承が多ければ多い程、速度は遅くなります。</p>
</aside>
</div><div><h3><code>hasOwnProperty</code>をフィルタリングに使用する</h3>
<pre><code>// 継承されているfoo
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i);
}
}
</code></pre>
<p>このループの唯一正しい使い方がこの方法です。<code>hasOwnProperty</code>を使用しているので、
<code>moo</code><strong>のみ</strong>が表示されるようになります。<code>hasOwnProperty</code>が省略されている場合は、このコードは
組み込みのプロトタイプが存在する場合に(特に<code>Object.prototype</code>が拡張されている場合)エラーを発生しやすくなります。</p>
<p>一般に広く使用されているJavaScriptフレームワークとして<a href="http://www.prototypejs.org/">Prototype</a>が挙げられます。このフレームワークには、
<code>for in</code> 内で<code>hasOwnProperty</code>が使用されプロトタプチェーン内を頭まで遡るのを中断する事が保証されています。</p>
</div><div><h3>終わりに</h3>
<p><strong>常に</strong><code>hasOwnProperty</code>を使用する事を推奨します。コードの実行環境や、組み込みのプロトタイプが拡張されているかどうかを仮定して書くようなコードを絶対書いてはいけません。</p></div></article></section><section id="function"><!-- Introduction--><header id="function.intro"><h1>関数</h1></header><!-- Articles--><article id="function.general"><h2>関数の宣言と式</h2><div><p>関数はJavaScriptの第一級オブジェクトです。この事は、その他の値と同じように渡す事が出来るという事です。この機能で良く使われる一つとして<strong>匿名関数</strong>を他のオジェクトにコールバックとして渡すというものがあり、これで非同期での実装が可能になります。</p>
</div><div><h3><code>関数</code>宣言</h3>
<pre><code>function foo() {}
</code></pre>
<p>上記の関数はプログラムの開始時の前に評価されるように<a href="#function.scopes">巻き上げ</a>られます。従って<em>定義</em>されたスコープ内の<em>どこでも</em>使用する事が可能になります。ソース内での実際の定義が呼ばれる前でもです。</p>
<pre><code>foo(); // このコードが動作する前にfooが作られているので、ちゃんと動作する
function foo() {}
</code></pre>
</div><div><h3><code>関数</code>式</h3>
<pre><code>var foo = function() {};
</code></pre>
<p>この例では、<code>foo</code>という変数に無名で<em>匿名</em>の関数が割り当てられています。</p>
<pre><code>foo; // 'undefined'
foo(); // これはTypeErrorが起こる
var foo = function() {};
</code></pre>
<p><code>var</code>は宣言である為に、変数名<code>foo</code>がコードが開始される実際の評価時より前のタイミングにまで巻き上げられています。<code>foo</code>は既にスクリプトが評価される時には定義されているのです。</p>
<p>しかし、コードの実行時にのみこの割り当てがされるため、<code>foo</code>という変数は対応するコードが実行される前にデフォルト値である<a href="#core.undefined">undefined</a>が代入されるのです。</p>
</div><div><h3>名前付き関数宣言</h3>
<p>他に特殊なケースとして、命名関数があります。</p>
<pre><code>var foo = function bar() {
bar(); // 動作する
}
bar(); // ReferenceError
</code></pre>
<p>この場合の<code>bar</code>は<code>foo</code>に対して関数を割り当てるだけなので、外部スコープでは使用できません。しかし、<code>bar</code>は内部では使用できます。これはJavaScriptでは<a href="#function.scopes">名前解決</a>による動作です。関数名は<em>いつも</em>関数自体のローカルスコープ内で有効になっています。</p></div></article><article id="function.this"><h2><code>this</code>はどのように動作するのか</h2><div><p>JavaScriptの<code>this</code>と名付けられた特殊なキーワードは他のプログラム言語と違うコンセプトを持っています。JavaScriptの<code>this</code>は正確に<strong>5個</strong>の別々の使い道が存在しています。</p>
</div><div><h3>グローバルスコープとして</h3>
<pre><code>this;
</code></pre>
<p><code>this</code>をグローバルスコープ内で使用すると、単純に<em>グローバル</em>オブジェクトを参照するようになります。</p>
</div><div><h3>関数呼び出しとして</h3>
<pre><code>foo();
</code></pre>
<p>この<code>this</code>は、再度<em>グローバル</em>オブジェクトを参照しています。</p>
<aside class="es5"><p><strong>ES5での注意:</strong> strictモードでは、このグローバルのケースは<strong>もはや</strong>存在していません。
この場合<code>this</code>は<code>undefined</code>値を代わりに持つことになります。</p>
</aside>
</div><div><h3>メソッド呼び出しとして</h3>
<pre><code>test.foo();
</code></pre>
<p>この例では<code>this</code>は<code>test</code>を参照します。</p>
</div><div><h3>コンストラクター呼び出し</h3>
<pre><code>new foo();
</code></pre>
<p><code>new</code>キーワードが付いた関数呼び出しは<a href="#function.constructors">コンストラクター</a>として機能します。関数内部では<code>this</code>は<em>新規に作成された</em><code>Object</code>を参照します。</p>
</div><div><h3><code>this</code>の明示的な設定</h3>
<pre><code>function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // 配列は下記で展開される
foo.call(bar, 1, 2, 3); // 結果はa = 1, b = 2, c = 3
</code></pre>
<p><code>Function.prototype</code>の<code>call</code>や<code>apply</code>メソッドを使用した時には、呼び出された関数の内部での<code>this</code>の値は、対応する関数呼び出しの最初の引数に<strong>明示的に設定</strong>されます。</p>
<p>結果として、上記の例では<em>メソッドケース</em>が適用<strong>されず</strong>、<code>foo</code>の内部の<code>this</code>は<code>bar</code>に設定されます。</p>
<aside>
<p><strong>注意:</strong> <code>this</code>は<code>Object</code>リテラル内部のオブジェクトを参照<strong>しません</strong>。
ですので、<code>var obj = {me: this}</code>での<code>me</code>は<code>obj</code>を参照<strong>しません</strong>。
<code>this</code>はここで紹介ている5個のケースの内どれか一つに束縛されます。</p>
</aside>
</div><div><h3>良くある落し穴</h3>
<p>これらのケースのほとんどは理にかなったものですが、最初のケースは実際に利用されることが<strong>絶対</strong>にないので、間違った言語設計だとみなせるでしょう。</p>
<pre><code>Foo.method = function() {
function test() {
// このファンクションはグローバルオブジェクトに設定される
}
test();
}
</code></pre>
<p>良くある誤解として<code>test</code>の中の<code>this</code>が<code>Foo</code>を参照しているというものがありますが、そのような事実は<strong>一切</strong>ありません。</p>
<p><code>test</code>の中の<code>Foo</code>にアクセスする為には、<code>Foo</code>を参照する<code>method</code>のローカル変数を作る必要があります。</p>
<pre><code>Foo.method = function() {
var that = this;
function test() {
// ここでthisの代わりに使用する
}
test();
}
</code></pre>
<p><code>that</code>は通常の変数名ですが、外部の<code>this</code>の参照の為に良く使われます。<a href="#function.closures">クロージャ</a>と組み合わせる事で<code>this</code>の値を渡す事ができるようになります。</p>
</div><div><h3>メソッドの割り当て</h3>
<p>JavaScriptを使用する上で、もう一つ動か<strong>ない</strong>ものが関数のエイリアスです。これは変数へメソッドを<strong>割り当て</strong>する事です。</p>
<pre><code>var test = someObject.methodTest;
test();
</code></pre>
<p>最初のケースの<code>test</code>は通常の関数呼び出しになる為に、この中の<code>this</code>は、もはや<code>someobject</code>を参照できなくなってしまいます。</p>
<p><code>this</code>の遅延バインディングは最初見た時にはダメなアイデアに見えますが、<a href="#object.prototype">プロトタイプ継承</a>により、きちんと動作します。</p>
<pre><code>function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
</code></pre>
<p><code>method</code>が<code>Bar</code>のインスタンスにより呼び出された時に、<code>this</code>はまさにそのインスタンスを参照するようになります。</p></div></article><article id="function.closures"><h2>クロージャと参照</h2><div><p>JavaScriptの一番パワフルな特徴の一つとして<em>クロージャ</em>が使える事が挙げられます。これはスコープが<strong>いつも</strong>外部に定義されたスコープにアクセスできるという事です。JavaScriptの唯一のスコープは<a href="#function.scopes">関数スコープ</a>ですが、全ての関数は標準でクロージャとして振る舞います。</p>
</div><div><h3>プライベート変数をエミュレートする</h3>
<pre><code>function Counter(start) {
var count = start;
return {
increment: function() {
count++;
},
get: function() {
return count;
}
}
}
var foo = Counter(4);
foo.increment();
foo.get(); // 5
</code></pre>
<p>ここで<code>Counter</code>は<strong>2つ</strong>のクロージャを返します。関数<code>increment</code>と同じく関数<code>get</code>です。これら両方の関数は<code>Counter</code>のスコープを<strong>参照</strong>し続けます。その為、そのスコープ内に定義されている<code>count</code>変数に対していつもアクセスできるようになっています。</p>
</div><div><h3>なぜプライベート変数が動作するのか?</h3>
<p>JavaScriptでは、スコープ自体を参照・代入する事が出来無い為に、外部から変数<code>count</code>にアクセスする手段が<strong>ありません</strong>。唯一の手段は、2つのクロージャを介してアクセスする方法だけです。</p>
<pre><code>var foo = new Counter(4);
foo.hack = function() {
count = 1337;
};
</code></pre>
<p>上記のコードは<code>Counter</code>のスコープ中にある変数<code>count</code>の値を変更する事は<strong>ありません</strong>。<code>foo.hack</code>は<strong>その</strong>スコープで定義されていないからです。これは<em>グローバル</em>変数<code>count</code>の作成 -またはオーバーライド- の代わりになるでしょう。</p>
</div><div><h3>ループ中のクロージャ</h3>
<p>一つ良くある間違いとして、ループのインデックス変数をコピーしようとしてか、ループの中でクロージャを使用してしまうというものがあります。</p>
<pre><code>for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
</code></pre>
<p>上記の例では<code>0</code>から<code>9</code>の数値が出力される事は<strong>ありません</strong>。もっと簡単に<code>10</code>という数字が10回出力されるだけです。</p>
<p><strong>匿名</strong>関数は<code>i</code>への<strong>参照</strong>を維持しており、同時に<code>forループ</code>は既に<code>i</code>の値に<code>10</code>をセットし終った<code>console.log</code>が呼ばれてしまいます。</p>
<p>期待した動作をする為には、<code>i</code>の値の<strong>コピー</strong>を作る必要があります。</p>
</div><div><h3>参照問題を回避するには</h3>
<p>ループのインデックス変数をコピーする為には、<a href="#function.scopes">匿名ラッパー</a>を使うのがベストです。</p>
<pre><code>for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e);
}, 1000);
})(i);
}
</code></pre>
<p>外部の匿名関数は<code>i</code>を即座に第一引数として呼び出し、引数<code>e</code>を<code>i</code>の<strong>値</strong>のコピーとして受け取ります。</p>
<p><code>e</code>を参照している<code>setTimeout</code>を受け取った匿名関数はループによって値が変わる事が<strong>ありません</strong>。</p>
<p>他にこのような事を実現する方法があります。それは匿名ラッパーから関数を返してあげる事です。これは上記のコードと同じような効果があります。</p>
<pre><code>for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}
</code></pre></div></article><article id="function.arguments"><h2>オブジェクトの<code>arguments</code></h2><div><p>JavaScriptの全ての関数スコープは<code>arguments</code>と呼ばれる特別な変数にアクセスできます。この変数は関数が受け取った全ての引数を保持する変数です。</p>
<aside>
<p><strong>注意:</strong> <code>arguments</code>が既に<code>var</code>や正式なパラメーターにより
関数のスコープが定義されている場合は
<code>arguments</code>オブジェクトは作られません。</p>
</aside>
<p><code>arguments</code>オブジェクトは<code>Array</code>では<strong>ありません</strong>。これは配列と同じような -<code>length</code>プロパティと名付けられています- 文法を持っていますが、<code>Array.prototype</code>を継承している訳では無いので、実際<code>Object</code>になります。</p>
<p>この為、<code>arguments</code>で<code>push</code>や<code>pop</code>、<code>slice</code>といった通常の配列メソッドは使用する事が<strong>出来ません</strong>。プレーンな<code>for</code>ループのような繰り返しでは上手く動作しますが、通常の<code>Array</code>メソッドを使いたい場合は本当の<code>Array</code>に変換しなければなりません。</p>
</div><div><h3>配列への変換</h3>
<p>下のコードは<code>arguments</code>オブジェクトの全ての要素を含んだ新しい<code>Array</code>を返します。</p>
<pre><code>Array.prototype.slice.call(arguments);
</code></pre>
<p>この変換は<strong>遅い</strong>です。コードのパフォーマンスに関わる重要な部分での使用は<strong>推奨しません</strong>。</p>
</div><div><h3>引き数の受け渡し</h3>
<p>下記の例はある関数から別の関数に引数を引き渡す際に推奨される方法です。</p>
<pre><code>function foo() {
bar.apply(null, arguments);
}
function bar(a, b, c) {
// do stuff here
}
</code></pre>
<p>他のテクニックとして、高速で非結合のラッパーとして<code>call</code>と<code>apply</code>両方を一緒に使用するという物があります。</p>
<pre><code>function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
// "メソッド"の非結合バージョンを作成する
// このメソッドはthis, arg1, arg2...argNのパラメーターを持っている
Foo.method = function() {
// 結果: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};
</code></pre>
</div><div><h3>仮パラメーターと引数のインデックス</h3>
<p><code>arguments</code>オブジェクトは<em>ゲッター</em>と<em>セッター</em>機能を自身のプロパティと同様に関数の仮パラメーターとして作成します。</p>
<p>結果として、仮パラメーターを変更すると<code>arguments</code>の対応する値も変更されますし、逆もしかりです。</p>
<pre><code>function foo(a, b, c) {
arguments[0] = 2;
a; // 2
b = 4;
arguments[1]; // 4
var d = c;
d = 9;
c; // 3
}
foo(1, 2, 3);
</code></pre>
</div><div><h3>パフォーマンスの神話と真実</h3>
<p><code>arguments</code>オブジェクトは、関数の内部の名前宣言と仮パラメーターという2つの例外を常に持ちながら生成されます。これは、使用されているかどうかは関係がありません。</p>
<p><em>ゲッター</em>と<em>セッター</em>は両方とも<strong>常に</strong>生成されます。その為これを使用してもパフォーマンスに影響は全くといって言い程ありません。<code>arguments</code>オブジェクトのパラメーターに単純にアクセスしているような、実際のコードであれば尚更です。</p>
<aside class="es5"><p><strong>ES5での注意:</strong> strictモードでは、これら<em>ゲッター</em>と<em>セッター</em>は生成されません。</p>
</aside>
<p>しかし、一つだけモダンJavaScriptエンジンにおいて劇的にパフォーマンスが低下するケースがあります。そのケースとは<code>arguments.callee</code>を使用した場合です。</p>
<pre><code>function foo() {
arguments.callee; // この関数オブジェクトで何かする
arguments.callee.caller; // そして関数オブジェクトを呼び出す
}
function bigLoop() {
for(var i = 0; i < 100000; i++) {
foo(); // 通常はインライン展開する
}
}
</code></pre>
<p>上記のコードでは、<code>foo</code>は自身と自身の呼び出し元の両方を知らないと<a href="http://en.wikipedia.org/wiki/Inlining">インライン展開</a>の対象になる事が出来ません。この事は、インライン展開によるパフォーマンスの向上の機会を失くす事になり、また、特定のコンテクストの呼び出しに依存する関数のせいで、カプセル化が解除されてしまいます。</p>
<p>この為に<code>arguments.callee</code>を使用または、そのプロパティを<strong>決して</strong>使用しない事を<strong>強く推奨</strong>します。</p>
<aside class="es5"><p><strong>ES5での注意:</strong> strictモードでは、<code>arguments.callee</code>は推奨されていない為に
<code>Typeerror</code>が返るようになっています。</p>
</aside></div></article><article id="function.constructors"><h2>コンストラクタ</h2><div><p>JavaScriptのコンストラクタは色々ある他のプログラム言語とは一味違います。<code>new</code>キーワードが付いているどんな関数呼び出しも、コンストラクタとして機能します。</p>
<p>コンストラクタ内部では -呼び出された関数の事です- <code>this</code>の値は新規に生成された<code>Object</code>を参照しています。この<strong>新規</strong>のオブジェクトの<a href="#object.prototype"><code>prototype</code></a>は、コンストラクタとして起動した関数オブジェクトの<code>prototype</code>として設定されています。</p>
<p>もし呼び出された関数が、<code>return</code>ステートメントを明示していない場合は、暗黙の了解で<code>this</code>の値を -新規のオブジェクトとして- 返します。</p>
<pre><code>function Foo() {
this.bla = 1;
}
Foo.prototype.test = function() {
console.log(this.bla);
};
var test = new Foo();
</code></pre>
<p>上記で<code>Foo</code>はコンストラクタとして呼び出され、<code>Foo.prototype</code>として新規に生成された<code>prototype</code>を設定されています。</p>
<p>明示的に<code>return</code>ステートメントがある場合、<code>Object</code>の値を返す<strong>だけでなく</strong>関数はこのステートメントを返します。</p>
<pre><code>function Bar() {
return 2;
}
new Bar(); // 新しいオブジェクト
function Test() {
this.value = 2;
return {
foo: 1
};
}
new Test(); // 返ってきたオブジェクト
</code></pre>
<p><code>new</code>キーワードが省略されている場合は、関数は新しいオブジェクトを返す事は<strong>ありません</strong>。</p>
<pre><code>function Foo() {
this.bla = 1; // グローバルオブジェクトに設定される
}
Foo(); // undefinedが返る
</code></pre>
<p>上記の例では、いくつかのケースでは動作するように見える場合があります。JavaScriptの<a href="#function.this"><code>this</code></a>の働きのせいで、<em>グローバルオブジェクト</em>が<code>this</code>の値として使用されるからです。</p>
</div><div><h3>ファクトリー</h3>
<p><code>new</code>キーワードを省略するためには、コンストラクタ関数が明示的に値を返す必要があります。</p>
<pre><code>function Bar() {
var value = 1;
return {
method: function() {
return value;
}
}
}
Bar.prototype = {
foo: function() {}
};
new Bar();
Bar();
</code></pre>
<p><code>Bar</code>で呼び出されたものは両方とも全く同じものものになります。これには、<code>method</code>と呼ばれるプロパティを持ったオブジェクトが新しく生成されますが、これは<a href="#function.closures">クロージャ</a>です。</p>
<p>また、注意する点として呼び出された<code>new Bar()</code>は返ってきたオブジェクトのプロトタイプに影響<strong>しません</strong>。プロトタイプが新しく生成されたオブジェクトにセットされるまで、<code>Bar</code>は絶対に新しいオブジェクトを返さないのです。</p>
<p>上記の例では、<code>new</code>キーワードの使用の有無は機能的に違いがありません。</p>
</div><div><h3>ファクトリーとして新しくオブジェクトを作成する</h3>
<p>大半の場合に推奨されるのは、<code>new</code>の付け忘れによるバグを引き起こしやすいので使用<strong>しない</strong>事です。</p>
<p>新しいオブジェクトを作成するためにファクトリーを使用するか、そのファクトリー内部に新しいオブジェクトを構築する必要があります。</p>
<pre><code>function Foo() {
var obj = {};
obj.value = 'blub';
var private = 2;
obj.someMethod = function(value) {
this.value = value;
}
obj.getPrivate = function() {
return private;
}
return obj;
}
</code></pre>
<p>上記の例では<code>new</code>キーワードが無いため堅牢になりますし、確実に<a href="#function.closures">プライベート変数</a>を使用するのが簡単になりますが、いくつかの欠点があります。</p>
<ol>
<li>作られたオブジェクトがプロトタイプ上のメソッドを共有しないために、よりメモリーを消費してしまいます。</li>
<li>ファクトリーを継承するために、他のオブジェクトの全てのメソッドをコピーする必要があるか、新しいオブジェクトのプロトタイプ上にそのオブジェクトを設置する必要があります。</li>
<li><code>new</code>キーワードが無いという理由だけで、プロトタイプチェーンから外れてしまうのは、どことなく言語の精神に反します。</li>
</ol>
</div><div><h3>終わりに</h3>
<p><code>new</code>キーワードが省略される事により、バグの可能性がもたらされますがプロトタイプを使わない確実な理由には<strong>なりません</strong>。最終的には、アプリケーションの必要性により、どちらの解決法がより良いかが決まってきます。特に大切なのは、オブジェクトの作成に特定のスタイルを選ぶ事、また<strong>そのスタイルに固執する事</strong>です。</p></div></article><article id="function.scopes"><h2>スコープと名前空間</h2><div><p>JavaScriptはブロックに2つのペアの中括弧を使うのが素晴しいですが、これはブロックスコープをサポートして<strong>いません</strong>。その為、この言語に残されているのは<em>関数スコープ</em>だけです。</p>
<pre><code>function test() { // スコープ
for(var i = 0; i < 10; i++) { // スコープではない
// 数える
}
console.log(i); // 10
}
</code></pre>
<aside>
<p><strong>注意:</strong> 代入が使用されてない時、return文や関数の引数、<code>{...}</code>表記はブロック文として
解釈されて、オブジェクトリテラルトは<strong>なりません</strong>。これは<a href="#core.semicolon">セミコロン自動挿入</a>
と連動して奇妙なエラーを引き起こすことになります。</p>
</aside>
<p>JavaScriptはまた明確な名前空間を持ちません。この事は全て一つの<em>グローバルで共有された</em>名前空間で定義されるという事です。</p>
<p>変数が参照されるまでの間、JavaScriptはスコープ全てを遡って参照を探索します。グローバルスコープまで遡っても要求した名前が無いと<code>ReferenceError</code>が発生します。</p>
</div><div><h3>グローバル変数の致命傷</h3>
<pre><code>// スクリプト A
foo = '42';
// スクリプト B
var foo = '42'
</code></pre>
<p>上記の2つのスクリプトは同じ効果を持って<strong>いません</strong>。スクリプト Aは<code>foo</code>と呼ばれる変数を、<em>グローバル</em>スコープに定義しており、スクリプト Bは<code>foo</code>を<em>現在</em>のスコープで定義ています。</p>
<p>再び、<code>var</code>が重大な影響を持っていない、<em>同じ効果</em>では<strong>無い</strong>スクリプトになります。</p>
<pre><code>// グローバルスコープ
var foo = 42;
function test() {
// ローカルスコープ
foo = 21;
}
test();
foo; // 21
</code></pre>
<p><code>test</code>関数の中の<code>var</code>ステートメントを省略すると<code>foo</code>の値をオーバーライドします。最初の内は大した事ではないように思いますが、JavaScriptが何千行規模になると、<code>var</code>を使っていない事で恐怖とバグの追跡の困難さを招くことになります。</p>
<pre><code>// グローバルスコープ
var items = [/* 同じリスト */];
for(var i = 0; i < 10; i++) {
subLoop();
}
function subLoop() {
// サブループのスコープ
for(i = 0; i < 10; i++) { // varステートメントが無くなった
// 素敵な実装を!
}
}
</code></pre>
<p>外側のループは<code>subloop</code>が最初に呼ばれた後に終了します。なぜなら、<code>subloop</code>がグローバル変数<code>i</code>の値で上書きされているからです。2番目の<code>for</code>ループに<code>var</code>を使用する事によって簡単にこのエラーを回避する事ができます。<code>var</code>ステートメントは<em>希望する影響</em>を外側のスコープに与える場合を除いては、<strong>絶対</strong>に残してはいけません。</p>
</div><div><h3>ローカル変数</h3>
<p>JavaScriptのローカル変数の為の唯一のソースは<a href="#function.general">function</a>パラメーターと<code>var</code>ステートメントを宣言された変数になります。</p>
<pre><code>// グローバルスコープ
var foo = 1;
var bar = 2;
var i = 2;
function test(i) {
// 関数testのローカル変数
i = 5;
var foo = 3;
bar = 4;
}
test(10);
</code></pre>
<p><code>foo</code>と<code>i</code>は、関数<code>test</code>のスコープ内のローカル変数ですが、<code>bar</code>の割り当ては同じ名前のグローバル変数で上書きされてしまいます。</p>
</div><div><h3>巻き上げ</h3>
<p>JavaScriptの<strong>巻き上げ</strong>宣言。この言葉の意味は<code>var</code>ステートメントと<code>function</code>宣言が、それらの外側のスコープに移動するというものです。</p>
<pre><code>bar();
var bar = function() {};
var someValue = 42;
test();
function test(data) {
if (false) {
goo = 1;
} else {
var goo = 2;
}
for(var i = 0; i < 100; i++) {
var e = data[i];
}
}
</code></pre>
<p>上記のコードは何も実行されないうちに変換されてしまいます。JavaScriptは<code>var</code>ステートメントと同じように、直近で囲んでいる<code>function</code>宣言を先頭に移動させます。</p>
<pre><code>// varステートメントはここに移動する
var bar, someValue; // 'undefined'がデフォルト
// function宣言もここに移動する
function test(data) {
var goo, i, e; // 無くなったブロックスコープはこちらに移動する
if (false) {
goo = 1;
} else {
goo = 2;
}
for(i = 0; i < 100; i++) {
e = data[i];
}
}
bar(); // barが'undefined'のままなので、Typeerrorで呼び出し失敗
someValue = 42; // 割り当てすると巻き上げの影響を受けない
bar = function() {};
test();
</code></pre>
<p>ブロックスコープの欠落はループ外の<code>var</code>ステートメントの移動だけでなく、その本体も移動させます。これはまた<code>if</code>が直感的じゃない結果になってしまいます。</p>
<p>元のコードの中の<code>if</code>ステートメントは<em>グローバル変数</em>である<code>goo</code>も変更しているように見えますが、実際には -巻き上げが適用された後に- <em>ローカル変数</em>を変更しています。</p>
<p><em>巻き上げ</em>についての知識がないと、下に挙げたコードは<code>ReferenceError</code>になるように見えます。</p>
<pre><code>// SomeImportantThingが初期化されているかチェックする
if (!SomeImportantThing) {
var SomeImportantThing = {};
}
</code></pre>
<p>しかし、勿論上記の動きは<code>val</code>ステートメントが<em>グローバルスコープ</em>の上に移動しているという事実に基づいています。</p>
<pre><code>var SomeImportantThing;
// 他のコードがSomeImportantThingをここで初期化するかもしれないし、しないかもしれない
// SomeImportantThingがある事を確認してください
if (!SomeImportantThing) {
SomeImportantThing = {};
}
</code></pre>
</div><div><h3>名前解決の順序</h3>
<p>JavaScriptの<em>グローバルスコープ</em>を含む、全てのスコープは、<em>現在のオブジェクト</em>を参照している特殊な名前<a href="#function.this"><code>this</code></a>を持っています。</p>
<p>関数スコープはまた、関数を通過してきた引数を含んでいる<a href="#function.arguments"><code>arguments</code></a>という名前も持っています。</p>
<p>例として、関数の中で<code>foo</code>と命名された変数にアクセスしようとする場合を考えましょう。JavaScriptは以下の順番で、その名前を探索しようとします。</p>
<ol>
<li><code>var foo</code>ステートメントが現在のスコープで使われている場合</li>
<li><code>foo</code>という名前の関数パラメーターが存在するかどうか</li>
<li>関数それ自体が<code>foo</code>として呼ばれているかどうか</li>
<li>一つ外のスコープに行き、再度<strong>#1</strong>から始める</li>
</ol>
<aside>
<p><strong>注意:</strong> <code>arguments</code>と呼ばれるパラメーターを持つという事は、デフォルトの<code>arguments</code>
オブジェクトを生成するのを<strong>阻害</strong>します。</p>
</aside>
</div><div><h3>名前空間</h3>
<p>一つしかグローバルの名前空間を持たない事による良くある問題は変数名の衝突による問題の起きる可能性です。JavaScriptでは、この問題を<em>匿名関数ラッパー</em>の助けで簡単に回避できます。</p>
<pre><code>(function() {
// "名前空間"に自分を含む
window.foo = function() {
// 露出したクロージャ
};
})(); // 即座に関数を実行する
</code></pre>
<p>無名関数は<a href="#function.general">expressions</a>とみなされ、呼び出し可能になり最初に評価されます。</p>
<pre><code>( // カッコ内の関数が評価される
function() {}
) // 関数オブジェクトが返される
() // 評価の結果が呼び出される
</code></pre>
<p>関数式を評価し、呼び出す別の方法として構文は違いますが、同様の動作をするのが下記です。</p>
<pre><code>// 2つの別の方法
+function(){}();
(function(){}());
</code></pre>
</div><div><h3>終わりに</h3>
<p>自身の名前空間にカプセル化する為に常に<em>匿名関数ラッパー</em>を使用する事を推奨します。これは、コードを名前衝突から守る為だけでなく、プログラムのより良いモジュール化の為でもあります。</p>
<p>さらに、グローバル変数の使用は<strong>悪い習慣</strong>と考えられています。<strong>一回</strong>でもグローバル変数を使用するとエラーが発生しやすく、メンテナンスがしにくいコードになってしまいます。</p></div></article></section><section id="array"><!-- Introduction--><header id="array.intro"><h1>配列</h1></header><!-- Articles--><article id="array.general"><h2>配列の繰り返しとプロパティ</h2><div><p>JavaScriptの配列もまたオブジェクトですので<a href="#object.forinloop"><code>for in ループ</code></a>を配列の繰り返しで使用するような理由はありません。実際、配列に<code>for in</code>を使用<strong>しない</strong>為の正当な理由はたくさんあります。</p>
<aside>
<p><strong>注意:</strong> JavaScriptの配列は<em>連想配列</em>では<strong>ありません</strong>。JavaScriptは<a href="#object.general">objects</a>だけがキーバリューをマッピングするものです。
また、連想配列は順序を<strong>保持</strong>しますが、オブジェクトは<strong>保持しません</strong>。</p>
</aside>
<p><code>for in</code>ループはプロトタイプチェーン上の全てのプロパティを列挙するため、<a href="#object.hasownproperty"><code>hasOwnProperty</code></a>をそれらのプロパティの存在判定に使います。この為、通常の<code>for</code>ループよりも<strong>20倍</strong>遅くなります。</p>
</div><div><h3>繰り返し</h3>
<p>配列の要素を繰り返すとのに、最高のパフォーマンスを出したければ昔ながらの<code>for</code>ループを使うのが一番です。</p>
<pre><code>var list = [1, 2, 3, 4, 5, ...... 100000000];
for(var i = 0, l = list.length; i < l; i++) {
console.log(list[i]);
}
</code></pre>
<p>上記の例では一つ余分に変数がありますが、それは配列の長さを取るための<code>l = list.length</code>の部分です。</p>
<p>また、<code>length</code>プロパティは配列自身に定義されていますが、ループのそれぞれの繰り返しで探索する為のオーバーヘッドがまだあります。最近のJavaScriptエンジンはこのような場合に最適化する<strong>はず</strong>です。新しいエンジンか古いエンジンで実行されるかどうかをコードが知る方法はありません。</p>
<p>実際には、キャッシュを抜きにするとループの結果はキャッシュされたものに比べて、<strong>半分だけ高速</strong>になっています。</p>
</div><div><h3><code>length</code>プロパティ</h3>
<p><code>length</code>プロパティの<em>ゲッター</em>は単に配列に含まれる要素の数を返すだけにも関わらず、<em>セッター</em>は配列を<strong>トランケート</strong>する為にも使用できます。</p>
<pre><code>var foo = [1, 2, 3, 4, 5, 6];
foo.length = 3;
foo; // [1, 2, 3]
foo.length = 6;
foo; // [1, 2, 3]
</code></pre>
<p>より小さいlengthを割り当てると配列をトランケートしますが、lengthが大きくなっても配列には何も影響しません。</p>
</div><div><h3>終わりに</h3>
<p>最高のパフォーマンスの為には、常に<code>for</code>ループを使用し、<code>length</code>プロパティをキャッシュする事をお勧めします。<code>for in</code>ループを配列で使用するのは、バグや最低のパフォーマンスの傾向があるコードを書く前兆になります。</p></div></article><article id="array.constructor"><h2><code>Array</code>コンストラクター</h2><div><p><code>Array</code>コンストラクターはそのパラメーターの扱い方が曖昧なので、新しい配列を作る時には、常に配列リテラル - <code>[]</code>記法 - を使用する事を強くお勧めします。</p>
<pre><code>[1, 2, 3]; // 結果: [1, 2, 3]
new Array(1, 2, 3); // 結果: [1, 2, 3]
[3]; // Result: [3]
new Array(3); // 結果: []
new Array('3') // 結果: ['3']
</code></pre>
<p>このケースの場合、<code>Array</code>コンストラクターに渡される引数は一つだけですが、その引数は<code>Number</code>になります。コンストラクターは、引数に値がセットされた<code>length</code>プロパティを伴った新しい<em>疎</em>配列を返します。特筆すべきなのは、新しい配列の<code>length</code>プロパティ<strong>のみ</strong>が、このようにセットされるという事です。実際の配列のインデックスは初期化されません。</p>
<pre><code>var arr = new Array(3);
arr[1]; // undefined
1 in arr; // false, インデックスがセットされていない
</code></pre>
<p>配列の長さが先行してセットされるという振舞いは、いくつかの場合に便利です。例えば、文字の繰り返しや、<code>for loop</code>を使用したコードの回避などの場合です。</p>
<pre><code>new Array(count + 1).join(stringToRepeat);
</code></pre>
</div><div><h3>終わりに</h3>
<p><code>Array</code>コンストラクターの使用は出来る限り避けてください。リテラルが当然望ましい形です。それらは、短かく明快な文法にもってるいる為に、コードの可読性を高めてくれます。</p></div></article></section><section id="types"><!-- Introduction--><header id="types.intro"><h1>型</h1></header><!-- Articles--><article id="types.equality"><h2>等価と比較</h2><div><p>JavaScriptはオブジェクトの値の等価の比較方法が2種類持っています。</p>
</div><div><h3>等価演算子</h3>
<p>等価演算子は2つのイコール記号: <code>==</code>から成っています。</p>
<p>JavaScriptは<em>弱い型付け</em>を特徴としています。これは等価演算子が比較をする際に型付けを<strong>強制</strong>するという意味です。</p>
<pre><code>"" == "0" // false
0 == "" // true
0 == "0" // true
false == "false" // false
false == "0" // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true
</code></pre>
<p>上記の表では型強制の結果が表示されています。<code>==</code>の使用が一般に悪い習慣とみなされる大きな理由として、変換ルールが複雑な為、バグの追跡が困難になる事が挙げられます。</p>
<p>加えて、型強制が行なわれるとパフォーマンスにも影響してしまいます。例えば、文字列は他の数字と比較する前に数値に変換されなければなりません。</p>
</div><div><h3>厳密等価演算子</h3>