JavaScript Type system and scopes

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
    }
  }
}
Made with Slides.com