-
Notifications
You must be signed in to change notification settings - Fork 1
Javascript
Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope before code execution regardless of whether their scope is global or local. Every time you write a program in javascript, it runs in an environment and that environment is called execution context. There are two types of execution contexts:
- Global Execution Context
- Execution Context created every time after a function is created. Every time a function is called the new execution context is pushed to the top of the global execution context, which makes an execution stack.
An undeclared variable is assigned the value undefined at execution and is also type undefined. A ReferenceError is thrown when trying to access a previously undeclared variable.
Function declarations are hoisted and Function expressions are not .. gives typeError
2 types of JS functions
- Function declaration and 2. Function Expression
- The Function Declaration is created when JavaScript is preparing to start the script and is visible everywhere in it.
function foo(){ } - Function Expressions are created when the execution reaches them.
let foo = function(){ }Difference - Syntax
- The main difference between a function expression and a function declaration is the function name, which can be omitted in function expressions to create anonymous functions.
- FE can be used as an IIFE. *can't use function expression before creating them (because they are not hoisted).
A closure is an inner function which gives you access to an outer function’s scope from inside even before the function is returned. In JavaScript, closures are created every time a function is created, at function creation time. A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created.
what happens internally is:
outer function execution goes into the execution stack first, then the variables goes into symbols table. Variable remains there till the execution of the function is completed. Then comes the inner function, it goes in execution stack and can access variable from symbols table. Once the execution of outer function is completed you can't access the variable outside.
Also, you can't access the variables declared inside the inner function.
function runExecution() { var a = 10; function add(b){ var b = 20; return a + b; } add(); }
Further explanation to that "reference" concept: Point 1: "An object is marked as eligible to be garbage collected when it can no longer be accessed." As you can't initiate garbage collection process manually in javascript, JS engine determines the eligibility of an object for GC using the above mentioned point. FYI, this is applicable for all types of objects.
But if there's a reference somewhere, which means if it can still be accessed (In case of closure, inner function still has reference preserved for variables defined in outer function), which means it still stays in the Heap memory & garbage collector doesn't consider these variables.
The spread operator takes an array (or any iterable) and spreads its values. The spread operator takes the array of parameters and spreads them across the arguments in the function call. But what if we need our function to be able to work with an unknown number of parameters? That’s where the rest parameter comes in. The rest parameter gives us an easier and cleaner way of working with an indefinite number of parameters
Arguments is like rest operator, it was used in old javascript but the difference between these both is, arguments creates an array like structure but not array, so we can't use methods of array, for example array.map(..)
- Spread syntax internally uses iterator, as for...of
- Rest parameters are used to create functions that accept any number of arguments.
- The spread syntax is used to pass an array to functions that normally require a list of many arguments.
Example of spread operator->
- Make copies of array or object.
- Merge arrays
- Scope: var variables are function scoped and let variables are block scoped.
- Hoisting: var variables are hoisted, let will throw referenceError.
- Global object: var variables are created as a global object i,e, are attached to window object, but let variables are not. (which means var are wasting memory attaching every variable to the global object.)
- Redeclaration:
var foo = 20; var foo;its ok but will throw an error in strict mode butlet bar = 20; let 20;is not ok.
- syntax
- no arguments binding in arrow functions
- use of this keyword -> arrow functions do not have their own this.
- using new keyword: regular functions are callable and constructible. but arrow functions are only callable and not constructible.
- no duplicate name parameters
A higher-order function is a function that can take another function as an argument, or that returns a function as a result. When you pass a function by name without parentheses, you are passing the function object itself. When you pass it with parentheses, you are passing the result of executing that function.
null is an object whereas undefined is of type undefined. null !== undefined but null == undefined undefined means a variable is declared but not assigned a value whereas null is an assigned value.
If we make a copy b = a , and change some nested value in b, it actually changes a’s nested value as well, since a and b actually point to the same thing. This is known as shallow copy.
Shallow copy in objects can be done by spread operators, Object.assign({}, obj) and obj.slice();
Shallow copy in arrays: spread, Array.from(arr)
When an object variable is copied – the reference is copied, the object is not duplicated. So what if we have a nested object, in that case nested properties are also copied by reference and change in nested properties will be reflected in the original array (this is called shallow copy). To solve this issue we'll use deep cloning.
Deep copy: JSON.parse(JSON.stringify(obj))
it means changing data type of a value to to another data type. 2 types
- implicit-> automatic conversion of data type
- explicit-> type conversion example.. parseInt(), parseFloat(), String(), Boolean()
- Constants
- Block scoped variables and block scoped functions
- arrow functions
- Destructring
- Template Literals
- Extended parameter handling using Rest and Spread
Promises lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future. A Promise can be in one of the 3 states
- Pending
- Fulfilled
- Rejected
- The bind() method creates a new function that, when called, has its this keyword set to the provided value.
- Call() expects all parameters to be passed in individually, whereas apply() expects an array of all of our parameters. Difference between call and bind is:
- Call() accepts additional parameters as well,
- Executes the function it was called upon right away.
- The call() method does not make a copy of the function it is being called on.
Debouncing is a programming practice used to ensure that time-consuming tasks do not fire so often, that it stalls the performance of the web page. In other words, it limits the rate at which a function gets invoked.
Throttling is a technique in which, no matter how many times the user fires the event, the attached function will be executed only once in a given time interval.
Throttling will delay executing a function. It will reduce the notifications of an event that fires multiple times. Debouncing will bunch a series of sequential calls to a function into a single call to that function. It ensures that one notification is made for an event that fires multiple times. Article for debouncing and Throttling
The value of this is determined by how a function is called (runtime binding). A property of an execution context (global, function or eval) that, in non–strict mode, is always a reference to an object and in strict mode can be any value.
- Global Context- In global execution context, this always refer to the window object or global object whether in strict mode or not.
- Function Context- Inside a function, the value of this depends on how the function is called. To set the value of this to a particular value when calling a function, use call(), or apply()
It is a method that simply converts an object passed as the argument into a non-extensible state. This method doesn't allow us to add new properties but the value of properties can be changed and also allow us to delete the existing properties.
Currying is the pattern of functions that immediately evaluate and return other functions. This is made possible by the fact that Javascript functions are expressions that can return other functions.
Curried functions are constructed by chaining closures by defining and immediately returning their inner functions simultaneously.
function curry(f) { // curry(f) does the currying transform return function(a) { return function(b) { return f(a, b); }; }; }
The nullish coalescing operator ?? provides a short syntax for selecting a first “defined” variable from the list.
height = height ?? 100; sets height to 100 if it is undefined
- Map is a collection of keyed data items, just like an Object. But the main difference is that Map allows keys of any type.
- Methods:
map.get(),map.set() - A Set is a special type collection – “set of values” (without keys), where each value may occur only once.
Object.keys(), Object.values(), Object.entries()