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

JS+HTML Riddles

JS+HTML Riddles

What does this code do? Will it print anything? Or will it throw an error? Does it depend on whether it’s running in Node or in the browser?

In this talk, I’ll present a series of JavaScript and HTML riddles full of mystery, and walk through each one step by step.

(these puzzles are far more elaborate and unpredictable than the usual overused questions like [] + {} or similar examples. I dare you to solve the final riddle!)

Avatar for Bruno Macabeus

Bruno Macabeus

January 15, 2026
Tweet

More Decks by Bruno Macabeus

Other Decks in Programming

Transcript

  1. ✨ nothing here is meant to be production code ✨

    (although I may have seen something similar in prod before 🙈)
  2. GAME TIME • QUESTION #1 > 'magic' is printed immediately,

    only once setTimeout(() => { console.log('magic') }, Infinity)
  3. GAME TIME • QUESTION #1 The Infinity is converted to

    1 (or 0) when used in the setTimeout argument, which implies running on the next tick.
  4. GAME TIME • QUESTION #1 But it wasn’t standardized in

    the past. In old IE and Opera versions, the behavior is never calling the callback.
  5. GAME TIME • QUESTION #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 • QUESTION #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 • QUESTION #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 • QUESTION #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 • QUESTION #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 • QUESTION #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))
 }
  11. GAME TIME • QUESTION #2 It’s confusing because the for

    initializer is different when using var or let
  12. GAME TIME • QUESTION #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks Variables
  13. GAME TIME • QUESTION #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 0 Variables
  14. GAME TIME • QUESTION #2 for (var x = 0;

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

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } setTimetout(() => console.log(x)) Tasks var x = 0 Variables
  16. GAME TIME • QUESTION #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 0 setTimetout(() => console.log(x)) Variables
  17. GAME TIME • QUESTION #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 1 setTimetout(() => console.log(x)) Variables
  18. GAME TIME • QUESTION #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 1 setTimetout(() => console.log(x)) Variables
  19. GAME TIME • QUESTION #2 for (var x = 0;

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

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

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 2 setTimetout(() => console.log(x)) setTimetout(() => console.log(x)) Variables
  22. GAME TIME • QUESTION #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 2 setTimetout(() => console.log(x)) setTimetout(() => console.log(x)) Variables
  23. GAME TIME • QUESTION #2 for (var x = 0;

    x < 2; x++) {
 setTimeout(() => console.log(x))
 } Tasks var x = 2 setTimetout(() => console.log(x)) setTimetout(() => console.log(x)) Variables
  24. GAME TIME • QUESTION #2 When using let, a new

    lexical scope is created for each iteration:
  25. GAME TIME • QUESTION #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks Variables
  26. GAME TIME • QUESTION #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 Variables
  27. GAME TIME • QUESTION #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks setTimetout(() => console.log(y_iteration_1)) let y_iteration_1 = 0 Variables
  28. GAME TIME • QUESTION #2 for (let y = 0;

    y < 2; y++) {
 setTimeout(() => console.log(y))
 } Tasks let y_iteration_1 = 0 setTimetout(() => console.log(y_iteration_1)) Variables
  29. GAME TIME • QUESTION #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)) Variables
  30. GAME TIME • QUESTION #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)) Variables
  31. GAME TIME • QUESTION #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)) Variables
  32. GAME TIME • QUESTION #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)) Variables
  33. GAME TIME • QUESTION #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)) Variables
  34. GAME TIME • QUESTION #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)) Variables
  35. GAME TIME • QUESTION #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)) Variables
  36. GAME TIME • QUESTION #2 for ( let z =

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

    { foo: 0 }; z.foo < 2; z.foo++ ) {
 setTimeout(() => console.log(z.foo))
 } // 2 2
  38. GAME TIME • QUESTION #2 Let’s check how for is

    de fi ned on the spec! https://262.ecma-international.org/14.0
  39. GAME TIME • QUESTION #2 The spec is explicit about

    the differences between var and let
  40. GAME TIME • QUESTION #3 It’s confusing because JS has

    4 different equality and uniformity algorithms
  41. GAME TIME • QUESTION #3 // 1. Abstract equality comparison

    0 == -0 // true 0n == -0n // true // ^ this n means bigint
  42. GAME TIME • QUESTION #3 Let’s check the SameValue on

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

    .innerHTML += '<div id="magic">bar</div>' console.log(magic.innerHTML) </script>
  44. GAME TIME • QUESTION #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>
  45. GAME TIME • QUESTION #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>
  46. GAME TIME • QUESTION #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>
  47. GAME TIME • QUESTION #4 <div id="magic">foo</div> <script> document .documentElement

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

    .innerHTML += '<div id="magic">bar</div>' console.log(magic.innerHTML) </script> > undefined
  49. GAME TIME • QUESTION #4 It’s confusing because this code

    uses a code smell from a legacy and not recommended HTML feature
  50. GAME TIME • QUESTION #4 Let’s check it on the

    HTML spec! https://html.spec.whatwg.org/ vs.
  51. GAME TIME • QUESTION #4 The spec de fi nes

    when an element is exposed, in other words, when it’s available from window
  52. GAME TIME • QUESTION #4 <!-- a div with id

    --> <div id="foo"></div> <script> window.foo // Element of `<div id="foo"></div>` </script>
  53. GAME TIME • QUESTION #4 <!-- a div with id

    --> <div id="foo"></div> <script> foo // Element of `<div id="foo"></div>` </script>
  54. GAME TIME • QUESTION #4 <!-- an img with name

    --> <img name="foo" /> <script> foo // Element of `<img name="foo" />` </script>
  55. GAME TIME • QUESTION #4 <!-- the same happens when

    the DOM is updated --> <script> document .documentElement .innerHTML = '<div id="foo">blah</div>' foo // Element of `<div id="foo">blah</div>` </script>
  56. GAME TIME • QUESTION #4 <!-- and when there are

    two img with same name? --> <img name="duplicated" /> <img name="duplicated" /> <script> duplicated /* HTMLCollection(2) [ img, img, duplicated: img ] */ </script>
  57. GAME TIME • QUESTION #4 <!-- and same id? -->

    <div id="duplicated" /> <div id="duplicated" /> <script> duplicated /* HTMLCollection(2) [ div, div, duplicated: div ] */ </script>
  58. GAME TIME • QUESTION #4 Since HTMLCollection doesn’t have the

    innerHTML property, magic.innerHTML returns undefined.
  59. GAME TIME • QUESTION #4 Since HTMLCollection doesn’t have the

    innerHTML property, magic.innerHTML returns undefined. But, there is a bug on Firefox, and it returns the Element for the fi rst one!
  60. GAME TIME • QUESTION #4 <div id="magic">foo</div> <div id="magic">bar</div> <script>

    magic /* It should returns HTMLCollection But, Firefox returns the Element for the first one */ </script>
  61. GAME TIME • QUESTION #5 ( class Magic { static

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

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

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

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

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

    console = console.log('foo') }, console.log(Magic.name) ) > it prints 'foo' and then throws in runtime
  67. GAME TIME • QUESTION #5 ( class Magic { static

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

    console = console.log('foo') }, console.log(Magic.name) ) ( // it forces the class to become an expression )
  69. GAME TIME • QUESTION #5 // ClassDeclaration: in a statement

    context class Magic { } // The class keyword can be: // ClassExpression: in an expression context const M = class Magic { } ( class Magic { } )
  70. GAME TIME • QUESTION #5 // ClassDeclaration: in a statement

    context class Magic { } // The class keyword can be: // ClassExpression: in an expression context const M = class Magic { } ( class Magic { } )
  71. GAME TIME • QUESTION #5 // ClassDeclaration: in a statement

    context class Magic { } // The class keyword can be: // ClassExpression: in an expression context const M = class Magic { } ( class Magic { } )
  72. GAME TIME • QUESTION #5 const M = class Magic

    { myself = () => Magic // it works } console.log(Magic) // it throws ReferenceError When using ClassExpression, the class name is only visible within the scope of the class itself
  73. GAME TIME • QUESTION #5 ( class Magic { static

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

    console = console.log('foo') } console.log(Magic.name) ) , // comma operator
  75. GAME TIME • QUESTION #5 The comma operator receives a

    list of expressions, it evaluates each item, and then returns the last one
  76. GAME TIME • QUESTION #5 ['a1', 'b2', ‘c3'].reduce( (state, pair)

    => { state[pair[0]] = pair[1] return state }, {} ) // {a: '1', b: '2', c: ‘3'}
  77. GAME TIME • QUESTION #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'}
  78. GAME TIME • QUESTION #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'}
  79. GAME TIME • QUESTION #5 Normally, we don’t use the

    comma operator directly. But our compilers use it frequently for two main reasons.
  80. GAME TIME • QUESTION #5 // 1. minify the code

    if(x){foo();return bar()}else{return 1} // it’s equivalent to return x?(foo(),bar()):1
  81. GAME TIME • QUESTION #5 // 2. spec complaince //

    foo.ts export function foo() { return this } // index.ts import { foo } from './foo.ts'
 foo() // returns undefined // tsc compiles it into (0, foo())
  82. GAME TIME • QUESTION #5 ( class Magic { static

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

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

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

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

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start()
  87. GAME TIME • QUESTION #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'
  88. GAME TIME • QUESTION #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() { } }
  89. GAME TIME • QUESTION #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() { } }
  90. GAME TIME • QUESTION #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); } }
  91. GAME TIME • QUESTION #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()
  92. GAME TIME • QUESTION #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) } start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start()
  93. GAME TIME • QUESTION #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' or undefined (depends on the env 🙃)
  94. GAME TIME • QUESTION #6 is too implicit and dynamic,

    and the setTimeout depends on the environment It’s confusing because this
  95. GAME TIME • QUESTION #6 const foo = { a:

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

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

    2 callback() } foo.printA() // 1 const foo = { a: 1, printA: function () { console.log(this.a) }, }
  98. GAME TIME • QUESTION #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) }, }
  99. GAME TIME • QUESTION #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) }, }
  100. GAME TIME • QUESTION #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) }, }
  101. GAME TIME • QUESTION #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 // `this` here is the global context callback() }
  102. GAME TIME • QUESTION #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 // `this` here is the global context callback() }
  103. GAME TIME • QUESTION #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 // `this` here is the global context callback() }
  104. GAME TIME • QUESTION #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) foo.printA() //

    1 function magic(callback) { this.a = 2 // `this` here is the global context callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, // `this` here } // is also the // global context
  105. GAME TIME • QUESTION #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) foo.printA() //

    1 function magic(callback) { this.a = 2 // `this` here is the global context callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, // `this` here } // is also the // global context // = prints `2`
  106. GAME TIME • QUESTION #6 magic(foo.printA) console.log(foo.a) console.log(globalThis.a) foo.printA() //

    1 function magic(callback) { this.a = 2 // `this` here is the global context callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, // `this` here } // is also the // global context // = prints `2`
  107. GAME TIME • QUESTION #6 foo.printA() // 1 function magic(callback)

    { this.a = 2 // `this` here is the global context callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, // `this` here } // is also the // global context // = prints `2` magic(foo.printA) console.log(foo.a) // 1 console.log(globalThis.a)
  108. GAME TIME • QUESTION #6 foo.printA() // 1 function magic(callback)

    { this.a = 2 // `this` here is the global context callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, // `this` here } // is also the // global context // = prints `2` magic(foo.printA) console.log(foo.a) // 1 console.log(globalThis.a)
  109. GAME TIME • QUESTION #6 foo.printA() // 1 function magic(callback)

    { this.a = 2 // `this` here is the global context callback() } const foo = { a: 1, printA: function () { console.log(this.a) }, // `this` here } // is also the // global context // = prints `2` magic(foo.printA) console.log(foo.a) // 1 console.log(globalThis.a) // 2
  110. GAME TIME • QUESTION #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'
  111. GAME TIME • QUESTION #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'
  112. GAME TIME • QUESTION #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'
  113. GAME TIME • QUESTION #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'
  114. GAME TIME • QUESTION #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 // with strict mode, `this` here is now undefined callback() }
  115. GAME TIME • QUESTION #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 -> error! callback() }
  116. GAME TIME • QUESTION #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() }
  117. GAME TIME • QUESTION #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)
  118. GAME TIME • QUESTION #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)
  119. GAME TIME • QUESTION #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)
  120. GAME TIME • QUESTION #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` is `foo` callback() }
  121. GAME TIME • QUESTION #6 foo.printA() // 1 'use strict'

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

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

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

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

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

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

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

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

    function magic(callback) { this.a = 2 // `this` is `foo` callback() } const foo = { a: 1, 2, printA: function () { console.log(this.a) }, // `this` is `foo` } // = prints `2` magic.bind(foo)(foo.printA.bind(foo)) console.log(foo.a) // 2 console.log(globalThis.a) // undefined
  130. GAME TIME • QUESTION #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)
  131. GAME TIME • QUESTION #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)
  132. GAME TIME • QUESTION #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)
  133. GAME TIME • QUESTION #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)
  134. GAME TIME • QUESTION #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)
  135. GAME TIME • QUESTION #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)
  136. GAME TIME • QUESTION #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)
  137. GAME TIME • QUESTION #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) // this is the global context } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  138. GAME TIME • QUESTION #6 const Foo = function() {

    this.a = 1 } Foo.prototype.printA = function() { console.log(this.a) // this is the global context } // = prints `undefined` function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  139. GAME TIME • QUESTION #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)
  140. GAME TIME • QUESTION #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)
  141. GAME TIME • QUESTION #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)
  142. GAME TIME • QUESTION #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)
  143. GAME TIME • QUESTION #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)
  144. GAME TIME • QUESTION #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)
  145. GAME TIME • QUESTION #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)
  146. GAME TIME • QUESTION #6 class Foo { constructor() {

    this.a = 1 } printA() { console.log(this.a) // `this` is `undefined`; it throw error } } function magic(callback) { callback() } const f = new Foo() f.printA() // 1 magic(f.printA)
  147. GAME TIME • QUESTION #6 this.message = 'foo' class Magic

    { message = 'bar' say() { console.log(this.message) // but why does it not crash } // when setTimeout calls it? start() { setTimeout(this.say, 1000); } } const m = new Magic() m.start()
  148. GAME TIME • QUESTION #6 There is one more prank:

    what’s the environment? There are differences between the browser and Node.js including on setTimeout!
  149. GAME TIME • QUESTION #6 On browser, it injects the

    global context on the callback. These two lines are equivalent: setTimeout(this.say, 1) setTimeout(this.say.bind(window), 1)
  150. GAME TIME • QUESTION #6 On Node, the this from

    the setTimeout callback is the instance from the Timeout class. And since there is no message property on this object, this.message is undefined
  151. GAME TIME • QUESTION #6 this.message = 'foo' class Magic

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