41
JavaScript What’s in the language?

Javascript patterns

Embed Size (px)

DESCRIPTION

The presentation covers Javascript Gotcha's and patterns to use while implementing client side browser applications.

Citation preview

Page 1: Javascript patterns

JavaScript  -­‐  What’s  in  the  language?  

Page 2: Javascript patterns

JavaScript  as  a  language  •  Implementa3on  of  ECMASCRIPT  •  Object  oriented  •  No  Classes  •  Dynamic  Objects  -­‐  collec3on  of  named  proper3es.  You  can  add,  remove,  update  its  members.    

•  Loose  typing  •  lambdas  •  Na3ve  and  host  objects  -­‐  Environment  specific  •  Prototypical  inheritance  

Page 3: Javascript patterns

Good  Parts  

•  Lambda  •  Dynamic  objects  •  Loose  typing  •  Object  literals  

Page 4: Javascript patterns

Bad  Parts  

•  Global  Variables  •  +  adds  and  concatenates  •  Semicolon  inser3on  •  typeof  •  with  and  eval  •  ==  and  !=  •  false,  null,  undefined,  NaN  

Page 5: Javascript patterns

General  Pa8erns  

Page 6: Javascript patterns

Minimizing  global  variables  

/*#Title:#Minimizing#Globals#Description:#they#are#declared#outside#of#any#function#or#simply#used#without#being#declared!

# # # */!!! ! ! myglobal!=!"hello";!//#antipattern!! ! ! console.log(myglobal);!//#"hello"!! ! ! console.log(window.myglobal);!//#"hello"!! ! ! console.log(window["myglobal"]);!//#"hello"!! ! ! console.log(this.myglobal);!//#"hello"!!

Page 7: Javascript patterns

Implied  global  variables  

! ! ! //!antipatten!1!! ! ! function!sum(x,!y)!{!! ! ! ! //!implied!global!! ! ! ! result!=!x!+!y;!! ! ! ! return!result;!! ! ! }!!!! ! ! //!preferred!1!! ! ! function!sum(x,!y)!{!

//!a!variable!declared!inside!of!a!function!is!local!to!that!function!and!not!available!outside!the!function!

! ! ! ! var!result!=!x!+!y;!! ! ! ! return!result;!! ! ! }!!!!

Page 8: Javascript patterns

! ! ! //"antipattern"2!! ! ! function!foo()!{!! ! ! ! var!a!=!b!=!0;!! ! ! ! //"...!! ! ! }!!! ! ! //"the"preceding"code"snippet"will"behave"as"if"you've"typed"the"following!! ! ! var!a!=!(b!=!0);!!!! ! ! //"preferred"2!! ! ! function!foo()!{!! ! ! ! var!a,!b;!! ! ! ! //"...!! ! ! ! a!=!b!=!0;!//"both"local!! ! ! }!!

Page 9: Javascript patterns

Single  var  PaSern  ! ! !!! ! ! /*!Benefits:!

!*!1.!Provides!a!single!place!to!look!for!all!the!local!variables!needed!by!the!function!

! ! ! !*!2.!Prevents!logical!errors!when!a!variable!is!used!before!it's!defined!! ! ! !*!3.!Helps!you!remember!to!declare!variables!and!therefore!minimize!globals!! ! ! */!!! ! ! function!func()!{!! ! ! ! var!a!=!1,!! ! ! ! ! ! b!=!2,!! ! ! ! ! ! sum!=!a!+!b,!! ! ! ! ! ! myobject!=!{},!! ! ! ! ! ! i,!! ! ! ! ! ! j;!!! ! ! ! //!function!body...!! ! ! }!!! ! ! function!updateElement()!{!! ! ! ! var!el!=!document.getElementById("result"),!! ! ! ! ! ! style!=!el.style;!! ! ! ! //!do!something!with!el!and!style...!! ! ! }!!

Page 10: Javascript patterns

Namespacing  

! ! ! //!unsafe!! ! ! var!MYAPP!=!{};!! ! ! //!better!! ! ! if!(typeof!MYAPP!===!"undefined")!{!! ! ! ! var!MYAPP!=!{};!! ! ! }!! ! ! //!or!shorter!! ! ! var!MYAPP!=!MYAPP!||!{};!!

Page 11: Javascript patterns

! ! ! MYAPP.namespace!=!function!(ns_string)!{!! ! ! ! var!parts!=!ns_string.split('.'),!! ! ! ! ! ! parent!=!MYAPP,!! ! ! ! ! ! i;!!! ! ! ! //"strip"redundant"leading"global!! ! ! ! if!(parts[0]!===!"MYAPP")!{!! ! ! ! ! parts!=!parts.slice(1);!! ! ! ! }!!! ! ! ! for!(i!=!0;!i!<!parts.length;!i!+=!1)!{!! ! ! ! ! //"create"a"property"if"it"doesn't"exist!! ! ! ! ! if!(typeof!parent[parts[i]]!===!"undefined")!{!! ! ! ! ! ! parent[parts[i]]!=!{};!! ! ! ! ! }!! ! ! ! ! parent!=!parent[parts[i]];!! ! ! ! }!! ! ! ! return!parent;!! ! ! };!!! ! ! //"assign"returned"value"to"a"local"var!! ! ! var!module2!=!MYAPP.namespace('MYAPP.modules.module2');!! ! ! console.log(module2!===!MYAPP.modules.module2);!//"true!!!

Page 12: Javascript patterns

Implied  Typecas3ng:  false,  null,  undefined,  NaN  

! ! ! var!zero!=!0;!!! ! ! /*#antipattern!# # # #*#JavaScript#implicitly#typecasts#variables#when#you#compare#them.!# # # #*#That's#why#comparisons#such#as#false#==#0#or#""#==#0#return#true.!# # # #*/!! ! ! if!(zero!==!false)!{!! ! ! ! //#this#block#is#executed...!! ! ! }!!!! ! ! //#preferred!! ! ! /*#To#avoid#confusion#caused#by#the#implied#typecasting,!

*#always#use#the#===#and#!==#operators#that#check#both#the#values#and#the#type#of#the#expressions#you#compare!

# # # */!! ! ! if!(zero!===!false)!{!! ! ! ! //#not#executing#because#zero#is#0,#not#false!! ! ! }!! !

Page 13: Javascript patterns

Avoiding  eval  

! ! ! /*!Title:!Avoiding!eval()!! ! ! !*!Description:!avoid!using!eval()!! ! ! !*/!!! ! ! //!antipattern!1!! ! ! var!property!=!"name";!! ! ! alert(eval("obj."!+!property));!!!! ! ! //!preferred!1!! ! ! var!property!=!"name";!! ! ! alert(obj[property]);!!!

Page 14: Javascript patterns

! ! ! /*#antipattern#2!*#It's#also#important#to#remember#that#passing#strings#to#setInterval(),#setTimeout(),!*#and#the#Function()#constructor#is,#for#the#most#part,#similar#to#using#eval()#and#therefore#should#be#avoided.!

# # # */!! ! ! setTimeout("myFunc()",!1000);!! ! ! setTimeout("myFunc(1,!2,!3)",!1000);!!!! ! ! //#preferred#2!! ! ! setTimeout(myFunc,!1000);!! ! ! setTimeout(function!()!{!! ! ! ! myFunc(1,!2,!3);!! ! ! },!1000);!! ! ! //#in#supported#browsers#(i.e.#not#IE)!! ! ! setTimeout(myFunc,!1000,!1,!2,!3);!!!

Page 15: Javascript patterns

For-­‐in  loops  ! ! ! /*#Title:#for-in#loops!# # # #*#Description:#optimized#for-in#loops!# # # #*/!!! ! ! //#the#object!! ! ! var!man!=!{!! ! ! ! hands:2,!! ! ! ! legs:2,!! ! ! ! heads:1!! ! ! };!!! ! ! //#somewhere#else#in#the#code!! ! ! //#a#method#was#added#to#all#objects!! ! ! if!(typeof!Object.prototype.clone!===!'undefined')!{!! ! ! ! Object.prototype.clone!=!function!()!{!! ! ! ! };!! ! ! }!!! !

Page 16: Javascript patterns

! ! ! //"antipattern!! ! ! //"for,in"loop"without"checking"hasOwnProperty()!! ! ! for!(var!i!in!man)!{!! ! ! ! console.log(i,!":",!man[i]);!! ! ! }!! ! ! /*!" " " "*"result"in"the"console!" " " "*"hands":"2!" " " "*"legs":"2!" " " "*"hands":"1!" " " "*"clone:"function()!" " " "*/!!!! ! ! //"preferred"1!! ! ! for!(var!i!in!man)!{!! ! ! ! if!(man.hasOwnProperty(i))!{!//"filter!! ! ! ! ! console.log(i,!":",!man[i]);!! ! ! ! }!! ! ! }!!! ! ! /*!" " " "*"result"in"the"console!" " " "*"hands":"2!" " " "*"legs":"2!" " " "*"heads":"1!" " " "*/!!

Page 17: Javascript patterns

Automa3c  semicolon  inser3on  

//antipattern!return!{!!!!!status:!true!};!!//preferred!return{!!!!!status:!true!};!!

Page 18: Javascript patterns

Func:on  Pa8erns  

Page 19: Javascript patterns

Closures  //"Your"setup"function"can"store"some"private"data"in"a"closure"and"use"that"data"somehow.!//"Here"setup()"creates"a"counter"function,"which"gives"a"next"ID"for"example."But"the"count"variable"is"not"exposed.!

!! ! ! var!setup!=!function!()!{!! ! ! ! var!count!=!0;!! ! ! ! return!function!()!{!! ! ! ! ! return!++count;!! ! ! ! };!! ! ! };!! ! ! //"usage!! ! ! var!next!=!setup();!! ! ! //next();"//"returns"1!! ! ! //next();"//"returns"2!! ! ! //next();"//"returns"3!!

Page 20: Javascript patterns

Currying  ! ! ! /***!# # # #currying!# # # #***/!!! ! ! //#a#curried#add()!! ! ! //#accepts#partial#list#of#arguments!! ! ! function!add(x,!y)!{!! ! ! ! var!oldx!=!x,!oldy!=!y;!! ! ! ! if!(typeof!oldy!===!"undefined")!{!//#partial!! ! ! ! ! return!function!(newy)!{!! ! ! ! ! ! return!oldx!+!newy;!! ! ! ! ! }!! ! ! ! }!! ! ! ! //#full#application!! ! ! ! return!x!+!y;!! ! ! }!!! ! ! //#test!! ! ! typeof!add(5);!//#"function"!! ! ! add(3)(4);!//#7!!

Page 21: Javascript patterns

Literals,  Constructors  and  Object  crea:on  Pa8erns  

Page 22: Javascript patterns

To  ‘new’  or  not  ! ! ! ! !!! ! ! //!antipattern!! ! ! var!car!=!new!Object();!! ! ! car.goes!=!"far";!!!! ! ! //!preferred!! ! ! var!car!=!{goes:"far"};!!! ! ! //!constructor!! ! ! function!Waffle()!{!! ! ! ! this.tastes!=!"yummy";!! ! ! }!!! ! ! //!antipattern!! ! ! //!forgotten!`new`!! ! ! var!good_morning!=!Waffle();!! ! ! console.log(typeof!good_morning);!//!"undefined"!! ! ! console.log(window.tastes);!//!"yummy"!!!! ! ! //!preferred!! ! ! var!good_morning!=!new!Waffle();!! ! ! console.log(typeof!good_morning);!//!"object"!! ! ! console.log(good_morning.tastes);!//!"yummy"!!!! ! !!

Page 23: Javascript patterns

PaSerns  for  enforcing  ‘new’  ! ! ! !! ! ! function!Waffle()!{!! ! ! ! if!(!(this!instanceof!Waffle))!{!! ! ! ! ! return!new!Waffle();!! ! ! ! }!!! ! ! ! this.tastes!=!"yummy";!! ! ! }!!! ! ! var!good_morning!=!new!Waffle();!! ! ! var!good_evening!=!Waffle();!!! ! ! console.log(typeof!good_morning);!//""object"!! ! ! console.log(good_morning.tastes);!//""yummy"!! ! ! console.log(typeof!good_evening);!//""object"!! ! ! console.log(good_evening.tastes);!//""yummy"!!

Page 24: Javascript patterns

! ! ! //!antipattern!! ! ! //!with!wrappers!! ! ! var!s!=!new!String("my!string");!! ! ! var!n!=!new!Number(101);!! ! ! var!b!=!new!Boolean(true);!!!! ! ! //!preferred!! ! ! //!without!wrappers!! ! ! var!s!=!"my!string";!! ! ! var!n!=!101;!! ! ! var!b!=!true;!!!

Page 25: Javascript patterns

! ! ! /*!# # # #only#use#primitive#wrappers#when#you#want#to#augment#the#value#and#persist#state!# # # #*/!!! ! ! //#primitive#string!! ! ! var!greet!=!"Hello!there";!! ! ! //#primitive#is#converted#to#an#object!! ! ! //#in#order#to#use#the#split()#method!! ! ! greet.split('!')[0];!//#"Hello"!! ! ! //#attemting#to#augment#a#primitive#is#not#an#error!! ! ! greet.smile!=!true;!! ! ! //#but#it#doesn't#actually#work!! ! ! console.log(typeof!greet.smile);!//#"undefined"!!! ! ! //#primitive#wrapper!! ! ! var!greet!=!new!String("Hello!there");!! ! ! //#split()#method#is#called#directly#on#the#object!! ! ! greet.split('!')[0];!//#"Hello"!! ! ! //#augment#the#object!! ! ! greet.smile!=!true;!! ! ! console.log(typeof!greet.smile);!//#"boolean"!!

Page 26: Javascript patterns

Module  paSern  MYAPP.utilities.array/=/(function/()/{// / / / //"private"properties// / / / var/array_string/=/"[object/Array]",// / / / ops/=/Object.prototype.toString,/// / / / //"private"methods// / / / inArray/=/function/(haystack,/needle)/{// / / / / for/(var/i/=/0,/max/=/haystack.length;/i/</max;/i/+=/1)/{// / / / / / if/(haystack[i]/===/needle)/{// / / / / / / return/i;// / / / / / }// / / / / }// / / / / return//1;// / / / },// / / / isArray/=/function/(a)/{// / / / / return/ops.call(a)/===/array_string;// / / / };// / / / //"end"var/// / / / //"revealing"public"API// / / / return/{// / / / / isArray:isArray,// / / / / indexOf:inArray// / / / };// / / }());/ !

Page 27: Javascript patterns

Code  Reuse  Pa8erns  

Page 28: Javascript patterns

Prototypal  Inheritance  

! ! ! function!object(o)!{!! ! ! ! function!F()!{!! ! ! ! }!!! ! ! ! F.prototype!=!o;!! ! ! ! return!new!F();!! ! ! }!!! ! ! //"object"to"inherit"from!! ! ! var!parent!=!{!! ! ! ! name:"Papa"!! ! ! };!!! ! ! //"the"new"object!! ! ! var!child!=!object(parent);!!! ! ! //"testing!! ! ! console.log(child.name);!//""Papa"!!! !

Page 29: Javascript patterns

! ! ! //"parent"constructor!! ! ! function!Person()!{!! ! ! ! //"an""own""property!! ! ! ! this.name!=!"Adam";!! ! ! }!! ! ! //"a"property"added"to"the"prototype!! ! ! Person.prototype.getName!=!function!()!{!! ! ! ! return!this.name;!! ! ! };!! ! ! //"create"a"new"person!! ! ! var!papa!=!new!Person();!! ! ! //"inherit!! ! ! var!kid!=!object(papa);!! ! ! //"test"that"both"the"own"property!! ! ! //"and"the"prototype"property"were"inherited!! ! ! console.log(kid.getName());!//""Adam"!!

Page 30: Javascript patterns

Augmen3ng  built-­‐in  Prototypes  

! ! ! if!(typeof!Object.prototype.myMethod!!==!"function")!{!! ! ! ! Object.prototype.myMethod!=!function!()!{!! ! ! ! ! //"implementation...!! ! ! ! };!! ! ! }!!

Page 31: Javascript patterns

Design  Pa8erns  

Page 32: Javascript patterns

CREATIONAL  

Builder   constructs  complex  objects  by  separa3ng  construc3on  and  representa3on  

Factory  Method   creates  objects  without  specifying  the  exact  class  to  create  

Singleton   restricts  object  crea3on  for  a  class  to  only  one  instance  

STRUCTURAL  

Decorator   dynamically  adds/overrides  behavior  in  an  exis3ng  method  of  an  object  

Facade   provides  a  simplified  interface  to  a  large  body  of  code  

BEHAVIORAL  

Chain  of  responsibility   delegates  commands  to  a  chain  of  processing  objects  

Command   creates  objects  which  encapsulate  ac3ons  and  parameters  

Mediator   allows  loose  coupling  between  classes  by  being  the  only  class  that  has  detailed  knowledge  of  their  methods  

Observer   is  a  publish/subscribe  paSern  which  allows  a  number  of  observer  objects  to  see  an  event  

Page 33: Javascript patterns

Composite  

//"Single"elements!$("#singleItem").addClass("active");!$("#container").addClass("active");!!//"Collections"of"elements!$("div").addClass("active");!$(".item").addClass("active");!$("input").addClass("active");!!

Page 34: Javascript patterns

Adapter  

//"Cross"browser"opacity:!//"opacity:"0.9;""Chrome"4+,"FF2+,"Saf3.1+,"Opera"9+,"IE9,"iOS"3.2+,"Android"2.1+!//"filter:"alpha(opacity=90);""IE6KIE8!!//"Setting"opacity!$(".container").css({!opacity:.5!});!!//"Getting"opacity!var!currentOpacity!=!$(".container").css('opacity');! !

Page 35: Javascript patterns

Observer  

//"Equivalent"to"subscribe(topicName,"callback)!$(document).on("topicName",!function!()!{!!!!!//..perform"some"behaviour!});!!//"Equivalent"to"publish(topicName)!$(document).trigger("topicName");!!//"Equivalent"to"unsubscribe(topicName)!$(document).off("topicName");! !

Page 36: Javascript patterns

AMD  -­‐  Asynchronous  module  defini3on  

define('''''module_id'/*optional*/,'''''[dependencies]'/*optional*/,'''''definition'function'/*function-for-instantiating-the-module-or-object*/')'!!!require(["foo",'"bar"],'function'(foo,'bar)'{'''''//-rest-of-your-code-here'''''foo.doSomething();'});'!

Page 37: Javascript patterns

Prolifera3on  of  MV*  frameworks  

Page 38: Javascript patterns

Prolifera3on  of  MV*  frameworks  

•  Rich  internet  single  page  applica3ons  •  Data  Binding  •  Client  side  templates  •  Client-­‐Centric  or  Server-­‐Centric-­‐  that  is  the  ques3on.  

Page 39: Javascript patterns

•  Minify,  concatenate,  compress  •  Load  scripts  at  the  end  of  pages  •  Sta3c  code  analysis  using  Jslint/Jshint  •  Tes3ng  your  code  –  Jasmine,  Phantomjs  etc  

Page 40: Javascript patterns

References  

Page 41: Javascript patterns

Ques:ons?