Deep
JavaScript
Foundation

Types

  • String
  • Number
  • BigInt
  • Boolean
  • Undefined
  • Symbol
  • Null
  • object
  • array
  • function

Objects

Types

typeof undeclared // "undefined"

let v = null

typeof v // "object"

v = () => {}

typeof v // "function"

v = [1, 2, 3]

typeof v // "object"

Type Coercion

ToPrimitive

valueOf

toString

Type Coercion

ToPrimitive

valueOf

let user = {
  username: 'ahmedosama-st',
  posts: [
    {
      id: 1,
      title: 'Exploring the V8 engine',
      url: 'example.com',
    },
  ],
}

console.log(Number(user)) // NaN
console.log(String(user)) // [object Object]

toString

Type Coercion

ToPrimitive

valueOf

let user = {
  username: 'ahmedosama-st',
  posts: [
    {
      id: 1,
      title: 'Exploring the V8 engine',
      url: 'example.com',
    },
  ],

  valueOf() {
    return this.posts.length
  },
}

console.log(Number(user)) // 1

toString

Type Coercion

ToPrimitive

valueOf

let user = {
  username: 'ahmedosama-st',
  posts: [
    {
      id: 1,
      title: 'Exploring the V8 engine',
      url: 'example.com',
    },
  ],

  toString() {
    return 'Hello world'
  },
}

console.log(String(user)) // Hello world

toString

Type Coercion

ToPrimitive

valueOf

let user = {
  username: 'ahmedosama-st',
  posts: [
    {
      id: 1,
      title: 'Exploring the V8 engine',
      url: 'example.com',
    },
  ],

  [Symbol.toPrimitive](hint) {
    if (hint == 'string') {
      return require('util').inspect(this, false, null, true)
    } else if (hint == 'number') {
      return this.posts.length
    }
  },
}

console.log(String(user)) // {username: 'ahmedosama', posts: [...], ...}
console.log(Number(user)) // 1

toString

Corner cases of coercion

Number("") // 0
Number("   \t\t\n") // 0
Number(null) // 0
Number(undefined) // NaN
Number([]) // 0
Number([null]) // 0
Number([undefined]) // 0


String(-0) // 0
String(null) // "null"
String(undefined) // "undefined"
String([null]) // ""
String([undefined]) // ""

Boolean( new Boolean(false) ) // true

More details can be found here

Boxing

Boxing is more like wrapping some value   in a container which has more functionalities that can   use
x
y
x
let name = "ahmed"

console.log(typeof name) // string


console.log(name.length) // 5?! How!
console.log(name.includes('e')) // true, C'mon

Boxing

Boxing is more like wrapping some value   in a container which has more functionalities that can   use
x
y
x
const x = new String('xa')

console.log(x.__proto__)

Equality

The == operator checks for values only while the === operator checks for values and type

BIG HELL NO

Equality

Equality

Equality

let p1 = { x: 1, y: 2 }
let p2 = { x: 2, y: 3 }

let first_name = 'ahmed'
let last_name = 'osama'

console.log(p1 == p2)  // false
console.log(p1 === p2) // false

console.log(first_name == last_name)  // false
console.log(first_name === last_name) // false

last_name = 'ahmed'

console.log(first_name == last_name)  // true
console.log(first_name === last_name) // true

Equality

Equality

let p1 = { x: 1, y: 2 }
let p2 = { y: 3, z: 4 }

if (
  (p1.z === null || p1.z === undefined) &&
  (p2.x === null || p2.x === undefined)
) {
  // some code
}

if (p1.z == undefined && p2.x == undefined) {
  // some code
}

Equality

Equality

const something = {
  valueOf() {
    return 42
  },
}

let x = [42]

if (42 == something) {
  console.log('hello')
}

if (42 == x) {
  console.log("welcome")
}

ToPrimitive(something)

Number(x)

turns it into "42"

then turns it into 42

and performs ===

WTF JS

[] == ![] // true

WTF JS

let posts   = []
let tweets  = []

if (posts == !tweets) {
  // passes
}

if (posts != tweets) {
  // also passes
}

// But why?! :/

WTF JS

let posts   = []
let tweets  = []

if (posts == !tweets) {
  // passes
}

if ([] == false) {} // two different types, coerce the non-primitive
if ("" == false) {} // still different types, coerce to numbers
if (0 == 0) {} // same numbers, use the ===
if (0 === 0) {} // surely its true

if (posts != tweets) {
  // also passes
}

if (!(posts == tweets)) {} // same types, use ===
if (!(false)) {} // negation of false becomes true

WTF JS

let posts = []

if (posts) {
  // passes
}

if (posts == true) {
  // fails? WTF
}

if (posts == false) {
  // passes!! aight that's it with js
}

WTF JS

let posts = []

if (posts)          {} // Non-primitive, coerce to boolean
if (Boolean(posts)) {} // checks if its in the falsy map
if (true)           {} // surely passes as its truthy value

if (posts == true) {} // not same type, coerce the non-primitive
if ("" == true)    {} // still not same type, but primitives, coerce to numbers
if (0 == 1)        {} // same types, use the ===
if (0 === 1)       {} // surely fails


if (posts == false) {} // not same type, coerce the non-primitive
if ("" == false)    {} // still not same type, but primitives, coerce to numbers
if (0 == 0)         {} // same types, use the ===
if (0 === 0)        {} // surely passes

WTF JS

console.log("0" == 0) // true




console.log(0 == []) // true










console.log("0" == []) // false

WTF JS

console.log("0" == 0) // true

// 1- Not the same type, coerce to numbers
// 2- becomes 0 == 0, same type use === returns true

console.log(0 == []) // true

// 1- Not the same type, coerce the non-primitive which becomes ""
// 2- Not the same type, coerce to numbers
// 3- becomes 0 == 0, same type, use === which returns true


console.log("0" == []) // false

// 1- Not the same type, coerce the non-primitive which becomes ""
// 2- Same type, use === which returns false as they're not identical strings
  • Global scope
  • Script Scope
  • Local Scope
  • Block scopes
  • Lexical scope
  • Closure
A scope is the variables that a function can access at certian line ( at function call).
Global scope is when you define a variable appended to the window object

Scopes

Global Scope

Global scope is when you define a variable appended to the globalThis object
var first_name = "Ahmed"

Script Scope

Script scope is when you define a variable that's accessible everywhere but not appended to the window object
var first_name = "Ahmed"

let last_name = "Osama"

Function scope

Function scope is when you define a variable inside a function 
function one() {
  var x = 1

  console.log(x)
}

one() // 1

console.log(X) // ReferenceError

Function scope

var first_name = "ahmed"

// ... some code

console.log(first_name) // probably "ahmed"
var first_name = "ahmed"

var first_name = "mohamed" // some impact by another developer

console.log(first_name) // now it's "mohamed"

Function scope

var first_name = 'ahmed'

function another() {
  var first_name = 'mohamed' // moving it into another scope
  console.log(first_name)
}

another()

console.log(first_name) // now it's "ahmed" again

Function scope

var first_name = 'ahmed'

function another() {
  var first_name = 'mohamed' // moving it into another scope
  console.log(first_name)
}

function another() {
  console.log("I'm changed")
}

another() // "I'm changed"

console.log(first_name) // now it's "ahmed" again

Function scope

var first_name = 'ahmed'

(function another() {
  var first_name = 'mohamed' // moving it into another scope
  console.log(first_name)
})()

console.log(first_name) // now it's "ahmed" again

IIFE

Block Scope

Block scope is when you define a variable within any curly braces or a statement on condition that you use a let instead of var
for (var i = 0; i < 5; i++) {
  console.log(`i value now is: ${i}`);
}

console.log(`i value now is: ${i}`)

...
for (var i = 0; i < 5; i++) {
  console.log(`i value now is: ${i}`);
}

console.log(`i value now is: ${i}`)

for (let j = 0; j < 5; i++) {
  console.log(`j value now is: ${j}`);
}

console.log(j) // reference error
Block scope is when you define a variable within any curly braces or a statement on condition that you use a let instead of var

Block Scope

if (true) {
  var x = 5;
}

console.log(x); // 5

...
Block scope is when you define a variable within any curly braces or a statement on condition that you use a let instead of var

Block Scope

if (true) {
  var x = 5;
}

console.log(x); // 5

if (false) {
  // some dummy code
} else {
  const y = 5;
}

console.log(y); // reference error
Block scope is when you define a variable within any curly braces or a statement on condition that you use a let instead of var

Block Scope

{
  var x = 5
}

console.log(x) // 5

...
Block scope is when you define a variable within any curly braces or a statement on condition that you use a let instead of var

Block Scope

Block Scope

{
  var x = 5
}

console.log(x) // 5

{
  let y = 5;
}

console.log(y) // reference error
Block scope is when you define a variable within any curly braces or a statement on condition that you use a let instead of var
let x = 5

function firstLayer() {
  console.log(x)

  ...
}

firstLayer()
Lexical scope is when a group of nested functions have access to their defined variables and the variables that are defined in their parent scope.

Lexical Scope

Lexical Scope

let x = 5

function firstLayer() {
  console.log(x)

  let y = 3

  return function secondLayer() {
    console.log(y)

    ...
  }
}

firstLayer()()
Lexical scope is when a group of nested functions have access to their defined variables and the variables that are defined in their parent scope.

Lexical Scope == [[Scopes]]

function counter() {
  var initial = 0
  var final = 5

  ...
}

let x = counter()

Closures

function counter() {
  var initial = 0
  var final = 5

  var increase = function () {
    return initial++
  }

  return increase
}

let x = counter()

Closures

function counter() {
  var initial = 0
  var final = 5

  return function increase() {
	return initial++
  }
}

let x = counter()

Closures

function counter() {
  var initial = 0
  var final = 5

  var increase = () => initial++;

  var decrease = () => initial--;

  return {
    increase,
    decrease
  }
}

let x = counter()

Closures

Kyle Simpson

Closures

Closure is when a function "remembers" its lexical scope even when the function is executed outside that lexical scope.
function counter() {
  var idx = 1

  return function one() {
    let idx1 = 2

    return function two() {
      let idx2 = 3

      return idx + idx1 + idx2
    }
  }
}

Callstack

 A call stack is an implementation of the stack data structure to keep track of function calls in your program

Me 👉👈

function one() {
  console.log('I am first')
}

function two() {
  console.log('I am second')
  one()
}

function third() {
  two()
  return 'I am third'
}

function run() {
  return third()
}

console.log(run())

main()

run()

third()

two()

one()

Stack  trace

Execution context

main()

Stack  trace

Global Execution Context

Executing code

global

context

Hoisting

Execution context

function add(x, y) {
  return x + y
}

Local
Memory

Execution

Return Value

x

y

x

y

function add(x, y) {
  return x + y
}

Local
Memory

Execution

Return Value

let value = add(2, 3)

2

3

return $x + $y;

Execution context

x

y

function add(x, y) {
  return x + y
}

Local
Memory

Execution

Return Value

let value = add(2, 3)

2

3

=

=

return x + y

}

5

Execution context

function add(int $x, int $y): int
{
    return $x + $y;
}

Local
Memory

Execution

Return Value

value = 5

5

Execution context

Lexical scope revisited

let x = 5

function firstLayer() {
  console.log(x)

  let y = 3

  return function secondLayer() {
    console.log(y)

    ...
  }
}

firstLayer()()

Hoisting

The action of moving variable/function declarations to the top of their execution context

console.log(x) // ReferenceError

Hoisting

The action of moving variable/function declarations to the top of their execution context

console.log(x) // undefined

var x = 5

Hoisting

The action of moving variable/function declarations to the top of their execution context

var x

console.log(x) // undefined

var x = 5

Hoisting

function sayWelcome() {
  console.log(`Hello ${name}`)

  var name = "ahmed"
}

sayWelcome() // Hello undefined

Hoisting

function sayWelcome() {
  var name

  console.log(`Hello ${name}`)

  var name = "ahmed"
}

sayWelcome() // Hello undefined

Hoisting

function sayWelcome() {
  console.log(`Hello ${name}`)

  let name = "ahmed"
}

sayWelcome() // TDZ Error (Access variable before initialization)

Hoisting

var teacher = "ahmed"

{
  console.log(teacher)

  let teacher = "mahmoud"
}

Hoisting

console.log(point.x)

const x = {
  x: 1,
  y: 2,
  z: 3
}

Hoisting

Var vs

Let vs

​ const

Let, const don't hoist

Hoisting

Undeclared vs

Undefined vs

Uninitialized vs

NULL

Hoisting

sayWelcome() // Hello undefined

function sayWelcome() {
  var name

  console.log(`Hello ${name}`)

  var name = "ahmed"
}

Hoisting

module.exports = {
  pipe,
  compose,
  curry
}

function pipe(...) {...}
function compose(...) {...}
function curry(...) {...}

Hoisting

function counter(start = 0) {
  return {
    increase,
    decrease,
  }

  function increase(step = 1) {
    return (start += step)
  }

  function decrease(step = 1) {
    return (start -= step)
  }
}

Wrapping Up

Wrapping Up

  • Types system in JS
  • Type coercion/conversion and corner cases
  • "Everything in JS is an object" is false, it's all because of boxing
  • Abstract Equality vs Strict Equality
    • === checks value and type, == checks only type (false)
  • Scopes
    • Block scopes
    • Function scopes and IIFE
    • Lexical Scope
  • Execution Context
    • Hoisting

Wrapping Up

SecTheater

  • Types system in JS
  • Type coercion/conversion and corner cases
  • "Everything in JS is an object" is false, it's all because of boxing
  • Abstract Equality vs Strict Equality
    • === checks value and type, == checks only type (false)
  • Scopes
    • Block scopes
    • Function scopes and IIFE
    • Lexical Scope
  • Execution Context
    • Hoisting

SecTheater

Raise up your techinal skills

SecTheater

Deep understanding of JavaScript foundation

By Security Theater

Deep understanding of JavaScript foundation

Ever wondered why the WATs of JS occur? Join me in this journey of understanding JavaScript foundation where we learn things like Type system and Coercion and many more interesting topics.

  • 60