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
|
---
title: Una re-introducció a JavaScript (tutorial JS)
slug: Web/JavaScript/A_re-introduction_to_JavaScript
translation_of: Web/JavaScript/A_re-introduction_to_JavaScript
---
<div>{{jsSidebar}}</div>
<p id="Introducció">Per què una reintroducció? Perquè {{Glossary("JavaScript")}} és conegut per ser <a class="external" href="http://javascript.crockford.com/javascript.html">el llenguatge de programació més incomprès del món</a>. És ridiculitzat sovint categoritzant-lo de joguina, però darrera de la seva simplicitat enganyosa s'amaguen característiques molt potents. JavaScript s'utilitza per a un nombre increïble d'aplicacions d'alt perfil, fet que mostra que un coneixement profund d'aquesta tecnologia és una habilitat important per a qualsevol desenvolupador web o mòbil.</p>
<p>És útil començar amb una visió general de la història del llenguatge. JavaScript va ser creat el 1995 per Brendan Eich, enginyer de Netscape, i la primera versió va sortir amb Netscape 2 a principis de 1996. (Originalment s'anava a dir LiveScript, però en una decisió pot encertada de marqueting se li va canviar pel de JavaScript en un intent de capitalitzar la popularitat del llenguatge Java de Sun Microsystem -. tot i que els dos llenguatges tenen molt poc en comú. Això ha sigut, des de llavors, una font de confusió).</p>
<p>Alguns mesos més tard, Microsoft va llançar JScript, un llenguatge compatible amb Internet Explorer 3 semblant a JavaScript. Uns mesos més tard Netscape el va portar a <a class="external" href="http://www.ecma-international.org/">Ecma International</a>, una organització d'estandarització europea, i d'aquí en va sortir la primera edició de l'estandard {{Glossary("ECMAScript")}} d'aquell any. L'estandard va patir una important actualització a la <a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">tercera edició de l'ECMAScript </a>el 1999, i s'ha mantingut estable des de llavors. La quarta edició es va abandonar, degut a diferència sobre la complexitat del llenguatge. Moltes parts de la quarta edició van servir de base per a la 5ena edició de l'ECMAScript , publicada el Desembre de 2009, i per la 6ena i més gran versió de l'estandard, que es publicarà el 2015.</p>
<p>D'ara en endavant, per familiaritat, em referiré a l'ECMAScript com a "JavaScript".</p>
<p>Al contrari que la majoria de llenguatges de programació, JavaScript no té el concepte de "input" ( entrada) o "output" sortida. Està pensat per a ser executat com un llenguatge d'"script" sobre un entorn extern que l'acull i li proporciona els mecanismes per a la comunicació amb el món exterior. L'entorn més comú és el navegador, però l'intèrpret de JavaScript es pot trobar en una extensa llista d'altres llocs, incloent Adobe Acrobat, Abobe Photoshop, imatge SVG , Yahoo's Widget engine, entorns de la banda del servidor com <a href="http://nodejs.org/" title="nodejs.org">Node.js</a>, bases de dades NoSQL com <a href="http://couchdb.apache.org/">Apache CouchDB</a>, que es de codi obert, ordinadors integrats<span style="background-color: #ffffff; color: #4d4e53; font-family: open sans,arial,sans-serif; font-size: 14px; line-height: 21px;">, entorns d'escriptori sencers com </span><a href="http://www.gnome.org/" style="margin: 0px; padding: 0px; border: 0px; color: rgb(0, 149, 221); text-decoration: none; font-family: 'Open Sans', Arial, sans-serif; font-size: 14px; line-height: 21px; background-color: rgb(255, 255, 255);">GNOME</a><span style="background-color: #ffffff; color: #4d4e53; font-family: open sans,arial,sans-serif; font-size: 14px; line-height: 21px;"> (una de les GUIs pel sistema operatiu GNU/Linux més populars), i la llista segueix</span>.</p>
<h2 id="Visió_General">Visió General</h2>
<p>JavaScript és un llenguatge orientat a objectes dinàmic amb tipus i operadors, amb contructor estàndard d'objectes i mètodes. La seva sintaxi ve de llenguatges com ara Java i C, de manera que moltes de les estructures d'aquests llenguatges s'apliquen també a JavaScript. Una de les principals diferències és que JavaScript no té classes; En el seu lloc, la funcionalitat de classe s'aconsegueix mitjançant prototips d'objectes. L'altra diferència principal és que les funcions són objectes, donant a les funcions la capacitat de tenir codi executable i ser passat a una altre funció com qualsevol altre objecte.</p>
<p>Comencem per mirar el component bàsic de qualsevol idioma: els tipus. Els programes de JavaScript manipulen valors, i tots aquests valors pertanyen a un tipus. Els tipus de JavaScript són:</p>
<ul>
<li>{{jsxref("Number")}}</li>
<li>{{jsxref("String")}}</li>
<li>{{jsxref("Boolean")}}</li>
<li>{{jsxref("Function")}}</li>
<li>{{jsxref("Object")}}</li>
<li>{{jsxref("Symbol")}} (nou a la 6ena edició)</li>
</ul>
<p>... ah, i {{jsxref ("undefined")}} i {{jsxref ("nul")}}, que són ... una mica estranys. I les matrius {{jsxref ("arrays")}}, que són un tipus especial d'objecte. I {{jsxref ("Data")}} i {{jsxref ("RegExp")}}, que són objectes que tens de forma gratuïta. I per ser tècnicament precisos, les funcions són només un tipus especial d'objecte. Així que el diagrama tipus s'assembla més a això:</p>
<ul>
<li>{{jsxref("Number")}}</li>
<li>{{jsxref("String")}}</li>
<li>{{jsxref("Boolean")}}</li>
<li>{{jsxref("Symbol")}} (nou a l'edició 6)</li>
<li>{{jsxref("Object")}}
<ul>
<li>{{jsxref("Function")}}</li>
<li>{{jsxref("Array")}}</li>
<li>{{jsxref("Date")}}</li>
<li>{{jsxref("RegExp")}}</li>
</ul>
</li>
<li>{{jsxref("null")}}</li>
<li>{{jsxref("undefined")}}</li>
</ul>
<p>I també hi ha alguns tipus interns com aquest {{jsxref("Error")}} . Crec que ésmés senzill si ens quedem amb el primer diagrama.</p>
<h2 id="Nombres">Nombres</h2>
<p>Els nombres a JavaScript són "valors de 64-bit de doble precisió en format IEEE 754", d'acord amb l'especificació. Això té conseqüències interessants. No hi ha. No hi ha coses com "integer" (nombre enter) a JavaScript, així que et cal ser una mica curós amb la seva aritmètica si estàs acostumat a les operacions de C o Java. Compte amb coses com:</p>
<pre class="brush: js">0.1 + 0.2 == 0.30000000000000004
</pre>
<p>A la pràctica, els valors enters són tractats com sencers de 32 bits (i s'emmagatzemen d'aquesta manera en algunes implementacions de navegador), fet que pot ser important per a operacions bit a bit.</p>
<p>Els operadors aritmètics estàndard hi són implantats, inclou la suma, la resta, el mòdul (o el residu) i molts altres. També hi ha un objecte incorporat que em vaig oblidar d'esmentar anteriorment que s'anomena {{jsxref ("Math")}} per si vols realitzar funcions matemàtiques més avançades i valors de constants:.</p>
<pre class="brush: js">Math.sin(3.5);
var circumfrence = Math.PI * (r + r);
</pre>
<p>Pot convertir una cadena a un enter utilitzant la funció incorporada {{jsxref ("Global_Objects / parseInt", "parseInt ()")}}. Això pren com a base ( decimal, hexadecimal, ...) per a la conversió un segon argument opcional , que sempre s'ha de proporcionar</p>
<pre class="brush: js">parseInt("123", 10); // 123
parseInt("010", 10); // 10
</pre>
<p>Si no el proporciones, pots obtenir resultats sorprenents en els navegadors més antics (anteriors a 2013):</p>
<pre class="brush: js">parseInt("010"); // 8
</pre>
<p>Això passa perquè la funció {{jsxref ("Global_Objects / parseInt", "parseInt ()")}} tracta per defecte la cadena com un nombre octal degut al 0 inicial.</p>
<p>Si voleu convertir un nombre binari a un sencer, només cal canviar la base:</p>
<pre class="brush: js">parseInt("11", 2); // 3
</pre>
<p>De la mateixa manera, pot analitzar els nombres de coma flotant utilitzant la funció incorporada {{jsxref ("Global_Objects / parseFloat", "parseFloat ()")}} que fa servir sempre la base 10 a diferència del seu cosí {{jsxref ("Global_Objects / parseInt", "parseInt () ")}}.</p>
<p>També pot utilitzar l'operador unari + per convertir les cadenes amb nombre als seus valors :</p>
<pre class="brush: js">+ "42"; // 42
</pre>
<p>Un valor especial anomenat {{jsxref ("NaN")}} (abreviatura de "Not a Number") es retorna si la cadena no és un nombre:</p>
<pre class="brush: js">parseInt("hello", 10); // NaN
</pre>
<p><code>NaN</code> és toxic: si es proporciona com una entrada a qualsevol operació matemàtica el resultat també serà sempre NaN:</p>
<pre class="brush: js">NaN + 5; // NaN
</pre>
<p>Podeu provar NaN utilitzant al funció incorporada {{jsxref ("Global_Objects / isNaN", "isNaN ()")}}:</p>
<pre class="brush: js">isNaN(NaN); // true
</pre>
<p>JavaScript també té els valors especials com l'infinit {{jsxref ("Infinity")}} i també -infinity:</p>
<pre class="brush: js"> 1 / 0; // Infinity
-1 / 0; // -Infinity
</pre>
<p>Podeu provar Infinity, -Infinity i el valor NaN utilitzant la funció incorporada {{jsxref ("Global_Objects / isFinite", "isFinite ()")}} :</p>
<pre class="brush: js">isFinite(1/0); // false
isFinite(-Infinity); // false
isFinite(NaN); // false
</pre>
<div class="note"><strong>Nota:</strong> Les funcions {{jsxref ("Global_Objects / parseInt", "parseInt ()")}} i {{jsxref ("Global_Objects / parseFloat", "parseFloat ()")}} analitzen una cadena fins que arriben a un caràcter que no és nombre vàlid pel format especificat, i torna el resultat de l'anàlisis fins a aquest moment. No obstant això, l'operador "+" senzillament converteix la cadena a NaN si hi ha algun caràcter no vàlid en ella. Només cal que intenti analitzar la cadena "10.2abc" amb cada mètode a la consola i entredrà millor les diferències.</div>
<h2 id="Cadenes">Cadenes</h2>
<p>Les cadenes a JavaScript són seqüències de caràcters. Més exactament, són seqüències de caràcters Unicode, amb cada caràcter representat per un nombre de 16 bits. Això hauria de ser una bona notícia per a qualsevol persona que ha hagut de lidiar amb la internacionalització.</p>
<p>Si vol representar un sol caràcter, només ha d'utilitzar una cadena de longitud 1.</p>
<p>Per trobar la longitud d'una cadena, pot accedir a la seva propietat ( atribut) length:</p>
<pre class="brush: js">"hello".length; // 5
</pre>
<p>Aquí tenim la nostra primera topoda amb objectes JavaScript! He esmentat que pot fer servir cadenes com {{jsxref ("objecte", "objectes", "", 1)}} Tenen {{jsxref ("String", "mètodes", "#Methods", 1)}}, que li permeten manipular la informació de la cadena i l'accés a la cadena:</p>
<pre class="brush: js">"hello".charAt(0); // "h"
"hello, world".replace("hello", "goodbye"); // "goodbye, world"
"hello".toUpperCase(); // "HELLO"
</pre>
<h2 id="Altres_Tipus">Altres Tipus</h2>
<p>JavaScript distingeix entre {{jsxref ("nul")}}, que és un valor que indica un no-valor deliberat (i només és accessible a través de la paraula clau null), i {{jsxref ("indefinit")}}, que és un valor de tipus 'indefinit' que indica un valor no inicialitzat - és a dir, un valor que ni tan sols s'ha assignat encara. Parlarem de les variables més tard, però a JavaScript, és possible declarar una variable sense assignar un valor a la mateixa. Si fa això, el tipus de la variable no està definida. indefinit és en realitat una constant.</p>
<p>JavaScript té un tipus booleà, amb possibles valors vertaders i falsos (que són paraules clau). Qualsevol valor pot ser convertit a un valor booleà d'acord amb les següents regles:</p>
<ol>
<li><code>false</code>, <code>0</code>, cadena buida (<code>""</code>), <code>NaN</code>, <code>null</code>, i <code>undefined</code> tots donant com a resultat <code>false.</code></li>
<li>Tots els altres valors es considern <code>true.</code></li>
</ol>
<p>Pot dur a terme aquesta conversió utilitzant de manera explícita la funció Boolean ():</p>
<pre class="brush: js">Boolean(""); // false
Boolean(234); // true
</pre>
<p>De totes maneres, no sol ser necessari, Javascript fa aquesta conversió automàticament quan s'espera un booleà, com en una sentència if (veure més avall). Per aquesta raó, de vegades parlem senzillamentt de "valors vertaders" i "valors falsos", és a dir els valors que esdevenen vertaders i falsos, respectivament, quan es converteixen en booleans. Aquests valors poden es poden dir "Truthy" i "Falsy", respectivament.</p>
<p>Operacions booleanes com && (AND lògic), || (o lògica), i! (Lògic no) també estan incorporats; Skip. Veure més avall.</p>
<h2 id="Variables">Variables</h2>
<p>Les noves variables a JavaScript es declaren fent servir la paraula clau var:</p>
<pre class="brush: js">var a;
var name = "simon";
</pre>
<p>Si es declara una variable sense assignar un valor a la mateixa, el seu tipus no està definit.</p>
<p>Una diferència important amb altres llenguatges com ara Java és que a JavaScript els blocs no tenen un "scope" (àmbit a on tenen un valor assignat) ( ; només les funcions tenen àmbit d'aplicació. Així que si una variable es defineix fent servir var en una sentència composta (per exemple, dins d'una estructura de control "if"), serà visible a tota la funció. No obstant això, a partir de ECMAScript Edition 6, es permeten les declaracions const que permetrar crear variables amb ambit d'assignació.</p>
<h2 id="Operadors">Operadors</h2>
<p>Els Operadors numèrics de JavaScript són +, -, *, / i% - que és l'operador del reste de la divisió. Els valors s'assignen utilitzant =, i també hi ha instruccions d'assignació compostos com += i -=. Aquests últims equivalen a x = x operador i.</p>
<pre class="brush: js">x += 5
x = x + 5 //equival a l'operador anterior
</pre>
<p>Podeu utilitzar ++ i - per augmentar i decrèixer, respectivament. Poden ser usats com a operadors de prefix o sufix.</p>
<p>L'operador + també serveix per a la concatenació de cadenes:</p>
<pre class="brush: js">"hello" + " world"; // "hello world"
</pre>
<p>Si s'agrega una cadena a un nombre (o un altre valor) tot es converteix a cadena su el primer valor és la cadena . Si no, primer s'operen el nombre i després es converteix a cadena:</p>
<pre class="brush: js">"3" + 4 + 5; // "345"
3 + 4 + "5"; // "75"
</pre>
<p>Afegir una cadena buida a alguna cosa és una forma útil per a la seva conversió.</p>
<p>Les comparacions a JavaScript es poden fer usant <, >, <= i >= . Aquests funcionen tant per cadenes com per nombres. L' "igual a" és una mica més complicatl. El doble igual fa la conversió al mateix tipus si són diferents i després compara els valors . Això, de vegades, suposa resultats interessants:</p>
<pre class="brush: js">"dog" == "dog"; // true
1 == true; // true
</pre>
<p>Per tenir em compte el tipus en la comparació , utilitza l'operador triple igual:</p>
<pre class="brush: js">1 === true; // false
true === true; // true
</pre>
<p>Hi ha tamble l'operador contrari <code>!=</code> i contrari estricte <code>!==</code> .</p>
<p>JavaScript té també operacions bit a bit. Si voleu utilitzar-les, allà estan.</p>
<h2 id="Estructures_de_control">Estructures de control</h2>
<p>JavaScript té un conjunt similar d'estructures de control a altres idiomes de la família C. Les sentències condicionals es fan a partir d' "if", i "else" ; ès poden encadenar si et convé:</p>
<pre class="brush: js">var name = "kittens";
if (name == "puppies") {
name += "!";
} else if (name == "kittens") {
name += "!!";
} else {
name = "!" + name;
}
name == "kittens!!"
</pre>
<p>JavaScript té bucles while i do-while. El primer d'ells és bo per bucles bàsics; el segon pels bucles que vol que s'executin com a mínim una vegada:</p>
<pre class="brush: js">while (true) {
// an infinite loop!
}
var input;
do {
input = get_input();
} while (inputIsNotValid(input))
</pre>
<p>El bucle "for" és el mateix que a C i Java: se li permet proporcionar la informació de control del bucle en una sola línia.</p>
<pre class="brush: js">for (var i = 0; i < 5; i++) {
// Will execute 5 times
}
</pre>
<p>Els operadors && i || fan servir la lògica de curtcircuit, això significa que el segon operant depèn de la primer. Això és útil per exemple per comprovar que els objectes no siguin nuls abans d'accedir als seus atributs:</p>
<pre class="brush: js">var name = o && o.getName();
</pre>
<p>O per donar valors per defecte:</p>
<pre class="brush: js">var name = otherName || "default";
</pre>
<p>JavaScript té un operador ternari per expressions condicionals:</p>
<pre class="brush: js">var allowed = (age > 18) ? "yes" : "no";
</pre>
<p>La declaració switch pot ser utilitzat per comparar amb múltiples branques basades en nombres o cadenes:</p>
<pre class="brush: js">switch(action) {
case 'draw':
drawIt();
break;
case 'eat':
eatIt();
break;
default:
doNothing();
}
</pre>
<p>Si no afegeix una sentència break, l'execució "cauen al" següent nivell. Això rares vegades serà el que voldrà - de fet val la pena etiquetar específicament aquest "fallthrough" deliberat si és el cas amb un comentari per ajudar a la depuració:</p>
<pre class="brush: js">switch(a) {
case 1: // fallthrough
case 2:
eatIt();
break;
default:
doNothing();
}
</pre>
<p>La clàusula d'incompliment és opcional. Pot tenir expressions, tant en la part del "switch" com la dels casos si vol; les comparacions es realitzen entre els dos fent servir l'operador ===:</p>
<pre class="brush: js">switch(1 + 3) {
case 2 + 2:
yay();
break;
default:
neverhappens();
}
</pre>
<h2 id="Objectes">Objectes</h2>
<p>Els objectes de JavaScript poden ser considerats com a simples col·leccions de parells nom-valor. Com a tals, són similars a:</p>
<ul>
<li>Dicdionaris a Python</li>
<li>Hashes in Perl and Ruby</li>
<li>Taules Hash a C i C++</li>
<li>HashMaps a Java</li>
<li>Matrius associades a PHP</li>
</ul>
<p>En realitat aquesta estructura de dades és fa ser tant que és una prova de la seva enorme versatilitat. Ja que tot (fins i tots els tipus bàsics) a JavaScript són objectes, qualsevol programa en JavaScript implica, naturalment, una gran quantitat d'operacions de recerca a taules hash. Éstà molt bé que siguin tan ràpids.</p>
<p>La part del "nom" és una cadena JavaScript, mentre que la part del " valor" pot ser qualsevol valor de Javascript - incloent altres objectes. Això li permet construir estructures de dades de la complexitat que es necessiti.</p>
<p>Hi ha dues formes bàsiques per crear un objecte buit:</p>
<pre class="brush: js">var obj = new Object();
</pre>
<p>I:</p>
<pre class="brush: js">var obj = {};
</pre>
<p>I....</p>
<pre class="brush: js">function Person(name, age) {
this.name = name;
this.age = age;
}
// Defineix un objecte
var You = new Person("You", 24);
// Estem creant una nova persona amb el nom "You"
// (que serà el primer paràmetre, i l'edat..)
</pre>
<p>Aquestes formes són semànticament equivalents; la segona es diu sintaxi literal d'objecte, i és la més convenient. Aquesta sintaxi és també el nucli de format JSON i s'ha de preferir en tot moment.</p>
<p>Un cop creat un objecte , és pot accedir a les seves propietats de nou d'una d'aquestes dues maneres:</p>
<pre class="brush: js">obj.name = "Simon";
var name = obj.name;
</pre>
<p>I...</p>
<pre class="brush: js">obj["name"] = "Simon";
var name = obj["name"];
</pre>
<p>Aquestes dues, també són semànticament equivalents. El segon mètode té l'avantatge que el nom de la propietat s'ofereix com una cadena, el que significa que es pot calcular en temps d'execució, encara que l'ús d'aquest mètode evita que algunes optimitzacions de motor JavaScript i Minifier s'apliquin. També es pot utilitzar per definir i obtenir propietats amb noms que són paraules reservades o que tenen espais:</p>
<pre class="brush: js">obj.for = "Simon"; // Syntax error, perque 'for' es una paraula reservada
obj["for"] = "Simon"; // funciona
</pre>
<div class="note">
<p><span style="color: #222222; font-family: verdana,arial,sans-serif; font-size: 12px; line-height: 18px;"><strong>Nota:</strong></span>A partir d'EcmaScript 5, les paraules reservades es poden usar com a noms de propietats d'objecte "en l'aficionat". Això significa que no necessiten ser posades "entre cometes" a l'hora de definir objectes literals. Veure ES5 Spec.</p>
</div>
<p>La sintaxi d'objecte literal es pot fer servir per inicialitzar un objecte totalment:</p>
<pre class="brush: js">var obj = {
name: "Carrot",
"for": "Max",
details: {
color: "orange",
size: 12
}
}
</pre>
<p>L'accès als atributs pot ser encadenat:</p>
<pre class="brush: js">obj.details.color; // orange
obj["details"]["size"]; // 12
</pre>
<h2 id="Matrius">Matrius</h2>
<p>Les matrius a Javascript són en realitat un tipus especial d'objecte. Treballen de manera molt semblant als objectes normals ( naturalment a les seves propietats només es pot accedir mitjançant la sintaxi de claudàtors []) però tenen una propietat màgica anomenada "length" (llargada) , que sempre és un nombre més que l'índex més alt de la matriu.</p>
<p>Una forma de creació de matrius és la següent:</p>
<pre class="brush: js">var a = new Array();
a[0] = "dog";
a[1] = "cat";
a[2] = "hen";
a.length; // 3
</pre>
<p>Una notació més convenient és utilitzar una matriu literal:</p>
<pre class="brush: js">var a = ["dog", "cat", "hen"];
a.length; // 3
</pre>
<p>Recordeu que array.length no és necessàriament el nombre d'elements de la matriu. Considera el següent:</p>
<pre class="brush: js">var a = ["dog", "cat", "hen"];
a[100] = "fox";
a.length; // 101
</pre>
<p>Recordi - la longitud de la matriu és un nombre més que l'índex més alt.</p>
<p>Si es consulta un índex de matriu que no existeix, s'obté indefinit:</p>
<pre class="brush: js">typeof a[90]; // indefinit
</pre>
<p>Si es té en compte l'anterior, es pot iterar sobre una matriu mitjançant el següent:</p>
<pre class="brush: js">for (var i = 0; i < a.length; i++) {
// Fer alguna cosa amb a[i]
}
</pre>
<p>Això és una mica ineficient si cada passada del bucle ha de calcular la "length". És pot millorar fent:</p>
<pre class="brush: js">for (var i = 0, len = a.length; i < len; i++) {
// Do something with a[i]
}
</pre>
<p>Una forma més maca, tot i que amb limitacions, seria:</p>
<pre class="brush: js">for (var i = 0, item; item = a[i++];) {
// Do something with item
}
</pre>
<p>Aquí estem creant dues variables. L'assignació a la part del mig del bucle també és comprova si es "true" - si això és així, el bucle continua. Després i es va incrementant, els elements de la matriu seran assignats a "item" en ordre seqüencial. El bucle es deté quan es troba que "item" és un element "Falsy"( per tant no definit).</p>
<p>Aquest truc només s'ha d'utilitzar per a les matrius que sap que no contenen valors "Falsy" (arrays d'objectes o {{Glossary("DOM")}} nodes, per exemple). Si està iterant sobre dades numèriques que podria incloure una dada 0 o una cadena que podria incloure la cadena buida s'ha d'utilitzar l'i, amb "len".</p>
<p>Pot iterar sobre una matriu usant un bucle for ... in. Recordeu que si algú afegeix noves propietats a Array.prototype, també es repetiran al llarg d'aquest bucle. Per tant "no" es recomana aquest mètode.</p>
<p>Una altra forma d'iterar sobre una matriu que s'ha afegit amb ECMAScript 5 és foreach ():</p>
<pre class="brush: js" style="font-size: 14px;">["dog", "cat", "hen"].forEach(function(currentValue, index, array) {
// Fer alguan cosa amb el valoractual o matriu[index]
});
</pre>
<p>Si vol afegir un element a una matriu simplement pot fer-ho d'aquesta manera:</p>
<pre class="brush: js">a.push(item);</pre>
<p>Les matrius vénen amb una sèrie de mètodes. Mira també la documentació completa pels mètodes de matriu.</p>
<table>
<thead>
<tr>
<th scope="col">Method name</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>a.toString()</code></td>
<td>Retorna una cadena amb el mètode toString () a on cada element esta separat per comes.</td>
</tr>
<tr>
<td><code>a.toLocaleString()</code></td>
<td>Retorna una cadena amb el toLocaleString () a on cada element està separat per comes.</td>
</tr>
<tr>
<td><code>a.concat(item1[, item2[, ...[, itemN]]])</code></td>
<td>Retorna una nova matriu amb els elements agregats a ella.</td>
</tr>
<tr>
<td><code>a.join(sep)</code></td>
<td>Converteix la matriu en una matriu amb valord de cadena separats entre ells pel paràmetre sep</td>
</tr>
<tr>
<td><code>a.pop()</code></td>
<td>Elimina i retorna l'últim element.</td>
</tr>
<tr>
<td><code>a.push(item1, ..., itemN)</code></td>
<td><code>Push</code> afegeix un o més elements al final.</td>
</tr>
<tr>
<td><code>a.reverse()</code></td>
<td>Inverteix la matriu.</td>
</tr>
<tr>
<td><code>a.shift()</code></td>
<td>Elimina i retorna el primer element.</td>
</tr>
<tr>
<td><code>a.slice(start, end)</code></td>
<td>Retorna una sub-matriu.</td>
</tr>
<tr>
<td><code>a.sort([cmpfn])</code></td>
<td>Pren una funció de comparació opcional.</td>
</tr>
<tr>
<td><code>a.splice(start, delcount[, item1[, ...[, itemN]]])</code></td>
<td>Li permet modificar una matriu mitjançant la supressió d'una secció i reemplaçar-la amb més elements.</td>
</tr>
<tr>
<td><code>a.unshift([item])</code></td>
<td>Afegeix items a l'inici de la matriu.</td>
</tr>
</tbody>
</table>
<h2 id="Funcions">Funcions</h2>
<p>Juntament amb els objectes, les funcions són el component central en la comprensió de JavaScript. La funció més bàsica no podria ser molt més simple:</p>
<pre class="brush: js">function add(x, y) {
var total = x + y;
return total;
}
</pre>
<p>Això demostra tot el que cal saber sobre les funcions bàsiques. Una funció de JavaScript pot tenir 0 o més paràmetres. El cos de la funció pot contenir tantes declaracions com es vulgui, i pot declarar les seves pròpies variables que són locals per a aquesta funció. La sentència return es pot utilitzar per tornar un valor en qualsevol moment i acabar la funció. Si no s'utilitza cap sentència return (o una declaració buida sense valor), JavaScript retorna undefined.</p>
<p>Els paràmetres amb nom resulten ser més com directrius que res mes. Pot cridar ("call") una funció sense passar els paràmetres que espera, en aquest cas és passaran com indefinits.</p>
<pre class="brush: js">add(); // NaN
//No pots fer una suma amb un valor indefinit
</pre>
<p>També és pot passar més arguments dels que la funció espera:</p>
<pre class="brush: js">add(2, 3, 4); // 5
// ha sumat els dos primers; el 4 ha sigut ignorat
</pre>
<p>Això pot semblar una mica ximple, però les funcions tenen accés a variables addicional dins del seu cos que s'anomenen arguments, que és com una matriu amb tots els valors passats a la funció. Tornem a escriure la funció add perque accepti tants valors com es vulgui:</p>
<pre class="brush: js">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>Penso que això no és més eficaç que escriure <code>2 + 3 + 4 + 5</code>. Creem una funció més útil, calcular el promig:</p>
<pre class="brush: js">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>Això és molt més útil, peró introdueix un nou problema. La funció avg () pren una llista d'argument separada per comes - però que passa si vol trobar la mitjana d'una matriu? Podria reescriure la funció de la següent manera:</p>
<pre class="brush: js">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>Però seria bo poder tornar a utilitzar la funció que ja hem creat. Per sort, JavaScript li permet cridar a una funció i cridar-la amb una sèrie arbitrària d'arguments, utilitzant el mètode {{jsxref ("Function.apply", "apply ()")}} de qualsevol objecte de funció.</p>
<pre class="brush: js">avg.apply(null, [2, 3, 4, 5]); // 3.5
</pre>
<p>El segon argument per apply () és la matriu que fem servir com a argument; el primer es discutirà més endavant. Això posa en relleu el fet que les funcions són objectes també.</p>
<p>JavaScript li deixa creas funcions anònimes.</p>
<pre class="brush: js">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>Aquesta és semànticament equivalent a la forma funció avg (). És molt potent, ja que li permet posar una definició de funció completa en qualsevol lloc, fins i tot on normalment si posa una expressió. Això permet tot tipus de trucs enginyosos. Aquí té una manera d '"amagar" algunes variables locals - àmbit de bloc com en C:</p>
<pre class="brush: js">var a = 1;
var b = 2;
(function() {
var b = 3;
a += b;
})();
a; // 4
b; // 2
</pre>
<p>JavaScript li permet cridar a funcions de forma recursiva. Això és particularment útil per fer front a les estructures d'arbre, com la que s'obté en el navegador DOM.</p>
<pre class="brush: js">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>Això posa en relleu un problema potencial amb funcions anònimes: com cridar-les de forma recursiva si no tenen un nom? JavaScript permet gravar en una expressió el nom de la funció . Podeu utilitzar noms IIFEs (Expressions de funció Immediatament invocats) com a continuació:</p>
<pre class="brush: js">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>El nom proporcionat a una expressió de funció com l'anterior només està disponible pel propi àmbit de la funció. Això permet tant que el motor pugui optimitzar més l'execució un codi més llegible. El nom també apareix en el depurador i en alguns seguiments de pila poden estalviar-li temps.</p>
<p>Recordeu que les funcions de JavaScript són en si mateixes objectes i se les hi pot afegir o canviar les propietats igual que en els objectes que hem vist a la secció Objectes</p>
<h2 id="Custom_objects">Custom objects</h2>
<div class="note"><strong>Note:</strong> For a more detailed discussion of object-oriented programming in JavaScript, see <a href="/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript" title="https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript">Introduction to Object Oriented JavaScript</a>.</div>
<p>In classic Object Oriented Programming, objects are collections of data and methods that operate on that data. JavaScript is a prototype-based language which contains no class statement, such as is found in C++ or Java. (This is sometimes confusing for programmers accustomed to languages with a class statement.) Instead, JavaScript uses functions as classes. Let's consider a person object with first and last name fields. There are two ways in which the name might be displayed: as "first last" or as "last, first". Using the functions and objects that we've discussed previously, here's one way of doing it:</p>
<pre class="example-bad brush: js">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;
}
s = makePerson("Simon", "Willison");
personFullName(s); // "Simon Willison"
personFullNameReversed(s); "Willison, Simon"
</pre>
<p>This works, but it's pretty ugly. You end up with dozens of functions in your global namespace. What we really need is a way to attach a function to an object. Since functions are objects, this is easy:</p>
<pre class="brush: js">function makePerson(first, last) {
return {
first: first,
last: last,
fullName: function() {
return this.first + ' ' + this.last;
},
fullNameReversed: function() {
return this.last + ', ' + this.first;
}
};
}
s = makePerson("Simon", "Willison")
s.fullName(); // "Simon Willison"
s.fullNameReversed(); // "Willison, Simon"
</pre>
<p>There's something here we haven't seen before: the <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/this" title="/en/JavaScript/Reference/Operators/this">this</a></code> keyword. Used inside a function, <code>this</code> refers to the current object. What that actually means is specified by the way in which you called that function. If you called it using <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Accessing_properties" title="/en/JavaScript/Reference/Operators/Member_Operators">dot notation or bracket notation</a> on an object, that object becomes <code>this</code>. If dot notation wasn't used for the call, <code>this</code> refers to the global object.</p>
<p>Note that <code>this</code> is a frequent cause of mistakes. For example:</p>
<pre class="brush: js">s = makePerson("Simon", "Willison");
var fullName = s.fullName;
fullName(); // undefined undefined
</pre>
<p>When we call <code>fullName()</code> alone, without using <code>s.fullName()</code>, <code>this</code> is bound to the global object. Since there are no global variables called <code>first</code> or <code>last</code> we get <code>undefined</code> for each one.</p>
<p>We can take advantage of the <code>this</code> keyword to improve our <code>makePerson</code> function:</p>
<pre class="brush: js">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>We have introduced another keyword: <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/new" title="/en/JavaScript/Reference/Operators/new">new</a></code>. <code>new</code> is strongly related to <code>this</code>. What it does is it creates a brand new empty object, and then calls the function specified, with <code>this</code> set to that new object. Notice though that the function specified with <code>this</code> does not return a value but merely modifies the <code>this</code> object. It's <code><code> </code>new</code> that returns the <code>this</code> object to the calling site. Functions that are designed to be called by <code>new</code> are called constructor functions. Common practice is to capitalize these functions as a reminder to call them with <code>new</code>.</p>
<p>The improved function still has the same pitfall with calling <code>fullName()</code> alone.</p>
<p>Our person objects are getting better, but there are still some ugly edges to them. Every time we create a person object we are creating two brand new function objects within it — wouldn't it be better if this code was shared?</p>
<pre class="brush: js">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>That's better: we are creating the method functions only once, and assigning references to them inside the constructor. Can we do any better than that? The answer is yes:</p>
<pre class="brush: js">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> is an object shared by all instances of <code>Person</code>. It forms part of a lookup chain (that has a special name, "prototype chain"): any time you attempt to access a property of <code>Person</code> that isn't set, JavaScript will check <code>Person.prototype</code> to see if that property exists there instead. As a result, anything assigned to <code>Person.prototype</code> becomes available to all instances of that constructor via the <code>this</code> object.</p>
<p>This is an incredibly powerful tool. JavaScript lets you modify something's prototype at any time in your program, which means you can add extra methods to existing objects at runtime:</p>
<pre class="brush: js">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>Interestingly, you can also add things to the prototype of built-in JavaScript objects. Let's add a method to <code>String</code> that returns that string in reverse:</p>
<pre class="brush: js">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>Our new method even works on string literals!</p>
<pre class="brush: js">"This can now be reversed".reversed(); // desrever eb won nac sihT
</pre>
<p>As I mentioned before, the prototype forms part of a chain. The root of that chain is <code>Object.prototype</code>, whose methods include <code>toString()</code> — it is this method that is called when you try to represent an object as a string. This is useful for debugging our <code>Person</code> objects:</p>
<pre class="brush: js">var s = new Person("Simon", "Willison");
s; // [object Object]
Person.prototype.toString = function() {
return '<Person: ' + this.fullName() + '>';
}
s.toString(); // "<Person: Simon Willison>"
</pre>
<p>Remember how <code>avg.apply()</code> had a null first argument? We can revisit that now. The first argument to <code>apply()</code> is the object that should be treated as '<code>this</code>'. For example, here's a trivial implementation of <code>new</code>:</p>
<pre class="brush: js">function trivialNew(constructor, ...args) {
var o = {}; // Create an object
constructor.apply(o, args);
return o;
}
</pre>
<p>This isn't an exact replica of <code>new</code> as it doesn't set up the prototype chain (it would be difficult to illustrate). This is not something you use very often, but it's useful to know about. In this snippet, <code>...args</code> (including the ellipsis) is called the "<a href="/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest arguments</a>" – as the name implies, this contains the rest of the arguments.</p>
<p>Calling</p>
<pre class="brush: js">var bill = trivialNew(Person, "William", "Orange");</pre>
<p>is therefore almost equivalent to</p>
<pre class="brush: js">var bill = new Person("William", "Orange");</pre>
<p><code>apply()</code> has a sister function named <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call" title="/en/JavaScript/Reference/Global_Objects/Function/call"><code>call</code></a>, which again lets you set <code>this</code> but takes an expanded argument list as opposed to an array.</p>
<pre class="brush: js">function lastNameCaps() {
return this.last.toUpperCase();
}
var s = new Person("Simon", "Willison");
lastNameCaps.call(s);
// Is the same as:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();
</pre>
<h3 id="Inner_functions">Inner functions</h3>
<p>JavaScript function declarations are allowed inside other functions. We've seen this once before, with an earlier <code>makePerson()</code> function. An important detail of nested functions in JavaScript is that they can access variables in their parent function's scope:</p>
<pre class="brush: js">function betterExampleNeeded() {
var a = 1;
function oneMoreThanA() {
return a + 1;
}
return oneMoreThanA();
}
</pre>
<p>This provides a great deal of utility in writing more maintainable code. If a function relies on one or two other functions that are not useful to any other part of your code, you can nest those utility functions inside the function that will be called from elsewhere. This keeps the number of functions that are in the global scope down, which is always a good thing.</p>
<p>This is also a great counter to the lure of global variables. When writing complex code it is often tempting to use global variables to share values between multiple functions — which leads to code that is hard to maintain. Nested functions can share variables in their parent, so you can use that mechanism to couple functions together when it makes sense without polluting your global namespace — 'local globals' if you like. This technique should be used with caution, but it's a useful ability to have.</p>
<h2 id="Closures">Closures</h2>
<p>This leads us to one of the most powerful abstractions that JavaScript has to offer — but also the most potentially confusing. What does this do?</p>
<pre class="brush: js">function makeAdder(a) {
return function(b) {
return a + b;
};
}
var x = makeAdder(5);
var y = makeAdder(20);
x(6); // ?
y(7); // ?
</pre>
<p>The name of the <code>makeAdder</code> function should give it away: it creates new 'adder' functions, which when called with one argument add it to the argument that they were created with.</p>
<p>What's happening here is pretty much the same as was happening with the inner functions earlier on: a function defined inside another function has access to the outer function's variables. The only difference here is that the outer function has returned, and hence common sense would seem to dictate that its local variables no longer exist. But they <em>do</em> still exist — otherwise the adder functions would be unable to work. What's more, there are two different "copies" of <code>makeAdder</code>'s local variables — one in which <code>a</code> is 5 and one in which <code>a</code> is 20. So the result of those function calls is as follows:</p>
<pre class="brush: js">x(6); // returns 11
y(7); // returns 27
</pre>
<p>Here's what's actually happening. Whenever JavaScript executes a function, a 'scope' object is created to hold the local variables created within that function. It is initialised with any variables passed in as function parameters. This is similar to the global object that all global variables and functions live in, but with a couple of important differences: firstly, a brand new scope object is created every time a function starts executing, and secondly, unlike the global object (which is accessible as <code>this</code> and in browsers is accessible as <code>window</code>) these scope objects cannot be directly accessed from your JavaScript code. There is no mechanism for iterating over the properties of the current scope object, for example.</p>
<p>So when <code>makeAdder</code> is called, a scope object is created with one property: <code>a</code>, which is the argument passed to the <code>makeAdder</code> function. <code>makeAdder</code> then returns a newly created function. Normally JavaScript's garbage collector would clean up the scope object created for <code>makeAdder</code> at this point, but the returned function maintains a reference back to that scope object. As a result, the scope object will not be garbage collected until there are no more references to the function object that <code>makeAdder</code> returned.</p>
<p>Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript's object system.</p>
<p>A closure is the combination of a function and the scope object in which it was created.</p>
<p>Closures let you save state — as such, they can often be used in place of objects. Several excellent introductions to closures can be found <a href="http://stackoverflow.com/questions/111102/how-do-javascript-closures-work">here</a>.</p>
<h3 id="Memory_leaks">Memory leaks</h3>
<p>An unfortunate side effect of closures is that they make it trivially easy to leak memory in Internet Explorer. JavaScript is a garbage collected language — objects are allocated memory upon their creation and that memory is reclaimed by the browser when no references to an object remain. Objects provided by the host environment are handled by that environment.</p>
<p>Browser hosts need to manage a large number of objects representing the HTML page being presented — the objects of the DOM. It is up to the browser to manage the allocation and recovery of these.</p>
<p>Internet Explorer uses its own garbage collection scheme for this, separate from the mechanism used for JavaScript. It is the interaction between the two that can cause memory leaks.</p>
<p>A memory leak in IE occurs any time a circular reference is formed between a JavaScript object and a native object. Consider the following:</p>
<pre class="example-bad brush: js">function leakMemory() {
var el = document.getElementById('el');
var o = { 'el': el };
el.o = o;
}
</pre>
<p>The circular reference formed above creates a memory leak; IE will not free the memory used by <code>el</code> and <code>o</code> until the browser is completely restarted.</p>
<p>The above case is likely to go unnoticed; memory leaks only become a real concern in long running applications or applications that leak large amounts of memory due to large data structures or leak patterns within loops.</p>
<p>Leaks are rarely this obvious — often the leaked data structure can have many layers of references, obscuring the circular reference.</p>
<p>Closures make it easy to create a memory leak without meaning to. Consider this:</p>
<pre class="example-bad brush: js">function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
el.style.backgroundColor = 'red';
};
}
</pre>
<p>The above code sets up the element to turn red when it is clicked. It also creates a memory leak. Why? Because the reference to <code>el</code> is inadvertently caught in the closure created for the anonymous inner function. This creates a circular reference between a JavaScript object (the function) and a native object (<code>el</code>).</p>
<p>There are a number of workarounds for this problem. The simplest is not to use the <code>el</code> variable:</p>
<pre class="example-good brush: js">function addHandler(){
document.getElementById('el').onclick = function(){
this.style.backgroundColor = 'red';
};
}
</pre>
<p>Surprisingly, one trick for breaking circular references introduced by a closure is to add another closure:</p>
<pre class="brush: js">function addHandler() {
var clickHandler = function() {
this.style.backgroundColor = 'red';
};
(function() {
var el = document.getElementById('el');
el.onclick = clickHandler;
})();
}
</pre>
<p>The inner function is executed straight away, and hides its contents from the closure created with <code>clickHandler</code>.</p>
<p>Another good trick for avoiding closures is breaking circular references during the <code>window.onunload</code> event. Many event libraries will do this for you. Note that doing so disables the <a href="/en-US/docs/Working_with_BFCache" title="En/Using_Firefox_1.5_caching">back-forward cache in Firefox</a>, so you should not register an <code>unload</code> listener in Firefox, unless you have other reasons to do so.</p>
|