compare. This can lead to funny behavior, for example: BUT: 0 = = " 0 " ; / / t r u e 0 = = " " ; / / t r u e " 0 " = = " " ; / / f a l s e Always use = = = " 1 " = = = 1 ; / / f a l s e [ ] = = = " " ; / / f a l s e 0 = = = " 0 " ; / / f a l s e 0 = = = " " ; / / f a l s e
i o n f o o ( ) { v a r f o o = " b a r " ; f u n c t i o n b a r ( ) { c o n s o l e . l o g ( f o o ) ; / / " b a r " o r e r r o r ? } } What about: f u n c t i o n f o o ( ) { v a r f o o = " b a r " ; f u n c t i o n b a r ( ) { v a r f o o = " b a z " ; c o n s o l e . l o g ( f o o ) ; / / " b a r " o r " b a z " ? } c o n s o l e . l o g ( f o o ) ; / / " b a r " o r " b a z " ? }
o " ; c o n s o l e . l o g ( e ) ; / / ? t r y { t h r o w " b a r " ; } c a t c h ( e ) { c o n s o l e . l o g ( e ) ; / / ? } c o n s o l e . l o g ( e ) ; / / ? Scopes are everywhere v a r a = " f o o " ; c o n s o l e . l o g ( a ) ; f u n c t i o n b a r ( ) { i f ( t r u e ) { v a r a = " b a r " ; c o n s o l e . l o g ( a ) ; } c o n s o l e . l o g ( a ) ; / / " f o o " , " b a r " o r e r r o r ? } Well... ALMOST everywhere
There is also a "root" scope, which we call the global scope In browsers this is w i n d o w On Node.js it is g l o b a l Be careful, if you don't use v a r in front of your variable, it will create the variable on the global scope! f u n c t i o n f o o ( ) { a = " b a r " ; } f o o ( ) ; c o n s o l e . l o g ( w i n d o w ) ;
t i c i e n = f u n c t i o n ( f i r s t n a m e , l a s t n a m e ) { t h i s . f i r s t n a m e = f i r s t n a m e ; t h i s . l a s t n a m e = l a s t n a m e ; t h i s . s a y N a m e = f u n c t i o n ( ) { c o n s o l e . l o g ( t h i s . f i r s t n a m e + " " + t h i s . l a s t n a m e ) ; } ; } ; v a r m e = n e w O p t i c i e n ( " D i m i t r i " , " M e s t d a g h " ) ; m e . s a y N a m e ( ) ; O p t i c i e n appears to be a normal function, but it can be instantiated using the n e w keyword. We call this a prototype.
is that they can be changed at runtime: v a r P e r s o n = f u n c t i o n ( f i r s t n a m e , l a s t n a m e , j o b ) { t h i s . f i r s t n a m e = f i r s t n a m e ; t h i s . l a s t n a m e = l a s t n a m e ; t h i s . j o b = j o b ; } ; P e r s o n . p r o t o t y p e . s a y J o b = f u n c t i o n ( ) { c o n s o l e . l o g ( t h i s . j o b ) ; } ; P e r s o n . p r o t o t y p e . s a y N a m e = f u n c t i o n ( ) { c o n s o l e . l o g ( t h i s . f i r s t n a m e + " " + t h i s . l a s t n a m e ) ; } ; v a r m e = n e w P e r s o n ( " D i m i t r i " , " M e s t d a g h " , " I T C o n s u l t a n t " ) ; m e . s a y J o b ( ) ; m e . s a y N a m e ( ) ;
a r O p t i c i e n = f u n c t i o n ( f i r s t n a m e , l a s t n a m e ) { P e r s o n . c a l l ( t h i s , f i r s t n a m e , l a s t n a m e ) ; / / s u p e r ( f i r s t n a m e , l a s t n a m e ) t h i s . j o b = " I T C o n s u l t a n t " ; } ; O p t i c i e n . p r o t o t y p e = n e w P e r s o n ( ) ; / / O p t i c i e n e x t e n d s f r o m P e r s o n v a r m e = n e w O p t i c i e n ( " D i m i t r i " , " M e s t d a g h " ) ; m e . s a y J o b ( ) ; m e . s a y N a m e ( ) ;
simple functions We can use them as prototypes F u n c t i o n i n s t a n c e o f O b j e c t ; / / t r u e O b j e c t i n s t a n c e o f F u n c t i o n ; / / t r u e
can even call them directly: ( f u n c t i o n ( ) { c o n s o l e . l o g ( " I ' m e x e c u t e d d i r e c t l y " ) ; } ( ) ) ; This is an Immediately Invoked Function Expression or an IIFE.
= = , what about: v a r h a s N a m e = f u n c t i o n ( p e r s o n ) { r e t u r n p e r s o n . n a m e ! = = u n d e f i n e d ; } ; c o n s o l e . l o g ( h a s N a m e ( { n a m e : " D i m i t r i M e s t d a g h " } ) ) ; ... works fine, don't you think so?
to IE8), u n d e f i n e d is a mutable object: w i n d o w . u n d e f i n e d = " D i m i t r i M e s t d a g h " ; v a r h a s N a m e = f u n c t i o n ( p e r s o n ) { r e t u r n p e r s o n . n a m e ! = = u n d e f i n e d ; } ; c o n s o l e . l o g ( h a s N a m e ( { n a m e : " D i m i t r i M e s t d a g h " / / T h i s w i l l r e t u r n f a l s e i n I E 8 ! ! ! } ) ) ;
well: ( f u n c t i o n ( $ , u n d e f i n e d ) { } ( j Q u e r y ) ) ; Add u n d e f i n e d as the last argument Nothing is passed to it, so it's REALLY u n d e f i n e d
c r e m e n t = f u n c t i o n ( n u m ) { n u m + = 1 ; } ; v a r n u m = 2 ; i n c r e m e n t ( n u m ) ; c o n s o l e . l o g ( n u m ) ; / / ? Just like Java, arguments are passed by value
a n g e N a m e = f u n c t i o n ( p e r s o n ) { p e r s o n = { n a m e : " J o h n D o e " } ; } ; v a r m e = { n a m e : " D i m i t r i M e s t d a g h " } ; c h a n g e N a m e ( m e ) ; c o n s o l e . l o g ( m e . n a m e ) ; / / ? Also, objects are passed by reference.
10 with one second delay each. Will this work? No!, think of . f o r ( v a r i d x = 1 ; i d x < = 1 0 ; i d x + + ) { s e t T i m e o u t ( f u n c t i o n ( ) { c o n s o l e . l o g ( i d x ) ; } , 1 0 0 0 * i d x ) ; } Tip 2
f o r ( v a r i d x = 1 ; i d x < = 1 0 ; i d x + + ) { ( f u n c t i o n ( n u m ) { s e t T i m e o u t ( f u n c t i o n ( ) { c o n s o l e . l o g ( n u m ) ; } , 1 0 0 0 * n u m ) ; } ( i d x ) ) ; } It works because arguments to a function are ... passed by value
= = There is no such thing as a block scope! Always use v a r to create variables! Prototypes can be inherited, extended and overriden at any time. Always wrap your code in an IIFE