Vanilla + ES6 Flashcards
Explain the difference between let, const, and var.
Scoping rules: variables declared by ‘var’ keyword is scoped to immediate function body (function scope) while ‘let’ & ‘const’ variables are scored to the immediate enclosing block (block scope)
Hoisting: variables declared with ‘var’ keyword are hoisted (initialized with undefined before the code runs) which means they are accessible in their enclosing scope even before they are declared. ‘let’ variables are not initialized until their definition is evaluated. Accessing them before the initialization results in a ‘ReferenceError’. The variable is said to be in a “temporal dead zone” from the start of the block until the initialization is processed.
Re-declaration: in strict mode, var will let you re-declare the same variable in the same scope while let raises a SyntaxError.
Global object property: At the top level, let unlike var does not create a property on the global (window) object
What are arrow functions in ES6? How do they differ from traditional function expressions?
New ES6 syntax for writing JS functions; simplies function scope.
Key Difference
Syntax:
- Arrow functions shorter syntax
- simplifies the function and return keywork
this
keyword:
- this
represents the object that called the function
- traditional functions: this gets rescoped to wherever it’s called so it could be the window, document, button or whatever.
- arrow functions: do not have their own this, they inherit it from the parent scope.
Argument object:
- Traditional functions have arguments
object which contains all the args passed to the function. Arrow does not but we can still use Rest parameters (…) to achieve a similar outcome.
Constructors:
- Traditional functions created with function declarations or expressions can be used as constructors (i.e., they can be instantiated with the new keyword). Arrow functions, however, cannot be used as constructors, and will throw an error when used with new.
Implicit Return:
- If the function body of an arrow function is written in one line and does not include curly braces, the value is implicitly returned without needing the return keyword.
Method properties:
- Arrow functions are not suitable to be used as object methods, as this will not be bound to the object. Traditional functions are suitable for this use case.
Can you explain what destructuring is in ES6 and provide an example of how it can be used?
Provides a simple way to unpack values from arrays, or properties from objects, into distinct variables. Also works in function parameters.
Describe how this
keyword works in JavaScript. How does it behave differently in arrow functions compared to regular functions?
In JS, the this
keywork is a special property that refers to the CONTEXT in which a function is called. It’s pretty tricky because what this
refers to can change depending on how and where it’s used.
Global context: this
refers to the global object (window object)
Function context: inside a regular function (not arrow, object method, or event handler), this
refers to the window or global object if not in strict mode. Otherwise undefined.
Method context: this
refers to the object that the method belongs to.
Event handler context: this
refers to the element that received the event.
Constructor context: this
refers to the newly created object
Manually set context: we can set value of this
using the call
, apply
or bind
methods.
Arrow function context: they don’t have their own this
so they inherit it from the parent scope => more predictable => easier to use for callbacks and event handlers.
What is a Promise in JavaScript? Can you describe a scenario where it would be useful?
An object representing the eventual completion or failure of an asynchronous operation. It’s basically a proxy for a value not necessarily known when the promise is created. It’s one way to deal with async operations without blocking the rest of your program.
A promise is in one of these states:
1. Pending: outcome not yet determined
2. Fulfilled: completed, the promise result is a value
3. Rejected: failed, result is an error
Promises can be chained together to perform a sequence of asynchronous operations one after the other. Once a Promise is fulfilled or rejected, it is considered settled and its state cannot change.
Scenario: Fetch API
One common scenario where Promises are useful is when dealing with AJAX requests in a web app. You might want to fetch data from a server, and because network operations can take a significant amount of time, you want them to be asynchronous so they don’t block the rest of your code.
We can then use then
on the Promise object with a callback that takes the response object and return another promise that resolves to data we want to use or perform an operation straight away. catch
to handle errors.
Can you explain how map(), reduce(), and filter() methods work in JavaScript? When would you use each?
A higher order function is a function that takes one or more functions as arguments, or returns a function as its result.
map(), reduce(), and filter() are higher-order functions in JavaScript that operate on arrays. Each takes a callback function as an argument and applies it in a certain way to produce a new result.
map(): creates a new array with the results of calling a provided function on every element in the calling array. It doesn’t modify the original array and returns a new array where the length matches the original assuming there are no undefined.
reduce(): applies a function against an accumulator and each element in the array from left -> right to reduce it to a single output value.
filter(): creates a new array with all the elements that pass the test/condition implemented by the provided function.
When to use each?
map(): when we want to transform all elements in an array
reduce(): when you want to compute a single value from all elements in array
filter(): when you want to select a subset of elements from an array based on a condition
They follow functional programming principles which avoids side effects, mutating data, etc.
What is the difference between a shallow copy and a deep copy? How would you create a deep copy of an object in JavaScript?
A shallow copy of an object is a copy where the new object has its own copy of the primitive data types (like numbers, strings, booleans), but any object references (including arrays, other objects, functions, etc.) point to the same objects as the original.
A deep copy of an object means creating a new object who’s primitive types and object references are copied over, so changes to one object do not affect the other. This includes recursively copying all objects and arrays.
One common method to create a deep copy of an object is to use JSON.stringify() to convert the object into a string, then JSON.parse() to parse it back into a new object:
Explain the concept of closure in JavaScript. Can you provide a practical use case?
A function that has access to its own scope, the outer scope and global scope. Basically, a function that is bundled with its lexical (parent) scope.
Even after outerFunction has finished executing and its execution context has been removed from the stack, innerFunction still has access to outerVariable. This is the power of closures - they keep the scope alive.
They’re particularly useful when you want to create functions on the fly with data that they should “remember”, or when you’re doing data encapsulation or object data privacy.
A practical use case for closures is data privacy or creating “private” variables. In JavaScript, we can’t have private variables due to its scoping rules, but closures give us a way to mimic them.
What are Template Literals in ES6? Can you give an example of how they can be used to enhance string manipulation?
A new way to define strings in JS. They provide a concise and convenient syntax to create strings and allow us to embed expressions within strings, perform multi-line string formatting, and create tagged templates.
What is the spread operator and how is it used in JavaScript? Can you provide an example?
The spread (…) operator in JS is used to unpack elements of iterable objects (like arrays or objects) into a list of elements.
Use cases:
1. Copying arrays: shallow copy of an array
2. Concatenating arrays let arr3 = [...arr1, ...arr2]
3. Using in function arguments sum(a,b,c) => sum(…[1,2,3])
4. Spreading objects: copy properties from one object to another
How does JavaScript handle asynchronous operations? Can you explain the event loop and how it relates to the call stack?
JS is single-threaded, so it executes one operation at a time in a single sequence. However, many operations like network requests are asynchronous, and can take a significant amount of time to complete. If a program waits for these operations synchronously, it would block the rest of the program from running.
To handle this, JS uses a combination of the CALL STACK, BROWSER WEB APIs, EVENT QUEUE, and the EVENT LOOP.
Call stack: a DS that tracks the program execution context to know what function is currently running and its nested calls. JS can only do one thing at a time since it has only one call stack. If a function is called, it’s added to the top of the stack. If a function is complete, it’s removed from the stack.
Web APIs and Event Queue: When an async operation like setTimeout or AJAX call is encountered. The operation is sent to be handled by the browser. Once the operation finishes (like timer expires, the network request receives a response), the provided callback function is sent to the event queue.
Event loop: this continuously checks if the call stack is empty. If yes: take the first callback function in the queue and pushes it onto the call stack to be executed.
In short: call stack handles the synchronous, line-by-line execution of code. Web APIs handle async operations. Once they are done, the callbacks enters the event queue. The event loop monitors the call stack and event queue, moving callbacks onto the stack when the stack is empty.
These all allow JS to be non-blocking and async, so it can finish other tasks without waiting for previous time consuming ones => performance and UX.
What is the purpose of async/await introduced in ES8? How does it improve upon promises?
Async/Await basically provides a more concise and easier-to-understand syntax for working with Promises, which are used for asynchronous operations in JavaScript.
Promises significantly improved the way we handle asynchronous operations, helping us avoid “callback hell” and making the code more readable and maintainable. However, Promises still use callbacks (.then() and .catch()), and complex Promise chains can still lead to somewhat difficult-to-read code.
So this is where async/await comes in:
Async: When placed before a function, async ensures that the function returns a Promise. If a value is returned from the function, it will be wrapped in a resolved Promise. If nothing is returned, a Promise that resolves to undefined is returned. If an error is thrown, it will return a rejected Promise.
Await: the await operator is used only inside an async function and makes JS wait until the Promise returns a result. It essentially pauses the execution of the async function and resumes when the Promise is either resolved or rejected, and then returns the result. This allows us to write asynchronous code that appears synchronous. Making it easier to read and understand. Also easier with try/catch block syntactic sugar for error handling which isn’t possible with plain promises.
Explain what ‘hoisting’ means in JavaScript. How does this behavior differ for var, let, and const?
Hoisting is a JavaScript mechanism where variable and function declarations are put into memory during the compile phase. This means that no matter where functions and variables are declared, they are moved to the top of their scope regardless of whether their scope is a global or a local.
var: when you declare a variable with ‘var’, both the declaration and the definition are hoisted (but definition is hoisted as ‘undefined’.
let and const: only the declarations are hoisted to the top of the block so you will get ‘ReferenceError’ because they are in the temporal dead zone from the start of the block until the declaration is processed.
Also this is likely because of var being in global scope as well since it’s is also added to the Window/Global object.
What are JavaScript modules in ES6? How do they differ from libraries in ‘vanilla’ JavaScript?
ES6 introduced the concept of JavaScript modules, which allow developers to break up their code into separate, reusable pieces, each encapsulating the code and functionality that serves a single purpose.
Modules are defined using export and imported using import. They are different from scripts because they allow you to export and import functions, objects, or values from one module to another, facilitating the reusability and maintainability of code.
Explain the Prototype Chain and Inheritance in JavaScript.
Every object in JavaScript has a built-in property, which is called its prototype. The prototype is itself an object, so the prototype will have its own prototype, making what’s called a prototype chain. The chain ends when we reach a prototype that has null
for its own prototype.
Prototype
> It’s like a map for that object type, it contains the functionalities for that object ttype. Any object that is instantiated will point to that prototype instead of creating new property in every instance (like a singleton in some way).
In a lot of cases it’s better to use prototype properties to add methods rather than creating the method inside the class.
JavaScript uses a Prototype Inheritance Model. That means that every constructor function/class has a prototype property that is shared by every instance of the constructor/class. So any methods and properties or prototype can be accessed by every instance. Prototype property returns an object.
Every object type has a prototype, and all instances created from that object type inherit the prototype methods. Only the constructor function has the prototype property.
function User(name) {
this.name = name;
}
User.prototype.sayHi = function () {
console.log(this.name);
};
let user = new User(‘John’);
user.sayHi(); // John
Differences between == and === operators.
Triple Equals (===)
- Returns true if both operands are of the same type and contain the same value.
- Does not perform type conversion.
- Preferred operator for equality comparison in JavaScript.
- Use it when you want to compare values strictly, considering both value and type.
Double Equals (==)
- Tries to perform type conversion if the types of the operands differ and then compares for equality.
- Performs complex type conversions, which can lead to unexpected results.
- Not recommended for equality comparison in JavaScript.
- Use it cautiously and with awareness of the type conversion rules.
JavaScript Event Model: Event Propagation, Event Bubbling and Event Capturing.
Event Propagation is the flow of the event in the DOM. It describes the order in which elements receive the event. It includes two phases: Capturing and Bubbling.
Event Capturing (or Trickling): In the capturing phase, the event starts from the top element (document object), and then it propagates down to the target element’s parents until it reaches the target element. It’s like the event is captured at the highest level and then trickled down to the element where the event occurred.
Event Bubbling: In the bubbling phase, the event starts from the target element, and then it bubbles up to the topmost parent (document object). It’s like a bubble in water, which starts at the bottom and then rises up to the surface.
Let’s say if we have two buttons: parent and child button, child button is inside parent button. If we click child button, we also clicked parent button.
The click event first gets dispatched to the child, then bubbles up to the parent. This is Event Bubbling.
Stopping Propagation: You can stop the event from propagating further either in capturing or bubbling phase using the stopPropagation() method. This can be useful when you don’t want parent handlers to be triggered.
Event Delegation: Understanding event propagation is key to event delegation, a technique where you delegate the handling of events for child elements to a single parent element. This can significantly improve performance for large amounts of elements.
Concepts of Callbacks and Promises in Asynchronous JavaScript.
A callback is a function that is to be executed after another function has finished executing, hence the name ‘callback’. In JavaScript, functions are objects and can be passed as arguments to other functions and can be executed after some event. However, managing asynchronous operations with callbacks can become more complex as you start to handle more tasks. This situation is sometimes referred to as “callback hell”.
To avoid “callback hell”, ES6 introduced Promises. A Promise is an object representing the eventual completion or failure of an asynchronous operation. It returns a value which is either a resolved value or a reason why it’s rejected.
Cross-browser compatibility issues and how to handle them.
Common issues include differences in:
- HTML and CSS interpretation and rendering
- JavaScript execution
- Unsupported features or APIs
- Layout and design inconsistencies
Solutions:
- Feature Detection
- Graceful degradation
- Progressive enhancement
- CSS Resets
- Cross-browser compatible libraries
Concepts around the Document Object Model (DOM) and manipulating it.
The Document Object Model (DOM) is a programming interface for HTML and XML documents. It represents the structure of a document as a tree of objects, allowing scripts to access and manipulate the content and structure of a web page.
- Nodes
In the DOM, all parts of the document, such as elements, attributes, and text, are represented by nodes. There are several types of nodes, but the most common are element nodes and text nodes. - Element, Attribute, and Text Nodes
An element node represents an HTML element in the document, an attribute node represents an attribute of an element, and a text node represents the text content of an element. - The Document Object
The document object is an entry point into the web page’s content. It’s a part of the Window object and can be used to access and manipulate the HTML content.
What is functional programming?
A programming paradigm where programs are constructed by applying and composing functions. It’s a declarative programming style that focuses on what to solve rather than how to solve. Its primary focus of what to solve in terms of function compositions and applications, instead of changing state and mutable data.
It involves:
1. Immutable data: data never changes, whenever we want to modify a data structure and its content => create a new copy and do so
2. Pure functions: takes in input and return an output without modifying any data outside its scope. Inherently testable and reliable since it doesn’t rely on external state.
3. First-class and Higher order functions: functions can be stored in variables, passed as function arguments and returned as results.
4. Function composition: Combining functions to produce new function or perform operation.
5. Avoid side effects: discourages changes in state and mutable data.
What is the difference between classical inheritance and prototypal inheritance?
Class Inheritance: instances inherit from classes (like a blueprint — a description of the class), and create sub-class relationships: hierarchical class taxonomies. Instances are typically instantiated via constructor functions with the new keyword. Class inheritance may or may not use the class keyword from ES6.
Prototypal Inheritance: instances inherit directly from other objects. Instances are typically instantiated via factory functions or Object.create(). Instances may be composed from many different objects, allowing for easy selective inheritance.
Prototypal is much more simpler and flexible
Can you provide an example of how to use the Set and Map classes in JavaScript? What are their advantages over traditional arrays and objects?
The Set and Map objects are collections which store unique elements.
Set is a collection of unique values without keys. Basically a glorified array that filters out duplicates on every insertion and specializes with unique values. Can be iterated with for..of or forEach
Map is a collection of keyed data items, just like an Object but the main difference is that Map allows keys of any type. In Object; can’t use object as keys for other objects and it converts object keys into a string.
How does async/await make handling Promises easier? Can you provide an example?
async/await makes handling Promises easier by providing a synchronous-looking way to write asynchronous code. They are a syntactic sugar on top of Promises.