Security Theater
SecTheater is an online teaching community that targets the IT department. We do our best to produce for you high quality and well-edited screen casts about web development.
Objects
typeof undeclared // "undefined"
let v = null
typeof v // "object"
v = () => {}
typeof v // "function"
v = [1, 2, 3]
typeof v // "object"
ToPrimitive
valueOf
toString
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
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
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
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
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 is more like wrapping some value in a container which has more functionalities that can use
let name = "ahmed"
console.log(typeof name) // string
console.log(name.length) // 5?! How!
console.log(name.includes('e')) // true, C'mon
Boxing is more like wrapping some value in a container which has more functionalities that can use
const x = new String('xa')
console.log(x.__proto__)
The == operator checks for values only while the === operator checks for values and type
BIG HELL NO
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
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
}
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 ===
[] == ![] // true
let posts = []
let tweets = []
if (posts == !tweets) {
// passes
}
if (posts != tweets) {
// also passes
}
// But why?! :/
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
let posts = []
if (posts) {
// passes
}
if (posts == true) {
// fails? WTF
}
if (posts == false) {
// passes!! aight that's it with 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
console.log("0" == 0) // true
console.log(0 == []) // true
console.log("0" == []) // false
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
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
Global scope is when you define a variable appended to the globalThis object
var first_name = "Ahmed"
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 is when you define a variable inside a functionÂ
function one() {
var x = 1
console.log(x)
}
one() // 1
console.log(X) // ReferenceError
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"
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
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
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
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
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
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
{
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
{
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.
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()
function counter() {
var initial = 0
var final = 5
var increase = function () {
return initial++
}
return increase
}
let x = counter()
function counter() {
var initial = 0
var final = 5
return function increase() {
return initial++
}
}
let x = counter()
function counter() {
var initial = 0
var final = 5
var increase = () => initial++;
var decrease = () => initial--;
return {
increase,
decrease
}
}
let x = counter()
Kyle Simpson
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
}
}
}
 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
main()
Stack trace
Global Execution Context
Executing code
global
context
Hoisting
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;
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
function add(int $x, int $y): int
{
return $x + $y;
}
Local
Memory
Execution
Return Value
value = 5
5
let x = 5
function firstLayer() {
console.log(x)
let y = 3
return function secondLayer() {
console.log(y)
...
}
}
firstLayer()()
The action of moving variable/function declarations to the top of their execution context
console.log(x) // ReferenceError
The action of moving variable/function declarations to the top of their execution context
console.log(x) // undefined
var x = 5
The action of moving variable/function declarations to the top of their execution context
var x
console.log(x) // undefined
var x = 5
function sayWelcome() {
console.log(`Hello ${name}`)
var name = "ahmed"
}
sayWelcome() // Hello undefined
function sayWelcome() {
var name
console.log(`Hello ${name}`)
var name = "ahmed"
}
sayWelcome() // Hello undefined
function sayWelcome() {
console.log(`Hello ${name}`)
let name = "ahmed"
}
sayWelcome() // TDZ Error (Access variable before initialization)
var teacher = "ahmed"
{
console.log(teacher)
let teacher = "mahmoud"
}
console.log(point.x)
const x = {
x: 1,
y: 2,
z: 3
}
Var vs
Let vs
​ const
Let, const don't hoist
Undeclared vs
Undefined vs
Uninitialized vs
NULL
sayWelcome() // Hello undefined
function sayWelcome() {
var name
console.log(`Hello ${name}`)
var name = "ahmed"
}
module.exports = {
pipe,
compose,
curry
}
function pipe(...) {...}
function compose(...) {...}
function curry(...) {...}
function counter(start = 0) {
return {
increase,
decrease,
}
function increase(step = 1) {
return (start += step)
}
function decrease(step = 1) {
return (start -= step)
}
}
Raise up your techinal skills
By Security Theater
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.
SecTheater is an online teaching community that targets the IT department. We do our best to produce for you high quality and well-edited screen casts about web development.