Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Demystifying 'this'

toshsharma
September 07, 2013

Demystifying 'this'

Understanding the 'this' keyword in JavaScript.

The original presentation can be viewed at http://toshsharma.github.io/presentation-this

toshsharma

September 07, 2013
Tweet

More Decks by toshsharma

Other Decks in Technology

Transcript

  1. What's this? f u n c t i o n

    h a n d l e r ( ) { v a r v a l = t h i s . v a l u e ; / / . . . } this refers to an object Its value in a function depends only on how the function is called
  2. this in object methods v a r p e r

    s o n = { n a m e : " J o h n " , 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 . n a m e ) ; } } ; p e r s o n . s a y N a m e ( ) ; / / " J o h n "
  3. this in object methods v a r p e r

    s o n = { 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 . n a m e ) ; } , n a m e : " J o h n " } ; v a r c e o = { n a m e : " M a r k " } ; c e o . s a y N a m e = p e r s o n . s a y N a m e ; p e r s o n . s a y N a m e ( ) ; / / " J o h n " c e o . s a y N a m e ( ) ; / / " M a r k "
  4. Attaching functions to objects f u n c t i

    o n i n d e p e n d e n t ( ) { c o n s o l e . l o g ( t h i s . n a m e ) ; } v a r p e r s o n = { n a m e : " J o h n " } ; p e r s o n . s a y N a m e = i n d e p e n d e n t ; p e r s o n . s a y N a m e ( ) ; / / " J o h n "
  5. Methods on the prototype chain v a r n a

    m e C a l l e r = { 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 . n a m e ) ; } } ; v a r p e r s o n = O b j e c t . c r e a t e ( n a m e C a l l e r ) ; p e r s o n . n a m e = " J o h n " ; p e r s o n . s a y N a m e ( ) ; / / " J o h n "
  6. Getters and Setters f u n c t i o

    n f u l l N a m e ( ) { r e t u r n 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 p e r s o n = { f i r s t N a m e : " J o h n " , l a s t N a m e : " D o e " } ; O b j e c t . d e f i n e P r o p e r t y ( p e r s o n , " n a m e " , { g e t : f u l l N a m e } ) ; c o n s o l e . l o g ( p e r s o n . n a m e ) ; / / " J o h n D o e "
  7. Function Calls f u n c t i o n

    f u n c ( ) { c o n s o l e . l o g ( t h i s ) ; } f u n c ( ) ; / / ? <window object> undefined (strict mode)
  8. Extracted Object Methods v a r p e r s

    o n = { 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 ) ; / / ? c o n s o l e . l o g ( t h i s ) ; / / ? } , f i r s t N a m e : " J o h n " } ; v a r f u n c = p e r s o n . s a y N a m e ; f u n c ( ) ; undefined <window object> undefined (strict mode)
  9. setTimeout, setInterval v a r p e r s o

    n = { f i r s t N a m e : " J o h n " , s a y N a m e : f u n c t i o n ( ) { 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 ( t h i s . f i r s t N a m e ) ; / / ? c o n s o l e . l o g ( t h i s ) ; / / ? } , 1 0 0 0 ) ; } } ; p e r s o n . s a y N a m e ( ) ; undefined <window object> <window object> (strict mode)
  10. <input onclick="/* inline code */"> < i n p u

    t t y p e = " b u t t o n " o n c l i c k = " t h i s . v a l u e = ' c h a n g e d ' ; " v a l u e = " c l i c k m e " / > this is the DOM element
  11. <input onclick="handler()"> HTML: < i n p u t t

    y p e = " b u t t o n " o n c l i c k = " h a n d l e r ( ) " / > JavaScript: f u n c t i o n h a n d l e r ( ) { c o n s o l e . l o g ( t h i s ) ; / / ? } <window object> undefined (strict mode)
  12. <input onclick="handler(this)"> HTML: < i n p u t t

    y p e = " b u t t o n " o n c l i c k = " h a n d l e r ( t h i s ) " / > JavaScript: f u n c t i o n h a n d l e r ( e l e m e n t ) { c o n s o l e . l o g ( t h i s ) ; / / ? c o n s o l e . l o g ( e l e m e n t ) ; / / ? } <window object> <input element>
  13. <input onclick="handler"> HTML: < i n p u t t

    y p e = " b u t t o n " o n c l i c k = " h a n d l e r " / > JavaScript: f u n c t i o n h a n d l e r ( ) { c o n s o l e . l o g ( t h i s ) ; / / ? } Nothing! This is not a valid way to specify on* attributes
  14. element.onclick = handler HTML: < i n p u t

    t y p e = " b u t t o n " i d = " s u b m i t " / > JavaScript: f u n c t i o n h a n d l e r ( ) { c o n s o l e . l o g ( t h i s ) ; / / ? } v a r e l e m e n t = d o c u m e n t . g e t E l e m e n t B y I d ( " s u b m i t " ) ; e l e m e n t . o n c l i c k = h a n d l e r ; <input element>
  15. element.addEventListener (...) HTML: < i n p u t t

    y p e = " b u t t o n " i d = " s u b m i t " / > JavaScript: f u n c t i o n h a n d l e r ( ) { c o n s o l e . l o g ( t h i s ) ; / / ? } v a r e l e m e n t = d o c u m e n t . g e t E l e m e n t B y I d ( " s u b m i t " ) ; e l e m e n t . a d d E v e n t L i s t e n e r ( " c l i c k " , h a n d l e r ) ; <input element>
  16. DOM event callbacks $ ( " p " ) .

    c l i c k ( f u n c t i o n ( ) { t h i s . s t y l e . b a c k g r o u n d C o l o r = " y e l l o w " ; $ ( t h i s ) . c s s ( " c o l o r " , " b l u e " ) ; } ) ; this is the 'raw' DOM element
  17. Functions on elements matched by jQuery Selectors $ ( "

    a " ) . t e x t ( f u n c t i o n ( ) { r e t u r n t h i s . g e t A t t r i b u t e ( " h r e f " ) ; } ) ; this is the 'raw' DOM element
  18. Iterate over elements matched by jQuery Selectors $ ( "

    a " ) . e a c h ( f u n c t i o n ( ) { c o n s o l e . l o g ( t h i s . g e t A t t r i b u t e ( " h r e f " ) ) ; } ) ; this is the 'raw' DOM element
  19. jQuery.each v a r a r r = [ "

    a a " , " b b " , " c c " , " d d " ] ; $ . e a c h ( a r r , f u n c t i o n ( ) { c o n s o l e . l o g ( t h i s ) ; } ) ; this is an individual object in the array/collection
  20. this in constructors f u n c t i o

    n P e r s o n ( ) { t h i s . n a m e = " J o h n " ; } v a r p = n e w P e r s o n ( ) ; c o n s o l e . l o g ( p . n a m e ) ; / / J o h n this is the new object being constructed
  21. Return value from constructors f u n c t i

    o n P e r s o n ( ) { t h i s . n a m e = " J o h n " ; r e t u r n { n a m e : " M a r k " , a g e : 2 0 } } v a r p = n e w P e r s o n ( ) ; c o n s o l e . l o g ( p . n a m e ) ; / / ? Mark
  22. Return value from constructors f u n c t i

    o n P e r s o n ( ) { t h i s . n a m e = " J o h n " ; r e t u r n 5 0 ; / / : - o } v a r p = n e w P e r s o n ( ) ; c o n s o l e . l o g ( p . n a m e ) ; / / ? John
  23. Nested Functions v a r o b j = {

    n a m e : " J o h n " , o u t e r : f u n c t i o n ( ) { c o n s o l e . l o g ( " O u t e r : " + t h i s . n a m e ) ; / / ? f u n c t i o n i n n e r ( ) { c o n s o l e . l o g ( " I n n e r : " + t h i s ) ; / / ? } i n n e r ( ) ; } } o b j . o u t e r ( ) ; Outer: John Inner: [object Window] Inner: undefined (strict mode)
  24. eval v a r o b j = { n

    a m e : " J o h n " , f u n c : f u n c t i o n ( ) { e v a l ( " c o n s o l e . l o g ( t h i s ) " ) ; / / ? ( 1 , e v a l ) ( " c o n s o l e . l o g ( t h i s ) " ) ; / / ? } } o b j . f u n c ( ) ; <obj object> <window object> <window object> (strict mode)
  25. Array: forEach, map, filter, every, some v a r a

    r r = [ " 1 1 " , " 2 2 " , " 3 3 " , " 4 4 " ] ; a r r . f o r E a c h ( f u n c t i o n ( ) { c o n s o l e . l o g ( t h i s ) ; / / ? } ) ; <window object> undefined (strict mode) a r r . f o r E a c h ( f u n c t i o n ( ) { c o n s o l e . l o g ( t h i s ) ; / / ? } , { n a m e : " J o h n " } ) ; Object {name: "John"}
  26. Inspecting the value of this v a r p e

    r s o n = { 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 ) ; / / < = = } , f i r s t N a m e : " J o h n " } ; v a r f u n c = p e r s o n . s a y N a m e ; func() person.sayName()
  27. Inspecting the value of this Chrome DevTools: Sources > Scope

    Variables > Local > this Firebug: Script > Watch > this Firefox: Debugger > Function Scope > this Opera: Scripts > State > Inspection > this Internet Explorer: Script > Locals > this
  28. setTimeout Creating a closure Original code: v a r p

    e r s o n = { f i r s t N a m e : " J o h n " , s a y N a m e : f u n c t i o n ( ) { 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 ( t h i s . f i r s t N a m e ) ; / / u n d e f i n e d } , 1 0 0 0 ) ; } } ; p e r s o n . s a y N a m e ( ) ;
  29. setTimeout Creating a closure Fixed code: v a r p

    e r s o n = { f i r s t N a m e : " J o h n " , s a y N a m e : f u n c t i o n ( ) { v a r s e l f = t h i s ; / / < = = 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 ( s e l f . f i r s t N a m e ) ; / / ? } , 1 0 0 0 ) ; } } ; p e r s o n . s a y N a m e ( ) ; John
  30. Nested function Creating a closure Original code: v a r

    o b j = { a g e : 2 0 , o u t e r : f u n c t i o n ( ) { f u n c t i o n i n n e r ( ) { c o n s o l e . l o g ( t h i s . a g e ) ; / / u n d e f i n e d } i n n e r ( ) ; } } o b j . o u t e r ( ) ;
  31. Nested function Creating a closure Fixed code: v a r

    o b j = { a g e : 2 0 , o u t e r : f u n c t i o n ( ) { v a r t h a t = t h i s ; / / < = = f u n c t i o n i n n e r ( ) { c o n s o l e . l o g ( t h a t . a g e ) ; / / ? } i n n e r ( ) ; } } o b j . o u t e r ( ) ; 20
  32. Function.prototype.call f u n c . c a l l

    ( t h i s A r g , a r g 1 , a r g 2 , a r g 3 , . . . ) v a r p e r s o n = { 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 . n a m e ) ; } } ; v a r c e o = { n a m e : " M a r k " } ; p e r s o n . s a y N a m e . c a l l ( c e o ) ; / / ? Mark
  33. Function.prototype.call v a r n o d e L i

    s t = d o c u m e n t . g e t E l e m e n t s B y T a g N a m e ( " h 2 " ) ; v a r f i r s t T w o = n o d e L i s t . s l i c e ( 0 , 2 ) ; TypeError: Object #<NodeList> has no method 'slice' v a r f i r s t T w o = A r r a y . p r o t o t y p e . s l i c e . c a l l ( n o d e L i s t , 0 , 2 ) ; OK
  34. Inheritance and this f u n c t i o

    n P e r s o n ( n a m e ) { t h i s . n a m e = n a m e ; } P e r s o n . p r o t o t y p e . m e t h o d = f u n c t i o n ( ) { / * . . . * / } f u n c t i o n E m p l o y e e ( n a m e , d e p a r t m e n t ) { P e r s o n . c a l l ( t h i s , n a m e ) ; / / < = = t h i s . d e p a r t m e n t = d e p a r t m e n t ; } E m p l o y e e . p r o t o t y p e = n e w P e r s o n ; E m p l o y e e . p r o t o t y p e . c o n s t r u c t o r = E m p l o y e e ; v a r e = n e w E m p l o y e e ( " J o h n D o e " , " M a r k e t i n g " ) ; c o n s o l e . l o g ( e . n a m e , e . d e p a r t m e n t ) ; / / ? John Doe Marketing
  35. Function.prototype.apply f u n c . a p p l

    y ( t h i s A r g , a r g s A r r a y ) v a r m a x = M a t h . m a x ( 8 2 , 1 2 , 1 , 5 2 , 2 7 ) ; c o n s o l e . l o g ( m a x ) ; 82 v a r n u m b e r s = [ 8 2 , 1 2 , 1 , 5 2 , 2 7 ] ; v a r m a x = M a t h . m a x . a p p l y ( n u l l , n u m b e r s ) ; c o n s o l e . l o g ( m a x ) ; 82
  36. Function.prototype.apply f u n c t i o n m

    a x I n A r r a y ( a r r ) { v a r m a x = - I n f i n i t y ; f o r ( v a r i = 0 ; i < a r r . l e n g t h ; i + + ) i f ( a r r [ i ] > m a x ) m a x = a r r [ i ] ; r e t u r n m a x ; } v a r n u m b e r s = [ 8 2 , 1 2 , 1 , 5 2 , 2 7 ] ; c o n s o l e . l o g ( m a x I n A r r a y ( n u m b e r s ) ) ; 82 f u n c t i o n m a x I n A r r a y ( a r r ) { r e t u r n M a t h . m a x . a p p l y ( n u l l , a r r ) ; } v a r n u m b e r s = [ 8 2 , 1 2 , 1 , 5 2 , 2 7 ] ; c o n s o l e . l o g ( m a x I n A r r a y ( n u m b e r s ) ) ; 82
  37. Function.prototype.bind f u n c . b i n d

    ( t h i s A r g , a r g 1 , a r g 2 , a r g 3 , . . . ) v a r p e r s o n = { 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 ) ; / / ? } , f i r s t N a m e : " J o h n " } ; v a r f u n c = p e r s o n . s a y N a m e . b i n d ( p e r s o n ) ; / / < = = f u n c ( ) ; John
  38. setTimeout Function.prototype.bind v a r p e r s o

    n = { f i r s t N a m e : " J o h n " , s a y N a m e : f u n c t i o n ( ) { 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 ( t h i s . f i r s t N a m e ) ; / / ? } . b i n d ( t h i s ) , 1 0 0 0 ) ; / / < = = } } ; p e r s o n . s a y N a m e ( ) ; John
  39. Function.prototype.bind Original code: v a r l o g =

    c o n s o l e . l o g ; l o g ( " H e l l o ! " ) ; / / ? TypeError: Illegal invocation Fixed code: v a r l o g = c o n s o l e . l o g . b i n d ( c o n s o l e ) ; l o g ( " H e l l o ! " ) ; / / ? Hello!
  40. Special Handling HTML: < s p a n o n

    c l i c k = " a l e r t ( t h i s ) " > C l i c k m e < / s p a n > < a h r e f = " h t t p : / / g o o g l e . c o m / " o n c l i c k = " a l e r t ( t h i s ) " > G o o g l e < / a > Click me Google .toString()
  41. eval.call HTML: v a r o b j = {

    n a m e : " J o h n " , f u n c : f u n c t i o n ( ) { e v a l . c a l l ( t h i s , " c o n s o l e . l o g ( t h i s ) " ) ; / / ? } } o b j . f u n c ( ) ; <window object> <window object> (strict mode)
  42. Further Reading - MDN - MDN - MDN - MDN

    Function.prototype.call Function.prototype.apply Function.prototype.bind this