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