SevenJavaScriptThingsIWishIKnewMuchEarlierInMyCareer
http://www.iwms.net/trans.aspx?id=2217
I’vebeenwritingJavaScriptcodeformuchlongerthanIcaretoremember.Iamveryexcitedaboutthelanguage’srecentsuccess;it’sgoodtobeapartofthatsuccessstory.I’vewrittendozensofarticles,bookchaptersandonefullbookonthematter,andyetIkeepfindingnewthings.Herearesomeofthe“aha!”momentsI’vehadinthepast,whichyoucantryoutratherthanwaitingforthemtocometoyoubychance.
[Offtopic:bytheway,didyouknowthatthereisaSmashingeBookSeries?Book#2isSuccessfulFreelancingforWebDesigners,260pagesforjust$9,90.]
ShortcutNotations
OneofthethingsIlovemostaboutJavaScriptnowisshortcutnotationstogenerateobjectsandarrays.So,inthepastwhenwewantedtocreateanobject,wewrote:
viewsource
print?
Thesamecanbeachievedwith:
viewsource
print?
Muchshorter,andyoudon’tneedtorepeatthenameoftheobject.Rightnow,car
isfine,butwhathappenswhenyouuseinvalidUserInSession
?ThemaingotchainthisnotationisIE.Nevereverleaveatrailingcommabeforetheclosingcurlybraceoryou’llbeintrouble.
Theotherhandyshortcutnotationisforarrays.Theoldschoolwayofdefiningarrayswasthis:
viewsource
print?
1 | var moviesThatNeedBetterWriters= new Array( |
2 | 'Transformers' , 'Transformers2' , 'Avatar' , 'IndianaJones4' |
Theshorterversionofthisis:
viewsource
print?
1 | var moviesThatNeedBetterWriters=[ |
2 | 'Transformers' , 'Transformers2' , 'Avatar' , 'IndianaJones4' |
Theotherthingaboutarraysisthatthereisnosuchthingasanassociativearray.Youwillfindalotofcodeexamplesthatdefinetheabovecar
examplelikeso:
viewsource
print?
4 | car[ 'hubcaps' ]= 'spinning' ; |
ThisisnotSparta;thisismadness—don’tbotherwiththis.“Associativearrays”isaconfusingnameforobjects.
Anotherverycoolshortcutnotationistheternarynotationforconditions.So,insteadofthefollowing…
viewsource
print?
…Youcouldwriteashorterversionusingtheternarynotation:
viewsource
print?
1 | var direction=x<200?1:-1; |
Thetrue
caseoftheconditionisafterthequestionmark,andtheothercasefollowsthecolon.
JSONAsADataFormat
BeforeIdiscoveredJSONtostoredata,IdidallkindsofcrazythingstoputcontentinaJavaScript-readyformat:arrays,stringswithcontrolcharacterstosplit,andotherabominations.ThecreationofJSONbyDouglasCrockfordchangedallthat.UsingJSON,youcanstorecomplexdatainaformatthatisnativetoJavaScriptanddoesn'tneedanyextraconversiontobeusedimmediately.
JSONisshortfor"JavaScriptObjectNotation"andusesbothoftheshortcutswecoveredearlier.
So,ifIwantedtodescribeaband,forexample,Icoulddothefollowing:
viewsource
print?
02 | "name" : "TheRedHotChiliPeppers" , |
05 | "name" : "AnthonyKiedis" , |
09 | "name" : "Michael'Flea'Balzary" , |
10 | "role" : "bassguitar,trumpet,backingvocals" |
14 | "role" : "drums,percussion" |
17 | "name" : "JohnFrusciante" , |
YoucanuseJSONdirectlyinJavaScriptand,whenwrappedinafunctioncall,evenasareturnformatofAPIs.ThisiscalledJSON-PandissupportedbyalotofAPIsoutthere.Youcanuseadataendpoint,returningJSON-Pdirectlyinascriptnode:
viewsource
print?
01 | <divid= "delicious" ></div><script> |
04 | for ( var i=0;i<o.length;i++){ |
05 | out+= '<li><ahref="' +o[i].u+ '">' + |
09 | document.getElementById( 'delicious' ).innerHTML=out; |
12 | <scriptsrc= "http://feeds.delicious.com/v2/json/codepo8/javascript?count=15&callback=delicious" ></script> |
ThiscallstheDeliciousWebservicetogetmylatestJavaScriptbookmarksinJSONformatandthendisplaysthemasanunorderedlist.
Inessence,JSONisprobablythemostlightweightwayofdescribingcomplexdata—anditrunsinabrowser.YoucanevenuseitinPHPusingthejson_decode()
function.
NativeJavaScriptFunctions(Math,ArrayAndString)
OnethingthatamazedmeishowmucheasiermylifegotonceIreadupthoroughlyonthemathandstringfunctionsofJavaScript.Youcanusethesetoavoidalotofloopingandconditions.Forexample,whenIhadthetaskoffindingthelargestnumberinanarrayofnumbers,Iusedtowritealoop,likeso:
viewsource
print?
1 | var numbers=[3,342,23,22,124]; |
3 | for ( var i=0;i<numbers.length;i++){ |
Thiscanbeachievedwithoutaloop:
viewsource
print?
1 | var numbers=[3,342,23,22,124]; |
2 | numbers.sort( function (a,b){ return b-a}); |
Noticethatyoucannotusesort()
onanumberarraybecauseitsortslexically.There'sagoodtutorialonsort()
hereincaseyouneedtoknowmore.
AnotherinterestingmethodisMath.max()
.Thisonereturnsthelargestnumberfromalistofparameters:
viewsource
print?
1 | Math.max(12,123,3,2,433,4); //returns433 |
Becausethistestsfornumbersandreturnsthelargestone,youcanuseittotestforbrowsersupportofcertainproperties:
viewsource
print?
2 | doc.documentElement.scrollTop, |
ThisworksaroundanInternetExplorerproblem.YoucanreadoutthescrollTop
ofthecurrentdocument,butdependingontheDOCTYPE
ofthedocument,oneortheotherpropertyisassignedthevalue.WhenyouuseMath.max()
yougettherightnumberbecauseonlyoneofthepropertiesreturnsone;theotherwillbeundefined
.YoucanreadmoreaboutshorteningJavaScriptwithmathfunctionshere.
Otherverypowerfulfunctionstomanipulatestringsaresplit()
andjoin()
.ProbablythemostpowerfulexampleofthisiswritingafunctiontoattachCSSclassestoelements.
Thethingis,whenyouaddaclasstoaDOMelement,youwanttoadditeitherasthefirstclassortoalreadyexistingclasseswithaspaceinfrontofit.Whenyouremoveclasses,youalsoneedtoremovethespaces(whichwasmuchmoreimportantinthepastwhensomebrowsersfailedtoapplyclasseswithtrailingspaces).
So,theoriginalfunctionwouldbesomethinglike:
viewsource
print?
1 | function addclass(elm,newclass){ |
3 | elm.className=(c=== '' )?newclass:c+ '' +newclass; |
Youcanautomatethisusingthesplit()
andjoin()
methods:
viewsource
print?
1 | function addclass(elm,newclass){ |
2 | var classes=elm.className.split( '' ); |
4 | elm.className=classes.join( '' ); |
Thisautomaticallyensuresthatclassesarespace-separatedandthatyoursgetstackedonattheend.
EventDelegation
EventsmakeWebappswork.Iloveevents,especiallycustomevents,whichmakeyourproductsextensiblewithoutyourneedingtotouchthecorecode.Themainproblem(andactuallyoneofitsstrengths)isthateventsareremovedfromtheHTML—youapplyaneventlistenertoacertainelementandthenitbecomesactive.NothingintheHTMLindicatesthatthisisthecasethough.Takethisabstractionissue(whichishardforbeginnerstowraptheirheadsaround)andthefactthat"browsers"suchasIE6haveallkindofmemoryproblemsandtoomanyeventsappliedtothem,andyou'llseethatnotusingtoomanyeventhandlersinadocumentiswise.
Thisiswhereeventdelegationcomesin.WhenaneventhappensonacertainelementandonalltheelementsaboveitintheDOMhierarchy,youcansimplifyyoureventhandlingbyusingasinglehandleronaparentelement,ratherthanusingalotofhandlers.
WhatdoImeanbythat?Sayyouwantalistoflinks,andyouwanttocallafunctionratherthanloadthelinks.TheHTMLwouldbe:
viewsource
print?
1 | <h2>GreatWebresources</h2> |
3 | <li><ahref= "http://opera.com/wsc" >OperaWebStandardsCurriculum</a></li> |
4 | <li><ahref= "http://sitepoint.com" >Sitepoint</a></li> |
5 | <li><ahref= "http://alistapart.com" >AListApart</a></li> |
6 | <li><ahref= "http://yuiblog.com" >YUIBlog</a></li> |
7 | <li><ahref= "http://blameitonthevoices.com" >Blameitonthevoices</a></li> |
8 | <li><ahref= "http://oddlyspecific.com" >Oddlyspecific</a></li> |
Thenormalwaytoapplyeventhandlersherewouldbetoloopthroughthelinks:
viewsource
print?
01 | //Classiceventhandlingexample |
03 | var resources=document.getElementById( 'resources' ); |
04 | var links=resources.getElementsByTagName( 'a' ); |
07 | //Attachalistenertoeachlink |
08 | links[i].addEventListener( 'click' ,handler, false ); |
11 | var x=e.target; //Getthelinkthatwasclicked |
Thiscouldalsobedonewithasingleeventhandler:
viewsource
print?
02 | var resources=document.getElementById( 'resources' ); |
03 | resources.addEventListener( 'click' ,handler, false ); |
05 | var x=e.target; //getthelinktha |
06 | if (x.nodeName.toLowerCase()=== 'a' ){ |
07 | alert( 'Eventdelegation:' +x); |
Becausetheclickhappensonalltheelementsinthelist,allyouneedtodoiscomparethenodeName
totherightelementthatyouwanttoreacttotheevent.
Disclaimer:whilebothoftheeventexamplesaboveworkinbrowsers,theyfailinIE6.ForIE6,youneedtoapplyaneventmodelotherthantheW3Cone,andthisiswhyweuselibrariesforthesetricks.
Thebenefitsofthisapproacharemorethanjustbeingabletouseasingleeventhandler.Say,forexample,youwanttoaddmorelinksdynamicallytothislist.Witheventdelegation,thereisnoneedtochangeanything;withsimpleeventhandling,youwouldhavetoreassignhandlersandre-loopthelist.
AnonymousFunctionsAndTheModulePattern
OneofthemostannoyingthingsaboutJavaScriptisthatithasnoscopeforvariables.Anyvariable,function,arrayorobjectyoudefinethatisnotinsideanotherfunctionisglobal,whichmeansthatotherscriptsonthesamepagecanaccess—andwillusuallyoverride—them.
Theworkaroundistoencapsulateyourvariablesinananonymousfunctionandcallthatfunctionimmediatelyafteryoudefineit.Forexample,thefollowingdefinitionwouldresultinthreeglobalvariablesandtwoglobalfunctions:
viewsource
print?
7 | function getMemberDetails(){ |
Anyotherscriptonthepagethathasavariablenamedstatus
couldcausetrouble.IfwewrapallofthisinanamesuchasmyApplication
,thenweworkaroundthatissue:
viewsource
print?
01 | var myApplication= function (){ |
05 | function createMember(){ |
08 | function getMemberDetails(){ |
This,however,doesn'tdoanythingoutsideofthatfunction.Ifthisiswhatyouneed,thengreat.Youmayaswelldiscardthenamethen:
viewsource
print?
05 | function createMember(){ |
08 | function getMemberDetails(){ |
Ifyouneedtomakesomeofthethingsreachabletotheoutside,thenyouneedtochangethis.InordertoreachcreateMember()
orgetMemberDetails()
,youneedtoreturnthemtotheoutsideworldtomakethempropertiesofmyApplication
:
viewsource
print?
01 | var myApplication= function (){ |
06 | createMember: function (){ |
09 | getMemberDetails: function (){ |
14 | //myApplication.createMember()and |
15 | //myApplication.getMemberDetails()nowworks. |
Thisiscalledamodulepatternorsingleton.ItwasmentionedalotbyDouglasCrockfordandisusedverymuchintheYahooUserInterfaceLibraryYUI.WhatailsmeaboutthisisthatIneedtoswitchsyntaxestomakefunctionsorvariablesavailabletotheoutsideworld.Furthermore,ifIwanttocallonemethodfromanother,IhavetocallitprecededbythemyApplication
name.Soinstead,IprefersimplytoreturnpointerstotheelementsthatIwanttomakepublic.Thisevenallowsmetoshortenthenamesforoutsideuse:
viewsource
print?
01 | var myApplication= function (){ |
05 | function createMember(){ |
08 | function getMemberDetails(){ |
16 | //myApplication.get()andmyApplication.create()nowwork. |
I'vecalledthis"revealingmodulepattern."
AllowingForConfiguration
WheneverI'vewrittenJavaScriptandgivenittotheworld,peoplehavechangedit,usuallywhentheywantedittodothingsthatitcouldn'tdooutofthebox—butalsooftenbecauseImadeittoohardforpeopletochangethings.
Theworkaroundistoaddconfigurationobjectstoyourscripts.I'vewrittenaboutJavaScriptconfigurationobjectsindetail,buthere'sthegist:
Haveanobjectaspartofyourwholescriptcalledconfiguration
.
Init,storeallofthethingsthatpeoplewilllikelychangewhentheyuseyourscript:
CSSIDandclassnames;
Strings(suchaslabels)forgeneratedbuttons;
Valuessuchas"numberofimagesbeingdisplayed,""dimensionsofmap";
Location,localeandlanguagesettings.
Returntheobjectasapublicpropertysothatpeoplecanoverrideit.
Mostofthetimeyoucandothisasalaststepinthecodingprocess.I'veputtogetheranexamplein"Fivethingstodotoascriptbeforehandingitovertothenextdeveloper."
Inessence,youwanttomakeiteasyforpeopletouseyourcodeandalterittotheirneeds.Ifyoudothat,youaremuchlesslikelytogetconfusingemailsfrompeoplewhocomplainaboutyourscriptsandrefertochangesthatsomeoneelseactuallydid.
InteractingWithTheBackEnd
OneofthemainthingsIlearnedfromallmyyearswithJavaScriptisthatitisagreatlanguagewithwhichtomakeinteractiveinterfaces,butwhenitcomestocrunchingnumbersandaccessingdatasources,itcanbedaunting.
Originally,IlearnedJavaScripttoreplacePerlbecauseIwassickofcopyingthingstoacgi-bin
folderinordertomakeitwork.Lateron,Ilearnedthatmakingaback-endlanguagedothemaindatachurningforme,insteadoftryingtodoallinJavaScript,makesmoresensewithregardtosecurityandlanguage.
IfIaccessaWebservice,IcouldgetJSON-Pasthereturnedformatanddoalotofdataconversionontheclient,butwhyshouldIwhenIhaveaserverthathasaricherwayofconvertingdataandthatcanreturnthedataasJSONorHTML…andcacheitformetoboot?
So,ifyouwanttouseAJAX,learnaboutHTTPandaboutwritingyourowncachingandconversionproxy.Youwillsavealotoftimeandnervesinthelongrun.
Browser-SpecificCodeIsAWasteOfTime.UseLibraries!
WhenIstartedWebdevelopment,thebattlebetweenusingdocument.all
andusingdocument.layers
asthemainwaytoaccessthedocumentwasstillraging.Ichosedocument.layers
becauseIlikedtheideaofanylayerbeingitsowndocument(andIhadwrittenmorethanenoughdocument.write
solutionstolastalifetime).Thelayermodelfailed,butsodiddocument.all
.WhenNetscape6wentalloutsupportingonlytheW3CDOMmodel,Ilovedit,butendusersdidn'tcare.Endusersjustsawthatthisbrowserdidn'tshowthemajorityoftheInternetscorrectly(althoughitdid)—thecodeweproducedwaswhatwaswrong.Webuiltshort-sightedcodethatsupportedastate-of-the-artenvironment,andthefunnythingaboutthestateoftheartisthatitisconstantlychanging.
I'vewastedquitesometimelearningtheinsandoutsofallofthebrowsersandworkingaroundtheirissues.DoingthisbackthensecuredmycareerandensuredthatIhadagreatjob.Butweshouldn'thavetogothroughthistrialbyfireanylonger.
LibrariessuchasYUI,jQueryandDojoareheretohelpuswiththis.Theytakeontheproblemsofbrowsersbyabstractingthepainsofpoorimplementation,inconsistenciesandflat-outbugs,andrelieveusofthechore.Unlessyouwanttobetatestacertainbrowserbecauseyou'reabigfan,don'tfixbrowserissuesinyourJavaScriptsolutions,becauseyouareunlikelytoeverupdatethecodetoremovethisfix.AllyouwouldbedoingisaddingtothealreadymassivepileofoutdatedcodeontheWeb.
Thatsaid,relyingsolelyonlibrariesforyourcoreskillisshort-sighted.ReaduponJavaScript,watchsomegoodvideosandtutorialsonit,andunderstandthelanguage.(Tip:closuresareGod'sgifttotheJavaScriptdeveloper.)Librarieswillhelpyoubuildthingsquickly,butifyouassignalotofeventsandeffectsandneedtoaddaclasstoeveryHTMLelementinthedocument,thenyouaredoingitwrong.
Resources
Inadditiontotheresourcesmentionedinthisarticle,alsocheckoutthefollowingtolearnmoreaboutJavaScriptitself:
DouglasCrockfordonJavaScript
Anin-depthvideoLectureseries.
TheOperaWebStandardsCurriculum
WithadetailedsectiononJavaScript.
RelatedPosts
Youmaybeinterestedinthefollowingrelatedposts:
TheSevenDeadlySinsOfJavaScriptImplementation
DevelopingSitesWithAJAX:DesignChallengesandCommonIssues
45PowerfulCSS/JavaScript-Techniques
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理