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

Copy of Deep understanding of JavaScript foundation

By Security Theater

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

  • 0