You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
most things in JS are synchronous, which means one at a time and in top-to-bottom order
there're 2 styles of asynchronous code in JS: old-style async callbacks and newer-style promises (async/await is syntactic sugar over promises)
async callbacks = function passed as argument to another function when this higher-order function will execute code in the background; example: second parameter of addEvenListener
Event loop
keeps running continuously and checks the Main stack if it has any frames to execute, if not then it checks Callback queue
because of this your asynchronous code will run only after the Main Stack is done
Execution stack
FILO = first in last out
is where all the javascript code gets pushed and executed one by one as the interpreter reads the program, and gets popped out once the execution is done
Callback/event queue
FIFO = first in first out
if Callback queue has codes to execute then it pops the message from it to the Main Stack for the execution
Event table
asynchronous code gets removed from Main Stack and forwarded to Event table
this table is responsible for moving your asynchronous code to the callback queue after the asynchronous operation is completed
this happens with any asynchronous code except promises
e.g. setTimeout, ajax(), addEventListener()
Job queue
new queue introduced exclusively to handle promises
just like callback queue, jobs are executed only when the main stack is empty
has higher priority than the callback queue; all jobs in the job queue will be executed before any async code in the callback queue
e.g. promises always get executed before setTimeout
is the environment in which a specific block of code is executed
Types
global execution context
functional execution context
Execution context creates
an object:
in global context = global object
in functional context = arguments object
this binding to:
in global context = global object
in functional context = the object calling the method or the window/global object for non-method functions
scope = which variables and functions are available to this code
Execution context phases
when an execution context is executed it goes through two phases: creation and execution
Creation phase
creates the global or functional execution context
set up memory space for variables and functions
hoisting: function statements are fully stored in memory and variables declared with var are stored with the initial placeholder value of undefined
Execution phase
code gets executed line by line
it's in this phase that variables are assigned values and function calls are executed
Execution context stack
global execution context is always the first context added to the stack
a new execution context is created with a function call, placed on top of the stack and the execution of the previous context is paused until this new context is done
after the execution of the topmost block is done, this block will be popped off from the stack and execution goes back to the item that was bellow it
Scope chain
every execution context has a reference to its outer scopes (if any), all the way up to the global scope
in JS, this reference is lexical - scope is defined by the location of the function definition (as opposed to the location of the function call)
Hoisting
JS engine behavior of put variables and functions declarations into memory during the creation phase (which happens before the execution phase)
it's relevant when you try to call a variable/function before its declaration
Declaration vs initialization
usually only declarations are hoisted, not initializations
except for functions statements, which are fully registered in the memory
variables declared with var get initialized to undefined
variables declared with let and const don't get initialized
Environment records
Declarative Environment Record
standard environment that you get when calling a function
its bindings are defined in some inaccessible internal data structure
Object Environment Record
uses an actual JS object to store bindings
Global Environment Record
consists in two environment records:
declarative = stores let, const & class declarations
object = stored in the global (window) object; includes var declarations, function statements and other globals that the browser (or other global environment) provides
Classes
functions that define classes are hoisted (like any function statement)
ES6 classes aren't hoisted
Var vs let & const
Scope
var is function scoped
let and const are block scoped = block scope is anything between curly braces
Arrow function
is a function expression that has a shorter syntax
are best suited for non-method functions, because the this in arrow functions won't point to the object
cannot be used as constructors, doesn't have arguments
this
do not bind its own this
instead, they inherit the one from the parent scope, which is called "lexical scoping"
For of vs for in
For of
for of creates a loop iterating over iterable objects (arrays, strings, NodeLists, iterators)
it returns a list of values of the object's properties
For in
for in iterates over all the enumerable properties of an object (including inherited properties ) in random order
returns a list of the object's key
it's not recommended to use the for in in a array because it can return elements out of order and enumerable properties that includes non-integer names and those that are inherited
Shallow vs deep copy
Shallow copy
a new object is created that has an exact copy of the values in the original object
if any of the fields of the object are references to other objects, just the reference addresses are copied
to shallow copy a literal array/object use Array.from() , array.slice() or the spread operator
Deep copy
an object is copied along with the objects to which it refers
to deep copy it use JSON stringify and parse. To deep copy objects with their prototype, a user defined function is needed
This
this gets set to the object used in the function call
e.g. myObj.f() = this is myObj
if there's no object in the function call (non-method function), defaults to global object or undefined in strict mode
Scope
this is the only dynamically scoped mechanism in JS, because
its value is defined by how it's called (which object precedes it)
and not by where it's defined (lexical scope)
the only exception is this inside arrow function, which is lexically scoped
"use strict";letx={f: function(){functiong(){console.log(this);}g();}}// the g function call is inside the x.f function and doesn't reference any objectx.f();// window or undefined
lexically scoped this in arrow functions
letx={f: function(){constg=()=>console.log(this);g();}}// this in an arrow function inherit its this from its parentx.f();// object x
Changing 'this' value
allows for a function/method belonging to one object to be assigned and called for a different object
constfoo={x: 10};constbar={x: 20,sum: function(y){console.log(this.x+y);}};bar.sum.call(foo,5);// takes a list of argumentsbar.sum.apply(foo,[5]);// takes an array of argumentsbar.sum.bind(foo,5)();// returns a function
Pass by value or reference
variable's value gets copied to another variable (b = a)
variables gets passed as function's arguments
By value
applies to primitives values (numbers, string, boolean...)
value is copied
any change made to this new variable or argument doesn't affect the passed value
By reference
applies to arrays & objects
doesn't copy the value, only saves a reference pointing to the passed value
any changes will affect both variables
Closure
let vs var
functionf(){letx=[];for(vari=0;i<3;i++){x.push((function(){letj=i;return()=>console.log(j)})());}// returns an array of functions// these functions reference an outer variable ('i')// therefore closure happensreturnx;}letx=f();// using var in the for loop, results will be all 3// using let in the for loop, result will be 1 2 3// thats because let creates a different variable every iteration of the loop,// while var is the same (just gets reassigned)x[0]();x[1]();x[2]();
Callback
a function passed into another function as an argument, which is then invoked inside the outer function at a given time
usually after another code (maybe asynchronous) got executed
Examples
functions that take a callback: forEach, promise, setTimeout, addEventListener
Partial application
bind = const add5 = sum.bind(null, 5);
OOP in JS
Primitives & objects
everything in JS is a
primitive (string, number, bigint, boolean, undefined, null and symbol)
or an object (arrays, objects, functions)
Prototypal inheritance
only objects (not primitives) have inheritance
inheritance is not class-based like Java and C++, it's prototypal
Primitives wrapper
when trying to access properties in a primitive
strings, numbers, boolean & symbols
the primitive will be wrapped in an object
after the property access is done, wrapper will be discard and everything goes back to normal
Prototype chain
each object (and subsequent object) has a private property which holds a link to another object called its prototype
the second to last prototype of every object is the Object prototype and the last one is the null
Access property
property will be sought on the object
if not found, sought on its first prototype and so on
Get an object's prototype
Object.getPrototypeOf(obj) or obj.__proto__
Iterators & generators
// when called, generators functions (function*) return a generatorfunction*counter(){letc=0;yield++c;yield++c;}// an iterator is any object which implements the next() method which returns { value, done }// generators can return (yield) multiple values in iterative mode (one-at-a-time)constiterator=counter();// it returns a special type of iterator, called Generatorconsole.log(iterator.next());console.log(iterator.next());console.log(iterator.next());// done
Promises
Using then, catch and finally
// like callbacks, promises allow us to wait on certain code to finish execution prior to running the next bit of codeconstmyPromise=()=>{returnnewPromise((resolve,reject)=>{setTimeout(()=>{constresp=true;resp ? resolve("done") : reject("error");},2000);})};myPromise().then(resp=>console.log(resp)).catch(err=>console.warn(err)).finally(()=>console.log("end"));