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

Charadinhas de JavaScript

Charadinhas de JavaScript

O que esse código faz? Será que printa alguma coisa? Ou vai dar erro? Dependeria se é no Node ou no browser? Nessa talk apresentarei várias charadinhas com mistérios do JS e HTML, e explicarei cada uma delas!
Serão charadinhas bem mais elaboradas e imprevisíveis do que questões já repetitivas como [] + {}, ou coisas assim. Duvido que você acerte a última charadinha!

Avatar for Bruno Macabeus

Bruno Macabeus

October 25, 2024
Tweet

More Decks by Bruno Macabeus

Other Decks in Programming

Transcript

  1. ✨ nada daqui deve ser usado em produção ✨ (apesar

    de que algumas charadinhas possam ter sido inspiradas em código de prod 🙈)
  2. GAME TIME • CHARADINHA #1 > 'magic' é printado imediatamente

    1x setTimeout(() => { console.log('magic') }, Infinity)
  3. GAME TIME • CHARADINHA #1 O Infinity é convertido para

    1 (ou 0) quando usado como argumento no setTimeout, o que implica ser executado no próximo tick.
  4. GAME TIME • CHARADINHA #1 Mas isso não era padronizado.

    Nas versões antigas do IE e no Opera, o comportamento era nunca chamar o callback.
  5. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 }
 
 for (let y = 0; y < 2; y++) { setTimeout(() => console.log(y))
 }
  6. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 }
 
 for (let y = 0; y < 2; y++) { setTimeout(() => console.log(y))
 } for ( ) {
 
 }
 
 for ( ) { 
 }
  7. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 }
 
 for (let y = 0; y < 2; y++) { setTimeout(() => console.log(y))
 } for (var x = 0; ) {
 
 }
 
 for (let y = 0; ) { 
 }
  8. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 }
 
 for (let y = 0; y < 2; y++) { setTimeout(() => console.log(y))
 } for ( ) {
 setTimeout(() => console.log(x))
 }
 
 for ( ) { setTimeout(() => console.log(y))
 }
  9. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 }
 
 for (let y = 0; y < 2; y++) { setTimeout(() => console.log(y))
 }
  10. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 }
 
 for (let y = 0; y < 2; y++) { setTimeout(() => console.log(y))
 }
  11. GAME TIME • CHARADINHA #2 > 2 2 0 1

    for (var x = 0; x < 2; x++) {
 setTimeout(() => console.log(x))
 }
 
 for (let y = 0; y < 2; y++) { setTimeout(() => console.log(y))
 }
  12. GAME TIME • CHARADINHA #2 Isso é confuso pois o

    comportamento do for é diferente quando usando var ou let
  13. GAME TIME • CHARADINHA #2 Quando usando var, a variável

    é compartilhada em cada iteração:
  14. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks Variáveis
  15. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 0 Variáveis
  16. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 0 Variáveis
  17. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } setTimetout(() => console.log(x)) Tasks var x = 0 Variáveis
  18. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 0 setTimetout(() => console.log(x)) Variáveis
  19. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 1 setTimetout(() => console.log(x)) Variáveis
  20. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 1 setTimetout(() => console.log(x)) Variáveis
  21. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks setTimetout(() => console.log(x)) var x = 1 setTimetout(() => console.log(x)) Variáveis
  22. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 1 setTimetout(() => console.log(x)) setTimetout(() => console.log(x)) Variáveis
  23. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 2 setTimetout(() => console.log(x)) setTimetout(() => console.log(x)) Variáveis
  24. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 2 setTimetout(() => console.log(x)) setTimetout(() => console.log(x)) Variáveis
  25. GAME TIME • CHARADINHA #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 2 setTimetout(() => console.log(x)) setTimetout(() => console.log(x)) Variáveis
  26. GAME TIME • CHARADINHA #2 Quando usando let, um novo

    escopo léxico é criado para cada iteração:
  27. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks Variáveis
  28. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 Variáveis
  29. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks setTimetout(() => console.log(y_iteration_1)) let y_iteration_1 = 0 Variáveis
  30. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 setTimetout(() => console.log(y_iteration_1)) Variáveis
  31. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 let y_iteration_2 = 1 setTimetout(() => console.log(y_iteration_1)) Variáveis
  32. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 let y_iteration_2 = 1 setTimetout(() => console.log(y_iteration_1)) Variáveis
  33. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks setTimetout(() => console.log(y_iteration_2)) let y_iteration_1 = 0 let y_iteration_2 = 1 setTimetout(() => console.log(y_iteration_1)) Variáveis
  34. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 let y_iteration_2 = 1 setTimetout(() => console.log(y_iteration_2)) setTimetout(() => console.log(y_iteration_1)) Variáveis
  35. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 let y_iteration_2 = 1 let y_iteration_2 = 2 setTimetout(() => console.log(y_iteration_2)) setTimetout(() => console.log(y_iteration_1)) Variáveis
  36. GAME TIME • CHARADINHA #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 let y_iteration_2 = 1 let y_iteration_2 = 2 setTimetout(() => console.log(y_iteration_2)) setTimetout(() => console.log(y_iteration_1)) Variáveis
  37. GAME TIME • CHARADINHA #2 let y_iteration_2 = 1 let

    y_iteration_2 = 2 for (let y = 0; y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 setTimetout(() => console.log(y_iteration_2)) setTimetout(() => console.log(y_iteration_1)) Variáveis
  38. GAME TIME • CHARADINHA #2 for ( let z =

    { foo: 0 }; z.foo < 2; z.foo++ ) {
 setTimeout(() => console.log(z.foo))
 }
  39. GAME TIME • CHARADINHA #2 for ( let z =

    { foo: 0 }; z.foo < 2; z.foo++ ) {
 setTimeout(() => console.log(z.foo))
 } // 2 2
  40. GAME TIME • CHARADINHA #2 Vejamos como o for é

    de fi nido na spec! https://262.ecma-international.org/14.0
  41. GAME TIME • CHARADINHA #3 // 1. Loose equality 0

    == -0 // true 0n == -0n // true
  42. GAME TIME • CHARADINHA #3 // 1. Loose equality 0

    == -0 // true 0n == -0n // true // ^ o `n` significa bigint
  43. GAME TIME • CHARADINHA #3 // 1. Loose equality 0

    == -0 // true 0n == -0n // true
  44. GAME TIME • CHARADINHA #3 // 2. Strict equality 0

    === -0 // true 0n === -0n // true
  45. GAME TIME • CHARADINHA #3 Vejamos o SameValue na spec

    do JS! https://262.ecma-international.org/14.0
  46. GAME TIME • CHARADINHA #4 <div id="magic">foo</div> <script> document .documentElement

    .innerHTML += '<div id="magic">bar</div>' console.log(magic.innerHTML) </script>
  47. GAME TIME • CHARADINHA #4 <div id="magic">foo</div> <script> document .documentElement

    .innerHTML += '<div id="magic">bar</div>' console.log(magic.innerHTML) </script> <div id="magic">foo</div>
  48. GAME TIME • CHARADINHA #4 <div id="magic">foo</div> <script> document .documentElement

    .innerHTML += '<div id="magic">bar</div>' console.log(magic.innerHTML) </script> <script> document .documentElement .innerHTML += '<div id="magic">bar</div>' </script>
  49. GAME TIME • CHARADINHA #4 <div id="magic">foo</div> <script> document .documentElement

    .innerHTML += '<div id="magic">bar</div>' console.log(magic.innerHTML) </script> <script> console.log(magic.innerHTML) </script>
  50. GAME TIME • CHARADINHA #4 <div id="magic">foo</div> <script> document .documentElement

    .innerHTML += '<div id="magic">bar</div>' console.log(magic.innerHTML) </script>
  51. GAME TIME • CHARADINHA #4 <div id="magic">foo</div> <script> document .documentElement

    .innerHTML += '<div id="magic">bar</div>' console.log(magic.innerHTML) </script>
  52. GAME TIME • CHARADINHA #4 <div id="magic">foo</div> <script> document .documentElement

    .innerHTML += '<div id="magic">bar</div>' console.log(magic.innerHTML) </script> > undefined
  53. GAME TIME • CHARADINHA #4 Isso é confuso pois o

    código usa um code smell de uma feature do HTML já legada e não recomendada
  54. GAME TIME • CHARADINHA #4 Vejamos a spec do HTML

    https://html.spec.whatwg.org/ vs.
  55. GAME TIME • CHARADINHA #4 A spec de fi ne

    quando um elemento é exposed. Ou seja, quando ele fi ca acessível no window
  56. GAME TIME • CHARADINHA #4 <!-- uma div com id

    --> <div id="foo"></div> <script> window.foo // `Element` de `<div id="foo"></div>` </script>
  57. GAME TIME • CHARADINHA #4 <!-- uma div com id

    --> <div id="foo"></div> <script> foo // `Element` de `<div id="foo"></div>` </script>
  58. GAME TIME • CHARADINHA #4 <!-- uma img com name

    --> <img name="foo" /> <script> foo // `Element` de `<img name="foo" />` </script>
  59. GAME TIME • CHARADINHA #4 <!-- o mesmo acontece quando

    o DOM é atualizado --> <script> document .documentElement .innerHTML = '<div id="foo">blah</div>' foo // `Element` de `<div id="foo">blah</div>` </script>
  60. GAME TIME • CHARADINHA #4 <!-- e se tivermos duas

    img com mesmo nome? --> <img name="duplicated" /> <img name="duplicated" /> <script> duplicated /* HTMLCollection(2) [ img, img, duplicated: img ] */ </script>
  61. GAME TIME • CHARADINHA #4 <!-- e se for o

    id? --> <div id="duplicated" /> <div id="duplicated" /> <script> duplicated /* HTMLCollection(2) [ div, div, duplicated: div ] */ </script>
  62. GAME TIME • CHARADINHA #4 Como o HTMLCollection não tem

    a property innerHTML, magic.innerHTML retorna undefined.
  63. GAME TIME • CHARADINHA #4 Como o HTMLCollection não tem

    a property innerHTML, magic.innerHTML retorna undefined. Porém, tem um bug no Firefox, e ele retorna o primeiro Element!
  64. GAME TIME • CHARADINHA #4 <div id="magic">foo</div> <div id="magic">bar</div> <script>

    magic /* Deve retornar `HTMLCollection` Porém, no Firefox retorna o primeiro `Element` */ </script>
  65. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) )
  66. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) ) ( , )
  67. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) ) ( class Magic { static console = console.log('foo') }, )
  68. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) ) ( , console.log(Magic.name) )
  69. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) )
  70. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) ) > printa 'foo' e lança exceção em runtime
  71. GAME TIME • CHARADINHA #5 Isso é confuso pois temos

    o ClassExpression e o comma operator
  72. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) )
  73. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) ) ( // isso força que o class se torna uma expressão )
  74. GAME TIME • CHARADINHA #5 // A keyword `class` pode

    ser: // ClassDeclaration: no contexto de statement class Magic { } // ClassExpression: no contexto de expression const M = class Magic { } ( class Magic { } )
  75. GAME TIME • CHARADINHA #5 // A keyword `class` pode

    ser: // ClassDeclaration: no contexto de statement class Magic { } // ClassExpression: no contexto de expression const M = class Magic { } ( class Magic { } )
  76. GAME TIME • CHARADINHA #5 // A keyword `class` pode

    ser: // ClassDeclaration: no contexto de statement class Magic { } // ClassExpression: no contexto de expression const M = class Magic { } ( class Magic { } )
  77. GAME TIME • CHARADINHA #5 const M = class Magic

    { myself = () => Magic // funciona } console.log(Magic) // lança ReferenceError Quando usando o ClassExpression, o nome da class é visível apenas dentro do escopo da class em si
  78. GAME TIME • CHARADINHA #5 Algo bem parecido também acontece

    com function // FunctionDeclaration function magic() { } magic() // consegue acessar o nome da função // FunctionExpression const foo = function magic() { } magic() // lança ReferenceError
  79. GAME TIME • CHARADINHA #5 Algo bem parecido também acontece

    com function // FunctionDeclaration function magic() { } magic() // consegue acessar o nome da função // FunctionExpression const foo = function magic() { } magic() // lança ReferenceError
  80. GAME TIME • CHARADINHA #5 Algo bem parecido também acontece

    com function // FunctionDeclaration function magic() { } magic() // consegue acessar o nome da função // FunctionExpression const foo = function magic() { } magic() // lança ReferenceError
  81. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) )
  82. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') } console.log(Magic.name) ) , // comma operator
  83. GAME TIME • CHARADINHA #5 O comma operator recebe uma

    lista de expressões e avalia cada item, retornando o último deles
  84. GAME TIME • CHARADINHA #5 ['a1', 'b2', ‘c3'].reduce( (state, pair)

    => { state[pair[0]] = pair[1] return state }, {} ) // {a: '1', b: '2', c: ‘3'}
  85. GAME TIME • CHARADINHA #5 ['a1', 'b2', ‘c3'].reduce( (state, pair)

    => { state[pair[0]] = pair[1] return state }, {} ) // {a: '1', b: '2', c: ‘3'} ['a1', 'b2', 'c3'].reduce( (state, pair) => (state[pair[0]] = pair[1], state), {} ) // {a: '1', b: '2', c: '3'}
  86. GAME TIME • CHARADINHA #5 (state, pair) => { state[pair[0]]

    = pair[1] return state }, (state, pair) => (state[pair[0]] = pair[1], state), ['a1', 'b2', ‘c3'].reduce( (state, pair) => { state[pair[0]] = pair[1] return state }, {} ) // {a: '1', b: '2', c: ‘3'} ['a1', 'b2', 'c3'].reduce( (state, pair) => (state[pair[0]] = pair[1], state), {} ) // {a: '1', b: '2', c: '3'}
  87. GAME TIME • CHARADINHA #5 Normalmente, nós não usamos o

    comma operator diretamente. Porém, nossos compiladores o usam frequentemente por duas razões.
  88. GAME TIME • CHARADINHA #5 // 1. minificar o código

    if(x){foo();return bar()}else{return 1} // é equivalente a return x?(foo(),bar()):1
  89. GAME TIME • CHARADINHA #5 // 2. spec complaince //

    foo.ts export function foo() { return this } // index.ts import { foo } from './foo.ts'
 foo() // retorna undefined // tsc compila para (0, foo())
  90. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) )
  91. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) ) ( class Magic { static console = console.log('foo') }, )
  92. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) ) ( , console.log( ) )
  93. GAME TIME • CHARADINHA #5 ( class Magic { static

    console = console.log('foo') }, console.log(Magic.name) ) ( , console.log(Magic.name) )
  94. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start()
  95. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start() this.message = 'foo'
  96. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start() class Magic { message = 'bar' say() { } start() { } }
  97. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start() class Magic { message = 'bar' say() { console.log(this.message) } start() { } }
  98. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start() class Magic { message = 'bar' say() { } start() { setTimeout(this.say, 1000); } }
  99. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start() const m = new Magic() m.start()
  100. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start()
  101. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start()
  102. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start() > 'foo' ou undefined
  103. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start() > 'foo' ou undefined (depende do environment 🙃)
  104. GAME TIME • CHARADINHA #6 é muito implícito e dinâmico,

    e o comportamento do setTimeout varia com o environment Isso é confuso pois o this
  105. GAME TIME • CHARADINHA #6 const foo = { a:

    1, printA: function () { console.log(this.a) }, }
  106. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, }
  107. GAME TIME • CHARADINHA #6 function magic(callback) { this.a =

    2 callback() } foo.printA() // 1 const foo = { a: 1, printA: function () { console.log(this.a) }, }
  108. GAME TIME • CHARADINHA #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) function magic(callback)

    { this.a = 2 callback() } foo.printA() // 1 const foo = { a: 1, printA: function () { console.log(this.a) }, }
  109. GAME TIME • CHARADINHA #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) function magic(callback)

    { this.a = 2 callback() } foo.printA() // 1 const foo = { a: 1, printA: function () { console.log(this.a) }, }
  110. GAME TIME • CHARADINHA #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) function magic(callback)

    { this.a = 2 callback() } foo.printA() // 1 const foo = { a: 1, printA: function () { console.log(this.a) }, }
  111. GAME TIME • CHARADINHA #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) foo.printA() //

    1 const foo = { a: 1, printA: function () { console.log(this.a) }, } function magic(callback) { this.a = 2 // o `this` é o contexto global callback() }
  112. GAME TIME • CHARADINHA #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) foo.printA() //

    1 const foo = { a: 1, printA: function () { console.log(this.a) }, } function magic(callback) { this.a = 2 // o `this` é o contexto global callback() }
  113. GAME TIME • CHARADINHA #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) foo.printA() //

    1 const foo = { a: 1, printA: function () { console.log(this.a) }, } function magic(callback) { this.a = 2 // o `this` é o contexto global callback() }
  114. GAME TIME • CHARADINHA #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) foo.printA() //

    1 const foo = { a: 1, printA: function () { console.log(this.a) }, // o `this` aqui } // também é o // contexto global function magic(callback) { this.a = 2 // o `this` é o contexto global callback() }
  115. GAME TIME • CHARADINHA #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) foo.printA() //

    1 const foo = { a: 1, printA: function () { console.log(this.a) }, // o `this` aqui } // também é o // contexto global // = printa `2` function magic(callback) { this.a = 2 // o `this` é o contexto global callback() }
  116. GAME TIME • CHARADINHA #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) foo.printA() //

    1 const foo = { a: 1, printA: function () { console.log(this.a) }, // o `this` aqui } // também é o // contexto global // = printa `2` function magic(callback) { this.a = 2 // o `this` é o contexto global callback() }
  117. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, // o `this` aqui } // também é o // contexto global // = printa `2` magic(foo.printA) console.log(foo.a) // 1 console.log(globalThis.a) function magic(callback) { this.a = 2 // o `this` é o contexto global callback() }
  118. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, // o `this` aqui } // também é o // contexto global // = printa `2` magic(foo.printA) console.log(foo.a) // 1 console.log(globalThis.a) function magic(callback) { this.a = 2 // o `this` é o contexto global callback() }
  119. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, // o `this` aqui } // também é o // contexto global // = printa `2` magic(foo.printA) console.log(foo.a) // 1 console.log(globalThis.a) // 2 function magic(callback) { this.a = 2 // o `this` é o contexto global callback() }
  120. GAME TIME • CHARADINHA #6 foo.printA() // 1 function magic(callback)

    { this.a = 2 callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, } magic(foo.printA) console.log(foo.a) console.log(globalThis.a)
  121. GAME TIME • CHARADINHA #6 foo.printA() // 1 function magic(callback)

    { this.a = 2 callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, } magic(foo.printA) console.log(foo.a) console.log(globalThis.a) 'use strict'
  122. GAME TIME • CHARADINHA #6 foo.printA() // 1 function magic(callback)

    { this.a = 2 callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, } magic(foo.printA) console.log(foo.a) console.log(globalThis.a) 'use strict'
  123. GAME TIME • CHARADINHA #6 foo.printA() // 1 function magic(callback)

    { this.a = 2 callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, } magic(foo.printA) console.log(foo.a) console.log(globalThis.a) 'use strict'
  124. GAME TIME • CHARADINHA #6 foo.printA() // 1 function magic(callback)

    { this.a = 2 callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, } magic(foo.printA) console.log(foo.a) console.log(globalThis.a) 'use strict'
  125. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, } magic(foo.printA) console.log(foo.a) console.log(globalThis.a) 'use strict' function magic(callback) { this.a = 2 // com strict mode, o `this` aqui é `undefined` callback() }
  126. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, } magic(foo.printA) console.log(foo.a) console.log(globalThis.a) 'use strict' function magic(callback) { this.a = 2 // undefined.a -> erro! callback() }
  127. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, } magic(foo.printA) console.log(foo.a) console.log(globalThis.a) 'use strict' function magic(callback) { this.a = 2 callback() }
  128. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, } 'use strict' function magic(callback) { this.a = 2 callback() } magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a)
  129. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, } 'use strict' function magic(callback) { this.a = 2 callback() } magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a)
  130. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, } 'use strict' function magic(callback) { this.a = 2 callback() } magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a)
  131. GAME TIME • CHARADINHA #6 foo.printA() // 1 const foo

    = { a: 1, printA: function () { console.log(this.a) }, } 'use strict' magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a) function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  132. GAME TIME • CHARADINHA #6 foo.printA() // 1 'use strict'

    magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a) const foo = { a: 1, 2, printA: function () { console.log(this.a) }, } function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  133. GAME TIME • CHARADINHA #6 foo.printA() // 1 'use strict'

    magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a) const foo = { a: 1, 2, printA: function () { console.log(this.a) }, } function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  134. GAME TIME • CHARADINHA #6 foo.printA() // 1 'use strict'

    magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a) const foo = { a: 1, 2, printA: function () { console.log(this.a) }, } function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  135. GAME TIME • CHARADINHA #6 foo.printA() // 1 'use strict'

    magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a) const foo = { a: 1, 2, printA: function () { console.log(this.a) }, // `this` é `foo` } function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  136. GAME TIME • CHARADINHA #6 foo.printA() // 1 'use strict'

    magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a) const foo = { a: 1, 2, printA: function () { console.log(this.a) }, // `this` é `foo` } // = printa `2` function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  137. GAME TIME • CHARADINHA #6 foo.printA() // 1 'use strict'

    magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) console.log(globalThis.a) const foo = { a: 1, 2, printA: function () { console.log(this.a) }, // `this` é `foo` } // = printa `2` function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  138. GAME TIME • CHARADINHA #6 foo.printA() // 1 'use strict'

    magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) // 2 console.log(globalThis.a) const foo = { a: 1, 2, printA: function () { console.log(this.a) }, // `this` é `foo` } // = printa `2` function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  139. GAME TIME • CHARADINHA #6 foo.printA() // 1 'use strict'

    const foo = { a: 1, 2, printA: function () { console.log(this.a) }, // `this` é `foo` } // = printa `2` magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) // 2 console.log(globalThis.a) function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  140. GAME TIME • CHARADINHA #6 foo.printA() // 1 'use strict'

    const foo = { a: 1, 2, printA: function () { console.log(this.a) }, // `this` é `foo` } // = printa `2` magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) // 2 console.log(globalThis.a) // undefined function magic(callback) { this.a = 2 // `this` é `foo` callback() }
  141. GAME TIME • CHARADINHA #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) } function magic(callback) { callback() } const f = new Foo() f.printA() magic(f.printA)
  142. GAME TIME • CHARADINHA #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) } function magic(callback) { callback() } const f = new Foo() f.printA() magic(f.printA)
  143. GAME TIME • CHARADINHA #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  144. GAME TIME • CHARADINHA #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  145. GAME TIME • CHARADINHA #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  146. GAME TIME • CHARADINHA #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  147. GAME TIME • CHARADINHA #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  148. GAME TIME • CHARADINHA #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) // o `this` é o contexto global } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  149. GAME TIME • CHARADINHA #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) // o `this` é o contexto global } // = printa `undefined` function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  150. GAME TIME • CHARADINHA #6 class Foo { constructor() {

    this.a = 1 } printA() { console.log(this.a) } } function magic(callback) { callback() } const f = new Foo() f.printA() magic(f.printA)
  151. GAME TIME • CHARADINHA #6 class Foo { constructor() {

    this.a = 1 } printA() { console.log(this.a) } } function magic(callback) { callback() } const f = new Foo() f.printA() magic(f.printA)
  152. GAME TIME • CHARADINHA #6 class Foo { constructor() {

    this.a = 1 } printA() { console.log(this.a) } } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  153. GAME TIME • CHARADINHA #6 class Foo { constructor() {

    this.a = 1 } printA() { console.log(this.a) } } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  154. GAME TIME • CHARADINHA #6 class Foo { constructor() {

    this.a = 1 } printA() { console.log(this.a) } } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  155. GAME TIME • CHARADINHA #6 class Foo { constructor() {

    this.a = 1 } printA() { console.log(this.a) } } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  156. GAME TIME • CHARADINHA #6 class Foo { constructor() {

    this.a = 1 } printA() { console.log(this.a) } } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  157. GAME TIME • CHARADINHA #6 class Foo { constructor() {

    this.a = 1 } printA() { console.log(this.a) // `this` é `undefined`; lança exceção } } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  158. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) // então por qual razão não lança } // exceção quando o setTimeout chamada? start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start()
  159. GAME TIME • CHARADINHA #6 Tem mais um truque: quando

    é o environment? Existe diversas diferenças entre o browser e o Node.js, incluindo no setTimeout!
  160. GAME TIME • CHARADINHA #6 No browser, o setTimeout injeta

    de forma implícita o contexto global no callback. Assim, essas duas linhas são equivalentes: setTimeout(this.say, 1) setTimeout(this.say.bind(window), 1)
  161. GAME TIME • CHARADINHA #6 Já no Node, o this

    do callback no setTimeout é uma instância da classe Timeout. E como não tem a property message nesse objeto, o this.message é undefined
  162. GAME TIME • CHARADINHA #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start()