0% found this document useful (0 votes)
19K views

A Re-Introduction To JavaScript (JS Tutorial) - JavaScript - MDN

This document provides an introduction and overview of JavaScript. It discusses JavaScript's history, uses, basic data types including numbers, strings, booleans, and variables. It also covers operators, comparisons, and functions. JavaScript was created in 1995 and first released in 1996 as a scripting language to run in web browsers. It has since expanded to be used in many other environments like Node.js and mobile apps.

Uploaded by

bmkmanoj
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19K views

A Re-Introduction To JavaScript (JS Tutorial) - JavaScript - MDN

This document provides an introduction and overview of JavaScript. It discusses JavaScript's history, uses, basic data types including numbers, strings, booleans, and variables. It also covers operators, comparisons, and functions. JavaScript was created in 1995 and first released in 1996 as a scripting language to run in web browsers. It has since expanded to be used in many other environments like Node.js and mobile apps.

Uploaded by

bmkmanoj
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

A re-introduction to JavaScript (JS

tutorial)
by109contributors:

Showall

Introduction
Whyareintroduction?BecauseJavaScriptisnotoriousforbeing theworld'smostmisunderstood
programminglanguage.Whileitisoftenderidedasatoy,beneathitsdeceptivesimplicityliesomepowerful
languagefeatures.JavaScriptisnowusedbyanincrediblenumberofhighprofileapplications,showingthat
deeperknowledgeofthistechnologyisanimportantskillforanywebormobiledeveloper.
It'susefultostartwithanoverviewofthelanguage'shistory.JavaScriptwascreatedin1995byBrendan
Eich,anengineeratNetscape,andfirstreleasedwithNetscape2earlyin1996.(Itwasoriginallygoingtobe
calledLiveScript,butwasrenamedinanillfatedmarketingdecisioninanattempttocapitalizeonthe
popularityofSunMicrosystem'sJavalanguagedespitethetwohavingverylittleincommon.Thishas
beenasourceofconfusioneversince.)
Severalmonthslater,MicrosoftreleasedJScript,amostlycompatibleJavaScriptworkalike,withInternet
Explorer3.Severalmonthsafterthat,NetscapesubmittedJavaScriptto EcmaInternational,aEuropean
standardsorganization,whichresultedinthefirsteditionoftheECMAScriptstandardthatyear.The
standardreceivedasignificantupdateas ECMAScriptedition3in1999,andhasstayedprettymuchstable
eversince.Thefourtheditionwasabandoned,duetopoliticaldifferencesconcerninglanguagecomplexity.
ManypartsofthefourtheditionformedthebasisforECMAScriptedition5,publishedinDecemberof2009,
andforthe6thmajoreditionofthestandard,waspublishedinJuneof2015.
Forfamiliarity,IwillrefertoECMAScriptas"JavaScript"fromthispointon.
Unlikemostprogramminglanguages,theJavaScriptlanguagehasnoconceptofinputoroutput.Itis
designedtorunasascriptinglanguageinahostenvironment,anditisuptothehostenvironmentto
providemechanismsforcommunicatingwiththeoutsideworld.Themostcommonhostenvironmentisthe
browser,butJavaScriptinterpreterscanalsobefoundinahugelistofotherplaces,includingAdobe
Acrobat,AbobePhotoshop,SVGimages,Yahoo'sWidgetengine,serversideenvironmentssuchas
Node.js,NoSQLdatabasesliketheopensource ApacheCouchDB,embeddedcomputers,complete
desktopenvironmentslike GNOME(oneofthemostpopularGUIsforGNU/Linuxoperatingsystems),and

thelistgoeson.

Overview
JavaScriptisanobjectorienteddynamiclanguagewithtypesandoperators,standardbuiltinobjects,and
methods.ItssyntaxcomesfromtheJavaandClanguages,somanystructuresfromthoselanguagesapply
toJavaScriptaswell.OneofthekeydifferencesisthatJavaScriptdoesnothaveclassesinstead,theclass
functionalityisaccomplishedbyobjectprototypes.Theothermaindifferenceisthatfunctionsareobjects,
givingfunctionsthecapacitytoholdexecutablecodeandbepassedaroundlikeanyotherobject.
Let'sstartoffbylookingatthebuildingblockofanylanguage:thetypes.JavaScriptprogramsmanipulate
values,andthosevaluesallbelongtoatype.JavaScript'stypesare:
Number
String
Boolean
Function
Object
Symbol(newinEdition6)
...oh,andundefinedandnull,whichare...slightlyodd.AndArray,whichareaspecialkindofobject.And
DateandRegExp,whichareobjectsthatyougetforfree.Andtobetechnicallyaccurate,functionsarejusta
specialtypeofobject.Sothetypediagramlooksmorelikethis:
Number
String
Boolean
Symbol(newinEdition6)
Object
Function
Array
Date
RegExp
null
undefined

AndtherearesomebuiltinErrortypesaswell.Thingsarealoteasierifwestickwiththefirstdiagram,
though.

Numbers
NumbersinJavaScriptare"doubleprecision64bitformatIEEE754values",accordingtothespec.Thishas
someinterestingconsequences.There'snosuchthingasanintegerinJavaScript,soyouhavetobealittle
carefulwithyourarithmeticifyou'reusedtomathinCorJava.Watchoutforstufflike:

0.1+0.2==0.30000000000000004

Inpractice,integervaluesaretreatedas32bitints(andarestoredthatwayinsomebrowser
implementations),whichcanbeimportantforbitwiseoperations.
Thestandardarithmeticoperatorsaresupported,includingaddition,subtraction,modulus(orremainder)
arithmeticandsoforth.There'salsoabuiltinobjectthatIforgottomentionearliercalledMathifyouwantto
performmoreadvancedmathematicalfunctionsandconstants:

1
2

Math.sin(3.5);
varcircumference=Math.PI*(r+r);

YoucanconvertastringtoanintegerusingthebuiltinparseInt()function.Thistakesthebaseforthe
conversionasanoptionalsecondargument,whichyoushouldalwaysprovide:

1
2

parseInt("123",10);//123
parseInt("010",10);//10

Ifyoudon'tprovidethebase,youcangetsurprisingresultsinolderbrowsers(pre2013):

parseInt("010");//8

ThathappenedbecausetheparseInt()functiondecidedtotreatthestringasoctalduetotheleading0.
Ifyouwanttoconvertabinarynumbertoaninteger,justchangethebase:

parseInt("11",2);//3

Similarly,youcanparsefloatingpointnumbersusingthebuiltinparseFloat()functionwhichusesbase10
alwaysunlikeitsparseInt()cousin.
Youcanalsousetheunary+operatortoconvertvaluestonumbers:

+"42";//42

AspecialvaluecalledNaN(shortfor"NotaNumber")isreturnedifthestringisnonnumeric:

parseInt("hello",10);//NaN

NaNistoxic:ifyouprovideitasaninputtoanymathematicaloperationtheresultwillalsobeNaN:

NaN+5;//NaN

YoucantestforNaNusingthebuiltinisNaN()function:

isNaN(NaN);//true

JavaScriptalsohasthespecialvaluesInfinityandInfinity:

1
2

1/0;//Infinity
1/0;//Infinity

YoucantestforInfinity,InfinityandNaNvaluesusingthebuiltinisFinite()function:

1
2
3

isFinite(1/0);//false
isFinite(Infinity);//false
isFinite(NaN);//false

Note: The parseInt() and parseFloat() functions parse a string until they reach a character that
isn'tvalidforthespecifiednumberformat,thenreturnthenumberparseduptothatpoint.Howeverthe"+"operator

simplyconvertsthestringtoNaNifthereisanyinvalidcharacterinit.Justtryparsingthestring"10.2abc"witheach
methodbyyourselfintheconsoleandyou'llunderstandthedifferencesbetter.

Strings
StringsinJavaScriptaresequencesofcharacters.Moreaccurately,theyaresequencesofUnicode
characters,witheachcharacterrepresentedbya16bitnumber.Thisshouldbewelcomenewstoanyone
whohashadtodealwithinternationalization.
Ifyouwanttorepresentasinglecharacter,youjustuseastringoflength1.
Tofindthelengthofastring,accessitslengthproperty:

"hello".length;//5

There'sourfirstbrushwithJavaScriptobjects!DidImentionthatyoucanusestringslikeobjectstoo?They
havemethodsaswellthatallowyoutomanipulatethestringandaccessinformationaboutthestring:

1
2
3

"hello".charAt(0);//"h"
"hello,world".replace("hello","goodbye");//"goodbye,world"
"hello".toUpperCase();//"HELLO"

Othertypes
JavaScriptdistinguishesbetweennull,whichisavaluethatindicatesadeliberatenonvalue(andisonly
accessiblethroughthenullkeyword),andundefined,whichisavalueoftype'undefined'thatindicatesan
uninitializedvaluethatis,avaluehasn'tevenbeenassignedyet.We'lltalkaboutvariableslater,butin
JavaScriptitispossibletodeclareavariablewithoutassigningavaluetoit.Ifyoudothis,thevariable'stype
isundefined.undefinedisactuallyaconstant.
JavaScripthasabooleantype,withpossiblevaluestrueandfalse(bothofwhicharekeywords).Any
valuecanbeconvertedtoabooleanaccordingtothefollowingrules:
1. false,0,theemptystring(""),NaN,null,andundefinedallbecomefalse.
2. allothervaluesbecometrue.
YoucanperformthisconversionexplicitlyusingtheBoolean()function:

1
2

Boolean("");//false
Boolean(234);//true

However,thisisrarelynecessary,asJavaScriptwillsilentlyperformthisconversionwhenitexpectsa
boolean,suchasinanifstatement(seebelow).Forthisreason,wesometimesspeaksimplyof"true
values"and"falsevalues,"meaningvaluesthatbecometrueandfalse,respectively,whenconvertedto
booleans.Alternatively,suchvaluescanbecalled"truthy"and"falsy",respectively.
Booleanoperationssuchas&&(logicaland),||(logicalor),and!(logicalnot)aresupportedseebelow.

Variables
NewvariablesinJavaScriptaredeclaredusingthevarkeyword:

1
2

vara;
varname="simon";

Ifyoudeclareavariablewithoutassigninganyvaluetoit,itstypeisundefined.
AnimportantdifferencefromotherlanguageslikeJavaisthatinJavaScript,blocksdonothavescopeonly
functionshavescope.Soifavariableisdefinedusingvarinacompoundstatement(forexampleinsidean
ifcontrolstructure),itwillbevisibletotheentirefunction.However,startingwithECMAScriptEdition6,let
andconstdeclarationsallowyoutocreateblockscopedvariables.

Operators
JavaScript'snumericoperatorsare+,,*,/and%whichistheremainderoperator.Valuesareassigned
using=,andtherearealsocompoundassignmentstatementssuchas+=and=.Theseextendouttox=
xoperatory.

1
2

x+=5
x=x+5

Youcanuse++andtoincrementanddecrementrespectively.Thesecanbeusedasprefixorpostfix
operators.
The+operatoralsodoesstringconcatenation:

"hello"+"world";//"helloworld"

Ifyouaddastringtoanumber(orothervalue)everythingisconvertedintoastringfirst.Thismightcatch
youup:

1
2

"3"+4+5;//"345"
3+4+"5";//"75"

Addinganemptystringtosomethingisausefulwayofconvertingit.
ComparisonsinJavaScriptcanbemadeusing<,>,<=and>=.Theseworkforbothstringsandnumbers.
Equalityisalittlelessstraightforward.Thedoubleequalsoperatorperformstypecoercionifyougiveit
differenttypes,withsometimesinterestingresults:

1
2

"dog"=="dog";//true
1==true;//true

Toavoidtypecoercion,usethetripleequalsoperator:

1
2

1===true;//false
true===true;//true

Therearealso!=and!==operators.
JavaScriptalsohasbitwiseoperations.Ifyouwanttousethem,they'rethere.

Controlstructures
JavaScripthasasimilarsetofcontrolstructurestootherlanguagesintheCfamily.Conditionalstatements
aresupportedbyifandelseyoucanchainthemtogetherifyoulike:

1
2
3
4
5
6

varname="kittens";
if(name=="puppies"){
name+="!";
}elseif(name=="kittens"){
name+="!!";
}else{

7
8
9

name="!"+name;
}
name=="kittens!!"

JavaScripthaswhileloopsanddowhileloops.Thefirstisgoodforbasicloopingthesecondforloops
whereyouwishtoensurethatthebodyoftheloopisexecutedatleastonce:

1
2
3

while(true){
//aninfiniteloop!
}

4
5
6
7
8

varinput;
do{
input=get_input();
}while(inputIsNotValid(input))

JavaScript'sforloopisthesameasthatinCandJava:itletsyouprovidethecontrolinformationforyour
looponasingleline.

1
2
3

for(vari=0;i<5;i++){
//Willexecute5times
}

The&&and||operatorsuseshortcircuitlogic,whichmeanswhethertheywillexecutetheirsecondoperand
isdependentonthefirst.Thisisusefulforcheckingfornullobjectsbeforeaccessingtheirattributes:

varname=o&&o.getName();

Orforsettingdefaultvalues:

varname=otherName||"default";

JavaScripthasaternaryoperatorforconditionalexpressions:

varallowed=(age>18)?"yes":"no";

Theswitchstatementcanbeusedformultiplebranchesbasedonanumberorstring:

1
2
3
4
5
6
7
8
9
10

switch(action){
case'draw':
drawIt();
break;
case'eat':
eatIt();
break;
default:
doNothing();
}

Ifyoudon'taddabreakstatement,executionwill"fallthrough"tothenextlevel.Thisisveryrarelywhatyou
wantinfactit'sworthspecificallylabelingdeliberatefallthroughwithacommentifyoureallymeantitto
aiddebugging:

1
2
3
4
5
6
7
8

switch(a){
case1://fallthrough
case2:
eatIt();
break;
default:
doNothing();
}

Thedefaultclauseisoptional.Youcanhaveexpressionsinboththeswitchpartandthecasesifyoulike
comparisonstakeplacebetweenthetwousingthe===operator:

1
2
3
4
5
6
7

switch(1+3){
case2+2:
yay();
break;
default:
neverhappens();
}

Objects
JavaScriptobjectscanbethoughtofassimplecollectionsofnamevaluepairs.Assuch,theyaresimilarto:

DictionariesinPython
HashesinPerlandRuby
HashtablesinCandC++
HashMapsinJava
AssociativearraysinPHP
Thefactthatthisdatastructureissowidelyusedisatestamenttoitsversatility.Sinceeverything(barcore
types)inJavaScriptisanobject,anyJavaScriptprogramnaturallyinvolvesagreatdealofhashtable
lookups.It'sagoodthingthey'resofast!
The"name"partisaJavaScriptstring,whilethevaluecanbeanyJavaScriptvalueincludingmore
objects.Thisallowsyoutobuilddatastructuresofarbitrarycomplexity.
Therearetwobasicwaystocreateanemptyobject:

varobj=newObject();

And:

varobj={};

Thesearesemanticallyequivalentthesecondiscalledobjectliteralsyntax,andismoreconvenient.This
syntaxisalsothecoreofJSONformatandshouldbepreferredatalltimes.
Objectliteralsyntaxcanbeusedtoinitializeanobjectinitsentirety:

1
2
3
4
5
6
7
8

varobj={
name:"Carrot",
"for":"Max",
details:{
color:"orange",
size:12
}
}

Attributeaccesscanbechainedtogether:

1
2

obj.details.color;//orange
obj["details"]["size"];//12

Thefollowingexamplecreatesanobjectprototype,Person,andinstanceofthatprototype,You.

1
2
3
4

functionPerson(name,age){
this.name=name;
this.age=age;
}

5
6
7
8
9

//Defineanobject
varYou=newPerson("You",24);
//Wearecreatinganewpersonnamed"You"
//(thatwasthefirstparameter,andtheage..)

Oncecreated,anobject'spropertiescanagainbeaccessedinoneoftwoways:

1
2

obj.name="Simon";
varname=obj.name;

And...

1
2

obj["name"]="Simon";
varname=obj["name"];

Thesearealsosemanticallyequivalent.Thesecondmethodhastheadvantagethatthenameofthe
propertyisprovidedasastring,whichmeansitcanbecalculatedatruntimethoughusingthismethod
preventssomeJavaScriptengineandminifieroptimizationsbeingapplied.Itcanalsobeusedtosetandget
propertieswithnamesthatarereservedwords:

1
2

obj.for="Simon";//Syntaxerror,because'for'isareservedword
obj["for"]="Simon";//worksfine

Note:StartingfromEcmaScript5,reservedwordsmaybeusedasobjectpropertynames"inthebuff".
Thismeansthattheydon'tneedtobe"clothed"inquoteswhendefiningobjectliterals.SeeES5
Spec.

Formoreonobjectsandprototypessee:Object.prototype.

Arrays
ArraysinJavaScriptareactuallyaspecialtypeofobject.Theyworkverymuchlikeregularobjects
(numericalpropertiescannaturallybeaccessedonlyusing[]syntax)buttheyhaveonemagicproperty
called'length'.Thisisalwaysonemorethanthehighestindexinthearray.
Onewayofcreatingarraysisasfollows:

1
2
3
4
5

vara=newArray();
a[0]="dog";
a[1]="cat";
a[2]="hen";
a.length;//3

Amoreconvenientnotationistouseanarrayliteral:

1
2

vara=["dog","cat","hen"];
a.length;//3

Notethatarray.lengthisn'tnecessarilythenumberofitemsinthearray.Considerthefollowing:

1
2
3

vara=["dog","cat","hen"];
a[100]="fox";
a.length;//101

Rememberthelengthofthearrayisonemorethanthehighestindex.
Ifyouqueryanonexistentarrayindex,yougetundefined:

typeofa[90];//undefined

Ifyoutaketheaboveintoaccount,youcaniterateoveranarrayusingthefollowing:

1
2

for(vari=0;i<a.length;i++){
//Dosomethingwitha[i]

Thisisslightlyinefficientasyouarelookingupthelengthpropertyonceeveryloop.Animprovementisthis:

1
2
3

for(vari=0,len=a.length;i<len;i++){
//Dosomethingwitha[i]
}

Anicerlookingbutlimitedidiomis:

1
2
3

for(vari=0,item;item=a[i++];){
//Dosomethingwithitem
}

Herewearesettinguptwovariables.Theassignmentinthemiddlepartoftheforloopisalsotestedfor
truthfulnessifitsucceeds,theloopcontinues.Sinceiisincrementedeachtime,itemsfromthearraywill
beassignedtoiteminsequentialorder.Theloopstopswhena"falsy"itemisfound(suchasundefined).
Thistrickshouldonlybeusedforarrayswhichyouknowdonotcontain"falsy"values(arraysofobjectsor
DOMnodesforexample).Ifyouareiteratingovernumericdatathatmightincludea0orstringdatathat
mightincludetheemptystringyoushouldusethei,lenidiominstead.
Youcaniterateoveranarrayusingafor...inloop.Notethatifsomeoneaddednewpropertiesto
Array.prototype,theywillalsobeiteratedoverbythisloop.Thereforethismethodis"not"recommended.
AnotherwayofiteratingoveranarraythatwasaddedwithECMAScript5isforEach():

1
2
3

["dog","cat","hen"].forEach(function(currentValue,index,array){
//DosomethingwithcurrentValueorarray[index]
});

Ifyouwanttoappendanitemtoanarraysimplydoitlikethis:

a.push(item);

Arrayscomewithanumberofmethods.Seealsothefulldocumentationforarraymethods.

Methodname
a.toString()

a.toLocaleString()
a.concat(item1[,item2[,...[,
itemN]]])
a.join(sep)

Description
ReturnsastringwiththetoString()ofeachelement
separatedbycommas.
ReturnsastringwiththetoLocaleString()ofeach
elementseparatedbycommas.
Returnsanewarraywiththeitemsaddedontoit.
Convertsthearraytoastringvaluesdelimitedbythesep
param

a.pop()

Removesandreturnsthelastitem.

a.push(item1,...,itemN)

Pushaddsoneormoreitemstotheend.

a.reverse()

Reversethearray.

a.shift()

Removesandreturnsthefirstitem.

a.slice(start,end)

Returnsasubarray.

a.sort([cmpfn])

Takesanoptionalcomparisonfunction.

a.splice(start,delcount[,item1[,

Letsyoumodifyanarraybydeletingasectionand

...[,itemN]]])

replacingitwithmoreitems.

a.unshift([item])

Prependsitemstothestartofthearray.

Functions
Alongwithobjects,functionsarethecorecomponentinunderstandingJavaScript.Themostbasicfunction
couldn'tbemuchsimpler:

1
2
3
4

functionadd(x,y){
vartotal=x+y;
returntotal;
}

Thisdemonstratesabasicfunction.AJavaScriptfunctioncantake0ormorenamedparameters.The
functionbodycancontainasmanystatementsasyoulike,andcandeclareitsownvariableswhicharelocal
tothatfunction.Thereturnstatementcanbeusedtoreturnavalueatanytime,terminatingthefunction.If

noreturnstatementisused(oranemptyreturnwithnovalue),JavaScriptreturnsundefined.
Thenamedparametersturnouttobemorelikeguidelinesthananythingelse.Youcancallafunction
withoutpassingtheparametersitexpects,inwhichcasetheywillbesettoundefined.

1
2

add();//NaN
//Youcan'tperformadditiononundefined

Youcanalsopassinmoreargumentsthanthefunctionisexpecting:

1
2

add(2,3,4);//5
//addedthefirsttwo;4wasignored

Thatmayseemalittlesilly,butfunctionshaveaccesstoanadditionalvariableinsidetheirbodycalled
arguments,whichisanarraylikeobjectholdingallofthevaluespassedtothefunction.Let'srewritethe
addfunctiontotakeasmanyvaluesaswewant:

1
2
3
4
5
6
7

functionadd(){
varsum=0;
for(vari=0,j=arguments.length;i<j;i++){
sum+=arguments[i];
}
returnsum;
}

8
9

add(2,3,4,5);//14

That'sreallynotanymoreusefulthanwriting2+3+4+5though.Let'screateanaveragingfunction:

1
2
3
4
5
6
7

functionavg(){
varsum=0;
for(vari=0,j=arguments.length;i<j;i++){
sum+=arguments[i];
}
returnsum/arguments.length;
}

8
9

avg(2,3,4,5);//3.5

Thisisprettyuseful,butintroducesanewproblem.Theavg()functiontakesacommaseparatedlistof
argumentsbutwhatifyouwanttofindtheaverageofanarray?Youcouldjustrewritethefunctionas
follows:

1
2
3
4
5
6
7

functionavgArray(arr){
varsum=0;
for(vari=0,j=arr.length;i<j;i++){
sum+=arr[i];
}
returnsum/arr.length;
}

8
9

avgArray([2,3,4,5]);//3.5

Butitwouldbenicetobeabletoreusethefunctionthatwe'vealreadycreated.Luckily,JavaScriptletsyou
callafunctionandcallitwithanarbitraryarrayofarguments,usingtheapply()methodofanyfunction
object.

avg.apply(null,[2,3,4,5]);//3.5

Thesecondargumenttoapply()isthearraytouseasargumentsthefirstwillbediscussedlateron.This
emphasizesthefactthatfunctionsareobjectstoo.
JavaScriptletsyoucreateanonymousfunctions.

1
2
3
4
5
6
7

varavg=function(){
varsum=0;
for(vari=0,j=arguments.length;i<j;i++){
sum+=arguments[i];
}
returnsum/arguments.length;
};

Thisissemanticallyequivalenttothefunctionavg()form.It'sextremelypowerful,asitletsyouputafull
functiondefinitionanywherethatyouwouldnormallyputanexpression.Thisenablesallsortsofclever
tricks.Here'sawayof"hiding"somelocalvariableslikeblockscopeinC:

1
2

vara=1;
varb=2;

3
4
5
6
7

(function(){
varb=3;
a+=b;
})();

8
9
10

a;//4
b;//2

JavaScriptallowsyoutocallfunctionsrecursively.Thisisparticularlyusefulfordealingwithtreestructures,
suchasyougetinthebrowserDOM.

1
2
3
4
5
6
7
8
9
10

functioncountChars(elm){
if(elm.nodeType==3){//TEXT_NODE
returnelm.nodeValue.length;
}
varcount=0;
for(vari=0,child;child=elm.childNodes[i];i++){
count+=countChars(child);
}
returncount;
}

Thishighlightsapotentialproblemwithanonymousfunctions:howdoyoucallthemrecursivelyiftheydon't
haveaname?JavaScriptletsyounamefunctionexpressionsforthis.YoucanusenamedIIFEs
(ImmediatelyInvokedFunctionExpressions)asbelow:

1
2
3
4
5
6
7
8
9
10

varcharsInBody=(functioncounter(elm){
if(elm.nodeType==3){//TEXT_NODE
returnelm.nodeValue.length;
}
varcount=0;
for(vari=0,child;child=elm.childNodes[i];i++){
count+=counter(child);
}
returncount;
})(document.body);

Thenameprovidedtoafunctionexpressionasaboveisonlyavailabletothefunction'sownscope.This
bothallowsmoreoptimizationstobedonebytheengineandamorereadablecode.Thenamealsoshows
upinthedebuggerandsomestacktraceswhichcansaveyoutime.

NotethatJavaScriptfunctionsarethemselvesobjectsandyoucanaddorchangepropertiesonthemjust
likeonobjectswe'veseenintheObjectssection.

Customobjects
Note: For a more detailed discussion of object-oriented programming in JavaScript, see Introduction to
ObjectOrientedJavaScript.

InclassicObjectOrientedProgramming,objectsarecollectionsofdataandmethodsthatoperateonthat
data.JavaScriptisaprototypebasedlanguagewhichcontainsnoclassstatement,suchasisfoundinC++
orJava.(Thisissometimesconfusingforprogrammersaccustomedtolanguageswithaclassstatement.)
Instead,JavaScriptusesfunctionsasclasses.Let'sconsiderapersonobjectwithfirstandlastnamefields.
Therearetwowaysinwhichthenamemightbedisplayed:as"firstlast"oras"last,first".Usingthe
functionsandobjectsthatwe'vediscussedpreviously,here'sonewayofdoingit:

1
2
3
4
5
6
7
8
9
10
11
12

functionmakePerson(first,last){
return{
first:first,
last:last
};
}
functionpersonFullName(person){
returnperson.first+''+person.last;
}
functionpersonFullNameReversed(person){
returnperson.last+','+person.first;
}

13
14
15
16

s=makePerson("Simon","Willison");
personFullName(s);//"SimonWillison"
personFullNameReversed(s);"Willison,Simon"

Thisworks,butit'sprettyugly.Youendupwithdozensoffunctionsinyourglobalnamespace.Whatwe
reallyneedisawaytoattachafunctiontoanobject.Sincefunctionsareobjects,thisiseasy:

1
2
3
4
5
6
7

functionmakePerson(first,last){
return{
first:first,
last:last,
fullName:function(){
returnthis.first+''+this.last;
},

8
9
10
11
12

fullNameReversed:function(){
returnthis.last+','+this.first;
}
};
}

13
14
15
16

s=makePerson("Simon","Willison")
s.fullName();//"SimonWillison"
s.fullNameReversed();//"Willison,Simon"

There'ssomethingherewehaven'tseenbefore:thethiskeyword.Usedinsideafunction,thisrefersto
thecurrentobject.Whatthatactuallymeansisspecifiedbythewayinwhichyoucalledthatfunction.Ifyou
calleditusingdotnotationorbracketnotationonanobject,thatobjectbecomesthis.Ifdotnotationwasn't
usedforthecall,thisreferstotheglobalobject.
Notethatthisisafrequentcauseofmistakes.Forexample:

1
2
3

s=makePerson("Simon","Willison");
varfullName=s.fullName;
fullName();//undefinedundefined

WhenwecallfullName()alone,withoutusings.fullName(),thisisboundtotheglobalobject.Since
therearenoglobalvariablescalledfirstorlastwegetundefinedforeachone.
WecantakeadvantageofthethiskeywordtoimproveourmakePersonfunction:

1
2
3
4
5
6
7
8
9
10
11

functionPerson(first,last){
this.first=first;
this.last=last;
this.fullName=function(){
returnthis.first+''+this.last;
};
this.fullNameReversed=function(){
returnthis.last+','+this.first;
};
}
vars=newPerson("Simon","Willison");

Wehaveintroducedanotherkeyword:new.newisstronglyrelatedtothis.Whatitdoesisitcreatesabrand
newemptyobject,andthencallsthefunctionspecified,withthissettothatnewobject.Noticethoughthat

thefunctionspecifiedwiththisdoesnotreturnavaluebutmerelymodifiesthethisobject.It'snewthat
returnsthethisobjecttothecallingsite.Functionsthataredesignedtobecalledbynewarecalled
constructorfunctions.Commonpracticeistocapitalizethesefunctionsasaremindertocallthemwithnew.
TheimprovedfunctionstillhasthesamepitfallwithcallingfullName()alone.
Ourpersonobjectsaregettingbetter,buttherearestillsomeuglyedgestothem.Everytimewecreatea
personobjectwearecreatingtwobrandnewfunctionobjectswithinitwouldn'titbebetterifthiscode
wasshared?

1
2
3
4
5
6
7
8
9
10
11
12

functionpersonFullName(){
returnthis.first+''+this.last;
}
functionpersonFullNameReversed(){
returnthis.last+','+this.first;
}
functionPerson(first,last){
this.first=first;
this.last=last;
this.fullName=personFullName;
this.fullNameReversed=personFullNameReversed;
}

That'sbetter:wearecreatingthemethodfunctionsonlyonce,andassigningreferencestotheminsidethe
constructor.Canwedoanybetterthanthat?Theanswerisyes:

1
2
3
4
5
6
7
8
9
10

functionPerson(first,last){
this.first=first;
this.last=last;
}
Person.prototype.fullName=function(){
returnthis.first+''+this.last;
};
Person.prototype.fullNameReversed=function(){
returnthis.last+','+this.first;
};

Person.prototypeisanobjectsharedbyallinstancesofPerson.Itformspartofalookupchain(thathasa
specialname,"prototypechain"):anytimeyouattempttoaccessapropertyofPersonthatisn'tset,
JavaScriptwillcheckPerson.prototypetoseeifthatpropertyexiststhereinstead.Asaresult,anything
assignedtoPerson.prototypebecomesavailabletoallinstancesofthatconstructorviathethisobject.

Thisisanincrediblypowerfultool.JavaScriptletsyoumodifysomething'sprototypeatanytimeinyour
program,whichmeansyoucanaddextramethodstoexistingobjectsatruntime:

1
2

s=newPerson("Simon","Willison");
s.firstNameCaps();//TypeErroronline1:s.firstNameCapsisnotafunction

3
4
5
6
7

Person.prototype.firstNameCaps=function(){
returnthis.first.toUpperCase()
};
s.firstNameCaps();//"SIMON"

Interestingly,youcanalsoaddthingstotheprototypeofbuiltinJavaScriptobjects.Let'saddamethodto
Stringthatreturnsthatstringinreverse:

1
2

vars="Simon";
s.reversed();//TypeErroronline1:s.reversedisnotafunction

3
4
5
6
7
8
9
10

String.prototype.reversed=function(){
varr="";
for(vari=this.length1;i>=0;i){
r+=this[i];
}
returnr;
};

11
12

s.reversed();//nomiS

Ournewmethodevenworksonstringliterals!

"Thiscannowbereversed".reversed();//desreverebwonnacsihT

AsImentionedbefore,theprototypeformspartofachain.TherootofthatchainisObject.prototype,
whosemethodsincludetoString()itisthismethodthatiscalledwhenyoutrytorepresentanobjectas
astring.ThisisusefulfordebuggingourPersonobjects:

1
2

vars=newPerson("Simon","Willison");
s;//[objectObject]

3
4
5

Person.prototype.toString=function(){
return'<Person:'+this.fullName()+'>';

7
8

s.toString();//"<Person:SimonWillison>"

Rememberhowavg.apply()hadanullfirstargument?Wecanrevisitthatnow.Thefirstargumentto
apply()istheobjectthatshouldbetreatedas'this'.Forexample,here'satrivialimplementationofnew:

1
2
3
4
5

functiontrivialNew(constructor,...args){
varo={};//Createanobject
constructor.apply(o,args);
returno;
}

Thisisn'tanexactreplicaofnewasitdoesn'tsetuptheprototypechain(itwouldbedifficulttoillustrate).
Thisisnotsomethingyouuseveryoften,butit'susefultoknowabout.Inthissnippet,...args(including
theellipsis)iscalledthe"restarguments"asthenameimplies,thiscontainstherestofthearguments.
Calling

varbill=trivialNew(Person,"William","Orange");

isthereforealmostequivalentto

varbill=newPerson("William","Orange");

apply()hasasisterfunctionnamedcall,whichagainletsyousetthisbuttakesanexpandedargument
listasopposedtoanarray.

1
2
3
4
5
6
7
8

functionlastNameCaps(){
returnthis.last.toUpperCase();
}
vars=newPerson("Simon","Willison");
lastNameCaps.call(s);
//Isthesameas:
s.lastNameCaps=lastNameCaps;
s.lastNameCaps();

Innerfunctions

Innerfunctions
JavaScriptfunctiondeclarationsareallowedinsideotherfunctions.We'veseenthisoncebefore,withan
earliermakePerson()function.AnimportantdetailofnestedfunctionsinJavaScriptisthattheycanaccess
variablesintheirparentfunction'sscope:

1
2
3
4
5
6
7

functionbetterExampleNeeded(){
vara=1;
functiononeMoreThanA(){
returna+1;
}
returnoneMoreThanA();
}

Thisprovidesagreatdealofutilityinwritingmoremaintainablecode.Ifafunctionreliesononeortwoother
functionsthatarenotusefultoanyotherpartofyourcode,youcannestthoseutilityfunctionsinsidethe
functionthatwillbecalledfromelsewhere.Thiskeepsthenumberoffunctionsthatareintheglobalscope
down,whichisalwaysagoodthing.
Thisisalsoagreatcountertothelureofglobalvariables.Whenwritingcomplexcodeitisoftentemptingto
useglobalvariablestosharevaluesbetweenmultiplefunctionswhichleadstocodethatishardto
maintain.Nestedfunctionscansharevariablesintheirparent,soyoucanusethatmechanismtocouple
functionstogetherwhenitmakessensewithoutpollutingyourglobalnamespace'localglobals'ifyoulike.
Thistechniqueshouldbeusedwithcaution,butit'sausefulabilitytohave.

Closures
ThisleadsustooneofthemostpowerfulabstractionsthatJavaScripthastoofferbutalsothemost
potentiallyconfusing.Whatdoesthisdo?

1
2
3
4
5
6
7
8
9

functionmakeAdder(a){
returnfunction(b){
returna+b;
};
}
varx=makeAdder(5);
vary=makeAdder(20);
x(6);//?
y(7);//?

ThenameofthemakeAdderfunctionshouldgiveitaway:itcreatesnew'adder'functions,whichwhencalled

withoneargumentaddittotheargumentthattheywerecreatedwith.
What'shappeninghereisprettymuchthesameaswashappeningwiththeinnerfunctionsearlieron:a
functiondefinedinsideanotherfunctionhasaccesstotheouterfunction'svariables.Theonlydifferencehere
isthattheouterfunctionhasreturned,andhencecommonsensewouldseemtodictatethatitslocal
variablesnolongerexist.Buttheydostillexistotherwisetheadderfunctionswouldbeunabletowork.
What'smore,therearetwodifferent"copies"ofmakeAdder'slocalvariablesoneinwhichais5andone
inwhichais20.Sotheresultofthosefunctioncallsisasfollows:

1
2

x(6);//returns11
y(7);//returns27

Here'swhat'sactuallyhappening.WheneverJavaScriptexecutesafunction,a'scope'objectiscreatedto
holdthelocalvariablescreatedwithinthatfunction.Itisinitialisedwithanyvariablespassedinasfunction
parameters.Thisissimilartotheglobalobjectthatallglobalvariablesandfunctionslivein,butwithacouple
ofimportantdifferences:firstly,abrandnewscopeobjectiscreatedeverytimeafunctionstartsexecuting,
andsecondly,unliketheglobalobject(whichisaccessibleasthisandinbrowsersisaccessibleaswindow)
thesescopeobjectscannotbedirectlyaccessedfromyourJavaScriptcode.Thereisnomechanismfor
iteratingoverthepropertiesofthecurrentscopeobject,forexample.
SowhenmakeAdderiscalled,ascopeobjectiscreatedwithoneproperty:a,whichistheargumentpassed
tothemakeAdderfunction.makeAdderthenreturnsanewlycreatedfunction.NormallyJavaScript'sgarbage
collectorwouldcleanupthescopeobjectcreatedformakeAdderatthispoint,butthereturnedfunction
maintainsareferencebacktothatscopeobject.Asaresult,thescopeobjectwillnotbegarbagecollected
untiltherearenomorereferencestothefunctionobjectthatmakeAdderreturned.
Scopeobjectsformachaincalledthescopechain,similartotheprototypechainusedbyJavaScript'sobject
system.
Aclosureisthecombinationofafunctionandthescopeobjectinwhichitwascreated.
Closuresletyousavestateassuch,theycanoftenbeusedinplaceofobjects.Severalexcellent
introductionstoclosurescanbefound here.

Memoryleaks
AnunfortunatesideeffectofclosuresisthattheymakeittriviallyeasytoleakmemoryinInternetExplorer.
JavaScriptisagarbagecollectedlanguageobjectsareallocatedmemoryupontheircreationandthat
memoryisreclaimedbythebrowserwhennoreferencestoanobjectremain.Objectsprovidedbythehost
environmentarehandledbythatenvironment.

BrowserhostsneedtomanagealargenumberofobjectsrepresentingtheHTMLpagebeingpresented
theobjectsoftheDOM.Itisuptothebrowsertomanagetheallocationandrecoveryofthese.
InternetExplorerusesitsowngarbagecollectionschemeforthis,separatefromthemechanismusedfor
JavaScript.Itistheinteractionbetweenthetwothatcancausememoryleaks.
AmemoryleakinIEoccursanytimeacircularreferenceisformedbetweenaJavaScriptobjectandanative
object.Considerthefollowing:

1
2
3
4
5

functionleakMemory(){
varel=document.getElementById('el');
varo={'el':el};
el.o=o;
}

ThecircularreferenceformedabovecreatesamemoryleakIEwillnotfreethememoryusedbyelando
untilthebrowseriscompletelyrestarted.
Theabovecaseislikelytogounnoticedmemoryleaksonlybecomearealconcerninlongrunning
applicationsorapplicationsthatleaklargeamountsofmemoryduetolargedatastructuresorleakpatterns
withinloops.
Leaksarerarelythisobviousoftentheleakeddatastructurecanhavemanylayersofreferences,
obscuringthecircularreference.
Closuresmakeiteasytocreateamemoryleakwithoutmeaningto.Considerthis:

1
2
3
4
5
6

functionaddHandler(){
varel=document.getElementById('el');
el.onclick=function(){
el.style.backgroundColor='red';
};
}

Theabovecodesetsuptheelementtoturnredwhenitisclicked.Italsocreatesamemoryleak.Why?
Becausethereferencetoelisinadvertentlycaughtintheclosurecreatedfortheanonymousinnerfunction.
ThiscreatesacircularreferencebetweenaJavaScriptobject(thefunction)andanativeobject(el).
Thereareanumberofworkaroundsforthisproblem.Thesimplestisnottousetheelvariable:

1
2
3
4
5

functionaddHandler(){
document.getElementById('el').onclick=function(){
this.style.backgroundColor='red';
};
}

Surprisingly,onetrickforbreakingcircularreferencesintroducedbyaclosureistoaddanotherclosure:

1
2
3
4
5
6
7
8
9

functionaddHandler(){
varclickHandler=function(){
this.style.backgroundColor='red';
};
(function(){
varel=document.getElementById('el');
el.onclick=clickHandler;
})();
}

Theinnerfunctionisexecutedstraightaway,andhidesitscontentsfromtheclosurecreatedwith
clickHandler.
Anothergoodtrickforavoidingclosuresisbreakingcircularreferencesduringthewindow.onunloadevent.
Manyeventlibrarieswilldothisforyou.NotethatdoingsodisablesthebackforwardcacheinFirefox,so
youshouldnotregisteranunloadlistenerinFirefox,unlessyouhaveotherreasonstodoso.

You might also like