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. JAVASCRIPT BEHIND THE SCENES
    META PROGRAMMING
    LUCASFCOSTA LFERNANDESCOSTA

    View full-size slide

  2. WHAT IS META
    PROGRAMMING?

    View full-size slide

  3. META PROGRAMMING IS
    A PROGRAMMING
    TECHNIQUE IN WHICH
    PROGRAMS CAN TREAT
    PROGRAMS AS INPUT

    View full-size slide

  4. This is Meta Programming

    View full-size slide

  5. But this is not exactly what we will be talking about
    This is Meta Programming

    View full-size slide

  6. Meta Level
    JavaScript
    But this is not exactly what we will be talking about
    This is Meta Programming

    View full-size slide

  7. 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

    View full-size slide

  8. Reflective Meta
    Programming

    View full-size slide

  9. Reflective Meta
    Programming
    Introspection

    View full-size slide

  10. Reflective Meta
    Programming
    Introspection
    Self-modification

    View full-size slide

  11. Reflective Meta
    Programming
    Introspection
    Self-modification
    Intercession

    View full-size slide

  12. Meta Object Protocol

    View full-size slide

  13. Meta Object Protocol
    Provides a vocabulary to
    access and manipulate
    the structure and behavior
    of systems of objects
    https://en.wikipedia.org/wiki/Metaobject

    View full-size slide

  14. Meta Object Protocol
    ecma-international.org/ecma-262

    View full-size slide

  15. Meta Object Protocol
    ecma-international.org/ecma-262

    View full-size slide

  16. Meta Object Protocol
    ecma-international.org/ecma-262

    View full-size slide

  17. Object.*
    METHODS

    View full-size slide

  18. Object.* Methods

    View full-size slide

  19. Object.* Methods
    Object.keys()

    View full-size slide

  20. Object.* Methods
    Object.keys()
    Object.assign()

    View full-size slide

  21. Object.* Methods
    Object.keys()
    Object.assign()
    Object.hasOwnProperty()

    View full-size slide

  22. Object.* Methods
    Object.keys()
    Object.assign()
    Object.hasOwnProperty()
    Object.getPrototypeOf()

    View full-size slide

  23. PROPERTY
    DESCRIPTORS

    View full-size slide

  24. Property Descriptors
    Objects that
    describe properties’
    characteristics

    View full-size slide

  25. Property Descriptors
    myObject
    myProperty

    View full-size slide

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

    View full-size slide

  27. Property Descriptors
    myObject
    value enumerable writable configurable get set
    any boolean boolean boolean function function
    myProperty This is a Property
    Descriptor

    View full-size slide

  28. Indicates the property’s value
    value enumerable writable configurable get set
    any boolean boolean boolean function function
    Property Descriptors

    View full-size slide

  29. Indicates if this property shows
    up when enumerating properties
    value enumerable writable configurable get set
    any boolean boolean boolean function function
    Property Descriptors

    View full-size slide

  30. 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

    View full-size slide

  31. 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

    View full-size slide

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

    View full-size slide

  33. 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

    View full-size slide

  34. value enumerable writable configurable get set
    any boolean boolean boolean function function
    Property Descriptors

    View full-size slide

  35. Property Descriptors
    Object.defineProperty

    View full-size slide

  36. Property Descriptors
    Object.defineProperty
    Parameters

    View full-size slide

  37. Property Descriptors
    Object.defineProperty
    obj
    Parameters

    View full-size slide

  38. Property Descriptors
    Object.defineProperty
    obj propName
    Parameters

    View full-size slide

  39. Property Descriptors
    Object.defineProperty
    obj propName descriptor
    Parameters

    View full-size slide

  40. Property Descriptors
    Object.getOwnPropertyDescriptor

    View full-size slide

  41. Property Descriptors
    Object.getOwnPropertyDescriptor
    Parameters

    View full-size slide

  42. Property Descriptors
    Object.getOwnPropertyDescriptor
    obj
    Parameters

    View full-size slide

  43. Property Descriptors
    Object.getOwnPropertyDescriptor
    obj propName
    Parameters

    View full-size slide

  44. Property Descriptors
    Object.getOwnPropertyDescriptor
    obj propName
    Parameters
    Does not work for inherited properties!

    View full-size slide

  45. Property Descriptors
    Object.getOwnPropertyDescriptor
    obj propName
    Parameters
    Use Object.getPrototypeOf to go up the chain

    View full-size slide

  46. Getters
    Lazy Properties

    View full-size slide

  47. Getters
    Lazy Properties
    Properties calculated
    only when needed

    View full-size slide

  48. Getters
    Lazy Properties
    basket
    fruits
    {bananas: 1, oranges: 1}

    View full-size slide

  49. Getters
    Lazy Properties
    basket
    dataNasc
    value: 08/05/1995
    weight
    400
    fruits
    {bananas: 1, oranges: 1}

    View full-size slide

  50. Getters
    Lazy Properties
    basket
    dataNasc
    value: 08/05/1995
    weight
    600
    fruits
    {bananas: 2, oranges: 1}

    View full-size slide

  51. Getters
    Lazy Properties
    basket
    dataNasc
    value: 08/05/1995
    weight
    800
    fruits
    {bananas: 3, oranges: 1}

    View full-size slide

  52. Getters
    Lazy Properties
    basket
    dataNasc
    value: 08/05/1995
    weight
    800
    fruits
    {bananas: 3, oranges: 1}
    Too many assignments to
    the weight property!

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  55. 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

    View full-size slide

  56. 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

    View full-size slide

  57. 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

    View full-size slide

  58. Getters
    Fluid APIs
    expect('word').to.be.a('string');
    expect([1, 2, 3]).to.have.length(3);

    View full-size slide

  59. Getters
    Fluid APIs
    expect('word').to.be.a('string');
    Wraps expect's
    arguments into an
    Assertion object

    View full-size slide

  60. Getters
    Fluid APIs
    expect('word').to.be.a('string');
    These properties have
    getter functions that just
    return the Assertion itself

    View full-size slide

  61. Getters
    Fluid APIs
    expect('word').to.be.a('string');
    This is a method in the
    Assertion object which
    actually does the check

    View full-size slide

  62. Setters
    Multiple Assignments
    person
    fullName
    set: function
    firstName
    value: ''
    lastName
    value: ''

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  65. 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'

    View full-size slide

  66. 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'

    View full-size slide

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

    View full-size slide

  68. 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!

    View full-size slide

  69. 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

    View full-size slide

  70. What are Proxies?
    Proxies are object
    wrappers which allow
    us to intercept
    operations

    View full-size slide

  71. Proxy Wrapper
    handler
    get
    set: function
    set
    set: function
    target
    firstName
    value: 'John'
    lastName
    value: 'Doe'
    Traps
    A PROXY’S COMPOSITION

    View full-size slide

  72. HOW PROXIES WORK
    Proxy Wrapper
    const p = new Proxy(target, handler);

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  76. 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

    View full-size slide

  77. 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

    View full-size slide

  78. 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

    View full-size slide

  79. List Comprehensions
    Infinite
    Arrays

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  88. 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

    View full-size slide

  89. 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

    View full-size slide

  90. Infinite
    Arrays

    View full-size slide

  91. Property
    Suggestions
    Helps your API's
    users figure out what
    is the correct way to
    use it

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  96. person
    target
    firstName
    value: 'John'
    lastName
    value: 'Doe'
    handler
    get
    function
    set
    function
    pessoa.seuNome
    Perhaps you meant:
    "firstName"?
    Property
    Suggestions

    View full-size slide

  97. Property
    Suggestions
    expect({}).to.be.a.strng
    TYPO!

    View full-size slide

  98. Property
    Suggestions
    expect({}).to.be.a.strng
    Trying to access a
    non-existing property
    returns undefined

    View full-size slide

  99. Property
    Suggestions
    expect({}).to.be.a.strng
    assertion
    target
    handler
    get
    function
    set
    function
    Checks if
    property
    assertion
    exists here

    View full-size slide

  100. 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'

    View full-size slide

  101. “Reflecting" Operations
    ES6 Reflect

    View full-size slide

  102. ES6 Reflect
    Reflect.get
    “Reflecting" Operations

    View full-size slide

  103. ES6 Reflect
    Reflect.get
    Reflect.set
    “Reflecting" Operations

    View full-size slide

  104. ES6 Reflect
    Reflect.get
    Reflect.set
    Reflect.[[trapName]]
    “Reflecting" Operations

    View full-size slide

  105. const p = new Proxy(obj, {
    get: (target, propName) => {
    console.log('[GET] ' + propName);
    return Reflect.get(target, propName);

    }
    });
    “Reflecting" Operations

    View full-size slide

  106. 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

    View full-size slide

  107. What are symbols?
    A new primitive type

    View full-size slide

  108. "Symbols are all about Reflection
    within implementation"
    Keith Cirkel
    What are symbols?
    A new primitive type

    View full-size slide

  109. symbol Symbol
    !==

    View full-size slide

  110. symbol Symbol
    !==
    Primitive Type

    View full-size slide

  111. symbol Symbol
    !==
    Primitive Type Object Wrapper

    View full-size slide

  112. symbols
    new Symbol('description')

    View full-size slide

  113. symbols
    new Symbol('description')

    View full-size slide

  114. symbols
    new Symbol('description')
    the new keyword
    denotes the creation
    of a new object

    View full-size slide

  115. symbols
    new Symbol('description')
    the new keyword
    denotes the creation
    of a new object
    returns a symbol
    (primitive)
    Symbol('description')

    View full-size slide

  116. symbols
    new Symbol('description')
    Symbol('description')
    the new keyword
    denotes the creation
    of a new object
    returns a symbol
    (primitive)

    View full-size slide

  117. PRIMITIVE
    SYMBOLS ARE
    UNIQUE

    View full-size slide

  118. A symbol is unique
    Symbol('id') !== Symbol('id')

    View full-size slide

  119. Symbol('id') !== Symbol('id')
    A symbol is unique
    Symbol.for('id') === Symbol.for('id')
    Be careful with the global registry

    View full-size slide

  120. 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

    View full-size slide

  121. symbols in the real world
    person
    firstName
    value: 'John'
    lastName
    value: 'Doe'

    View full-size slide

  122. markTimestamp(person)
    symbols in the real world
    person
    firstName
    value: 'John'
    lastName
    value: 'Doe'

    View full-size slide

  123. markTimestamp(person)
    person
    firstName
    value: 'John'
    lastName
    value: 'Doe'
    timestamp
    value: 1481236691
    symbols in the real world
    person
    firstName
    value: 'John'
    lastName
    value: 'Doe'

    View full-size slide

  124. 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'

    View full-size slide

  125. pessoa
    nome
    value: 'João'
    sobrenome
    value: 'Silva'
    person
    firstName
    value: 'John'
    lastName
    value: 'Doe'
    symbols in the real world

    View full-size slide

  126. symbols in the real world
    markTimestamp(person)
    person
    firstName
    value: 'John'
    lastName
    value: 'Doe'

    View full-size slide

  127. 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'

    View full-size slide

  128. 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'

    View full-size slide

  129. Symbols used to drive
    the language’s native
    implementations
    Well Known Symbols

    View full-size slide

  130. Indexes the function used to
    check if an object is an instance
    of a constructor
    Well Known Symbols
    Symbol.hasInstance

    View full-size slide

  131. Well Known Symbols
    Symbol.hasInstance
    bristol instanceof AwesomePlace

    View full-size slide

  132. Well Known Symbols
    Symbol.hasInstance
    AwesomePlace[Symbol.hasInstance](bristol)
    bristol instanceof AwesomePlace

    View full-size slide

  133. Well Known Symbols
    Symbol.hasInstance

    View full-size slide

  134. Well Known Symbols

    View full-size slide

  135. Well Known Symbols
    Symbol.toPrimitive

    View full-size slide

  136. Well Known Symbols
    Symbol.toPrimitive
    Symbol.toStringTag

    View full-size slide

  137. Well Known Symbols
    Symbol.toPrimitive
    Symbol.toStringTag
    Symbol.iterator

    View full-size slide

  138. Well Known Symbols
    Symbol.toPrimitive
    Symbol.toStringTag
    Symbol.iterator
    And many others…

    View full-size slide

  139. THANK YOU!
    MORE DETAILS AT LUCASFCOSTA.COM
    LUCASFCOSTA LFERNANDESCOSTA

    View full-size slide