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