- An Interpreter intranslates on the fly - no conversion into other code, so no optimization
- Compilers translates ahead of time
Both of these do exactly what compilers do: Take one language and convert into a different one!
The memory heap is where all the memory allocation happens.
The call stack is where the engine keep track of where your code is in the execution.
A stack overflow happens when to many items are push onto the stack.
and on completion will return, the Event Loop will then first check the Job Queue(resolved promises), if there is nothing in the Job Queue it will check the callback Queue to push the next task onto the Call Stack.
a new execution context is added and we start running our code until everything gets popped of the stack and all our code is run.
The lexical environment is where the code is located. Everytime you create a function you are also creating a new lexical environment.
The execution context tells you which lexical environment is currently running.
When a function is called it creats a execution context with "this" declared pointing to itself. It also creates the arguments key word and the variable environment.
If a variable is not found in its local environment it will look for the variable in it's parent environment. If it can't find it there it will look in the parents parent environment...and it will keep doing this untill it finds a variable with that name or if it reaches the global scope without finding the variable it will return undefined. This is called the scope chain.
This is an example of where the variable is not declared in the function (func), so it will look for it in it's parent environment.
If functions is on the global scope S If functions is local to each other
It enables us to attached private data to a function and it creates a fresh environment so that you don't add a bunch of variables and functions on the global execution context.
This is an example of how IIFE's create private data. In ES6 we don't need to do this because we have block scoping and is not limited to function scoping.
Refers to the current object. Who called me? So it's whatever is on the left. ( obj.sing() )
call() can execute a method with it's this object pointing to another object. Basically you copy a method from another object.
apply(), works exactly the same as call(), the only difference is takes an array of parameters.
bind() returns a new function with a certain context and parameters and it's usually used when we want to call a function later on with a certain type of this context.
We can use typeof to check what type something is,
A higher order function is simply a functions that takes another function as a argument or a function that returns another function.
Closures can help us to write memory efficient code.
Below we have a closure that keeps the referecing the the creation of a big array so that it is not recreated very time.
By wrapping our Database in a closure we can encapsulate our private functions and data. The way to read this is that
- Database is a function that defines a closure.
- The variables within that closure have access to each other (i.e. _create has access to _data).
- When the Database is called it returns an object that explicitly exposes 4 functions and nothing else.
These days we don't really use the prototype syntax to write Object Orientated code, we use the class construct.
All objects have a _proto__ property which is simply a pointer to up the chain prototype.
An example of doing OOP using the prototype syntax. This is also what happens under the hood when using classes.
- Organizing the code into units
- Clear + Understandable
- Easy to Extend
- Easy to Maintain
- Memory Efficient
- The class keyword in JS is syntactic sugar. Under the hood, it still uses prototypal inheritance
- Instances of a class must be instantiated with the new keyword
- The constructor method is used to instantiate the state (data) of a new object
- The state is typically unique to each instance
- Functions are typically not included in the constructor because it would create a memory reference for the function in each new instance of the class, thus using more memory than needed
- By including functions as methods of the class, instances of the class can reference the function via the prototype chain
- Prototypal Inheritance has better memory efficiency than classical inheritance due to it sharing the memory references of its prototype properties with those objects that inherit from it. In classical inheritance, instances of the class create new memory references for each inherited property.
Example of OOP class syntax
- Encapsulation - Rapping code into boxes that are related to each other.
- Abstraction - Hidding complexity from the user, only exposing the necessary methods in a class.
- Inheritance - Avoid rewriting the same code again. (using extends and super)
- Polymorphism - The abitity to call the same method of different objects and each object responds in a different way.
The goal of Functional Programming is to minimize side effects and compartmentalize functions so that when there is a bug, you know exactly where to go.
A pure function must always return the same output given the same input and the function cannot modify anything outside itself.
An image describing the aspects of good, pure functions
Imperative code is code that tells the machine what to do and how to do it.
Declarative code is code that tells the machines what to do and what should happen, it doesn’t tell the machine how to do it.
Functional programming helps us to be more Declarative.
Not changing the data (state). Make a copy of the state and return the state everytime.
- Currying transforms a function with multiple arguments into a sequence/series of functions each taking a single argument.
- Currying can remind us of methods shared through prototypes of objects which saves memory
Memoization is a specific kind of caching algorithm.
Function composition is an act or mechanism to combine simple functions to build more complicated ones.
A pipeline consists of a chain of processing elements (processes, threads, coroutines, functions, etc.), arranged so that the output of each element is the input of the next; the name is by analogy to a physical pipeline.
Shopping Cart example using compose and pipe.
Another example with pipe.
A promise is an object that may produce a single value some time in the future.
Either a resolved value, or a reason thta it's not resoved (rejected).
Three posible states, fullfilled, rejected or pending.
Async Await is build on top of promises. It improved that async syntax.
- An IIFE would create a function scope for the functions and variables to live inside of where they would be private. This would prevent pollution of the global namespace.
- By returning functions/variables from the IIFE in an object, we create an interface for interacting with the code inside of the IIFE function scope.
- This method of containerizing our code is called the Revealing Module Pattern.
- Provides native module functionality in the browser
- Errors are used with the keyword throw
- The name property refers to the general class of Error
- The message property generally provides a more succinct message than one would get by converting the error object to a string.
- The stack property traces the Error’s position in the call-stack back to the global context which is typically
- Error, general error
- SyntaxError, e.g. a misplaced comma
- ReferenceError, e.g. undefined variable
When an Error is thrown, it searches up the call-stack for a catch.
If no catch is found, the runtime handles it.
In the browser, it is onerror().
In Node.js, it is process.on(‘uncaughtException’)
- Error is a class and can be extended with the extends keyword to create custom Errors.
- This can be useful for creating secure Errors by not displaying too much information.