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

JavaScript Behind the Scenes: Meta Programming

JavaScript Behind the Scenes: Meta Programming

Infinite sequences, lazy properties and changing your program’s structure in runtime. Yes, JavaScript is that powerful. In this talk, I demonstrate how to solve problems in a smarter way and with better performance and readability by redefining how the language’s features work behind the scenes.

Lucas Fernandes da Costa

March 02, 2017
Tweet

More Decks by Lucas Fernandes da Costa

Other Decks in Programming

Transcript

  1. But this is not exactly what we will be talking

    about This is Meta Programming
  2. Meta Level JavaScript But this is not exactly what we

    will be talking about This is Meta Programming
  3. Meta Level JavaScript Base Level Java But this is not

    exactly what we will be talking about But this is not exactly what we will be talking about This is Meta Programming
  4. Meta Object Protocol Provides a vocabulary to access and manipulate

    the structure and behavior of systems of objects https://en.wikipedia.org/wiki/Metaobject
  5. Property Descriptors myObject value enumerable writable configurable get set any

    boolean boolean boolean function function myProperty
  6. Property Descriptors myObject value enumerable writable configurable get set any

    boolean boolean boolean function function myProperty This is a Property Descriptor
  7. Indicates the property’s value value enumerable writable configurable get set

    any boolean boolean boolean function function Property Descriptors
  8. Indicates if this property shows up when enumerating properties value

    enumerable writable configurable get set any boolean boolean boolean function function Property Descriptors
  9. Indicates if this property’s value can be changed using the

    assignment operator value enumerable writable configurable get set any boolean boolean boolean function function Property Descriptors
  10. Indicates if this property’s descriptor can be changed and if

    this property can be deleted value enumerable writable configurable get set any boolean boolean boolean function function Property Descriptors
  11. The function which will be invoked when accessing the property

    value enumerable writable configurable get set any boolean boolean boolean function function Property Descriptors
  12. The function which will be called when trying to assign

    to this property value enumerable writable configurable get set any boolean boolean boolean function function Property Descriptors
  13. Getters Lazy Properties basket dataNasc value: 08/05/1995 weight 800 fruits

    {bananas: 3, oranges: 1} Too many assignments to the weight property!
  14. Getters Lazy Properties pessoa dataNasc value: 08/05/1995 idade get: function

    basket weight fruits {bananas: 1, oranges: 1} get: function basket.weight
  15. Getters Lazy Properties pessoa dataNasc value: 08/05/1995 idade get: function

    pessoa dataNasc value: 08/05/1995 idade get: function basket weight fruits {bananas: 1, oranges: 1} get: function calls the get function basket.weight
  16. Getters Lazy Properties pessoa dataNasc value: 08/05/1995 idade get: function

    200 pessoa dataNasc value: 08/05/1995 idade get: function pessoa dataNasc value: 08/05/1995 basket.weight idade get: function basket weight fruits {bananas: 1, oranges: 1} get: function calls the get function
  17. Getters Lazy Properties pessoa dataNasc value: 08/05/1995 idade get: function

    300 pessoa dataNasc value: 08/05/1995 idade get: function pessoa dataNasc value: 08/05/1995 basket.weight idade get: function basket weight fruits {bananas: 2, oranges: 1} get: function calls the get function
  18. Setters person fullName set: function firstName value: '' lastName value:

    '' Multiple Assignments person.fullName = 'John Doe'
  19. Setters person fullName Calls the set function passing 'John Doe'

    to it set: function firstName value: '' lastName value: '' person.fullName = 'John Doe' Multiple Assignments
  20. Setters Multiple Assignments person fullName set: function firstName value: ''

    lastName value: '' person fullName set: function firstName value: 'John' lastName value: 'Doe' Calls the set function passing 'John Doe' to it person.fullName = 'John Doe'
  21. Setters Multiple Assignments person fullName set: function firstName value: ''

    lastName value: '' person fullName set: function firstName value: 'John' lastName value: 'Doe' Calls the set function passing 'John Doe' to it person.fullName = 'John Doe'
  22. Setters Multiple Assignments person fullName set: function firstName value: ''

    lastName value: '' Be careful not to set fullName again inside the setter fullName set: function
  23. Setters Multiple Assignments person fullName set: function firstName value: ''

    lastName value: '' Be careful not to set fullName again inside the setter fullName set: function INFINITE RECURSION!
  24. Setters Multiple Assignments person fullName set: function firstName value: ''

    lastName value: '' Be careful not to set fullName again inside the setter You can use a getter to concatenate firstName and lastName
  25. Proxy Wrapper handler get set: function set set: function target

    firstName value: 'John' lastName value: 'Doe' Traps A PROXY’S COMPOSITION
  26. Proxy Wrapper target firstName value: 'John' lastName value: 'Doe' const

    p = new Proxy(target, handler); HOW PROXIES WORK
  27. Proxy Wrapper target firstName value: 'John' lastName value: 'Doe' handler

    get function set function const p = new Proxy(target, handler); HOW PROXIES WORK
  28. const p = new Proxy(target, handler); p Proxy Wrapper target

    firstName value: 'John' lastName value: 'Doe' handler get function set function HOW PROXIES WORK
  29. const p = new Proxy(target, handler); p.name Asks the wrapper

    for this property Proxy Wrapper target firstName value: 'John' lastName value: 'Doe' handler get function set function HOW PROXIES WORK
  30. handler get set function const p = new Proxy(target, handler);

    p.name Calls the get trap passing target and the property’s name target firstName value: 'John' lastName value: 'Doe' Proxy Wrapper function HOW PROXIES WORK
  31. Proxy Wrapper handler get function set function const p =

    new Proxy(target, handler); p.name Returns the value returned by the get trap target firstName value: 'John' lastName value: 'Doe' HOW PROXIES WORK
  32. 0 1 2 0 2 4 evens[0] Proxy Wrapper get

    function Infinite Arrays
  33. 0 1 2 0 2 4 evens[0] Proxy Wrapper get

    function Infinite Arrays
  34. 0 1 2 0 2 4 evens[0] Proxy Wrapper get

    function Infinite Arrays
  35. 0 1 2 0 2 4 evens[0] Proxy Wrapper get

    function Infinite Arrays
  36. 0 1 2 0 2 4 evens[0] Proxy Wrapper get

    function Infinite Arrays
  37. 0 1 2 3 0 2 4 undefined evens[3] Proxy

    Wrapper get function Infinite Arrays
  38. 0 1 2 3 0 2 4 undefined evens[3] Proxy

    Wrapper get function Infinite Arrays
  39. 0 1 2 3 0 2 4 undefined evens[3] Infinite

    Arrays Proxy Wrapper get function
  40. 0 1 2 3 0 2 4 undefined evens[3] Proxy

    Wrapper get function Calculates the value that should have been in the index 3 Infinite Arrays
  41. 0 1 2 3 0 2 4 undefined evens[3] Proxy

    Wrapper get function Calculates the value that should have been in the index 3 Infinite Arrays
  42. Property Suggestions person target firstName value: 'John' lastName value: 'Doe'

    handler get function set function typo! person.firstNsme
  43. person target firstName value: 'John' lastName value: 'Doe' handler get

    function set function Property Suggestions person.firstNsme
  44. person target firstName value: ‘John' lastName value: ‘Doe' handler get

    function set function person.firstNsme Property Suggestions
  45. person target firstName value: 'John' lastName value: 'Doe' handler get

    function set function pessoa.seuNome Perhaps you meant: "firstName"? Property Suggestions
  46. Property Suggestions expect({}).to.be.a.strng assertion target handler get function set function

    Checks if property assertion exists here This does not exist Perhaps you meant: 'string'
  47. const p = new Proxy(obj, { get: (target, propName) =>

    { console.log('[GET] ' + propName); return Reflect.get(target, propName);
 } }); “Reflecting" Operations
  48. const p = new Proxy(obj, { get: (target, propName) =>

    { console.log('[GET] ' + propName); return Reflect.get(target, propName);
 } }); “Reflecting" Operations Trap Name == Reflect Method’s Name
  49. symbols new Symbol('description') the new keyword denotes the creation of

    a new object returns a symbol (primitive) Symbol('description')
  50. Symbol('id') !== Symbol('id') Symbol.for('id') === Symbol.for('id') Be careful with the

    global registry A symbol is unique These two return the exact same primitive
  51. markTimestamp(person) person firstName value: 'John' lastName value: 'Doe' timestamp value:

    1481236691 symbols in the real world person firstName value: 'John' lastName value: 'Doe'
  52. Easily overwritten by mistake/namespace clash symbols in the real world

    markTimestamp(person) person firstName value: 'John' lastName value: 'Doe' timestamp value: 1481236691 person firstName value: 'John' lastName value: 'Doe'
  53. pessoa nome value: 'João' sobrenome value: 'Silva' person firstName value:

    'John' lastName value: 'Doe' symbols in the real world
  54. person firstName value: 'John' lastName value: 'Doe' symbol(time) value: 1481236691

    symbols in the real world markTimestamp(person) person firstName value: 'John' lastName value: 'Doe'
  55. We will never have an unintentional assignment person firstName value:

    'John' lastName value: 'Doe' symbol(time) value: 1481236691 symbols in the real world markTimestamp(person) person firstName value: 'John' lastName value: 'Doe'
  56. Indexes the function used to check if an object is

    an instance of a constructor Well Known Symbols Symbol.hasInstance