30 Seconds of Interviews
A curated collection of common interview questions to help you prepare for your next interview.
Foreword
Interviews are daunting and can make even the most seasoned expert forget things under pressure. Review and learn what questions are commonly encountered in interviews curated by the community that's answered them and go prepared for anything they'll ask. By bringing together experience and real-world examples, you can go from being nervous to being prepared for that next big opportunity.
View online
Sponsors
All financial support on Patreon will be equally split between core colaborators on projects in the way of purchasing educational materials and courses.
Contributing
30 seconds of interviews is a community effort, so feel free to contribute in any way you can. Every contribution helps!
Do you have an excellent idea or know some cool questions that aren't on the list? Read the contribution guidelines and submit a pull request.
Join our Gitter channel to help with the development of the project.
Table of Contents
JavaScript
View contents
- How can you avoid callback hells?
- What is a callback?
- How do you clone an object in JavaScript?
- What is a closure? Can you give a useful example of one?
- How do you compare two objects in JavaScript?
- What is the DOM?
- What is the difference between the equality operators
==
and===
? - What is event-driven programming?
- Generate an array, containing the Fibonacci sequence, up until the nth term.
- What does
0.1 + 0.2 === 0.3
evaluate to? - What is the difference between the array methods
map()
andforEach()
? - What is functional programming?
- What will the console log in this example?
- How does hoisting work in JavaScript?
- What is the reason for wrapping the entire contents of a JavaScript source file in a function that is immediately invoked?
- Create a function that masks a string of characters with
#
except for the last four (4) characters. - Explain the difference between mutability and immutability, and mutating vs non-mutating methods.
- What is the only value not equal to itself in JavaScript?
- NodeJS uses a callback pattern in many instances where if an error were returned it will pass it as the first argument to the callback. What are the advantages of this pattern?
- What is the event loop in Node.js?
- What is the difference between
null
andundefined
? - Describe the different ways to create an object. When should certain ways be preferred over others?
- What is the difference between a parameter and an argument?
- Does JavaScript pass by value or by reference?
- Create a function
pipe
that performs left-to-right function composition by returning a function that accepts one argument. - In which states can a Promise be?
- What are Promises?
- How does prototypal inheritance differ from classical inheritance?
- What is a pure function?
- What is the output of the following code?
- What does the following function return?
- Explain the difference between a static method and an instance method.
- What is the difference between synchronous and asynchronous code in JavaScript?
- What is the
this
keyword and how does it work? - What does the following code evaluate to?
- What are JavaScript data types?
- What is the purpose of JavaScript UI libraries/frameworks like React, Vue, Angular, Hyperapp, etc?
- What does
'use strict'
do and what are some of the key benefits to using it? - What are the differences between
var
,let
,const
and no keyword statements?
HTML
View contents
- What are
defer
andasync
attributes on a<script>
tag? - What is the DOM?
- Can a web page contain multiple
<header>
elements? What about<footer>
elements? - Discuss the differences between an HTML specification and a browser’s implementation thereof.
- What are some differences that XHTML has compared to HTML?
- Briefly describe the correct usage of the following HTML5 semantic elements:
<header>
,<article>
,<section>
,<footer>
- What is HTML5 Web Storage? Explain
localStorage
andsessionStorage
. - What is the purpose of
alt
attribute on images? - Where and why is the
rel="noopener"
attribute used?
CSS
View contents
- What is CSS BEM?
- What are the advantages of using CSS preprocessors?
- Can you describe how CSS specificity works?
- Using flexbox, create a 3-column layout where each column takes up a
col-{n} / 12
ratio of the container. - What is a focus ring? What is the correct solution to handle them?
- Can you name the four types of
@media
properties? - What are the advantages of using CSS sprites and how are they utilized?
Node
View contents
JavaScript
==
and ===
?
What is the difference between the equality operators View answer
Triple equals (===
) checks for strict equality, which means both the type and value must be the same. Double equals (==
) on the other hand first performs type coercion so that both operands are of the same type and then applies strict comparison.
Good to hear
- Whenever possible, use triple equals to test equality because loose equality
==
can have unintuitive results. - Type coercion means the values are converted into the same type.
- Mention of falsy values and their comparison.
Additional links
In which states can a Promise be?
View answer
A Promise
is in one of these states:
- pending: initial state, neither fulfilled nor rejected.
- fulfilled: meaning that the operation completed successfully.
- rejected: meaning that the operation failed.
A pending promise can either be fulfilled with a value, or rejected with a reason (error). When either of these options happens, the associated handlers queued up by a promise's then method are called.
Good to hear
Additional links
What is a callback?
View answer
Callbacks are functions passed as an argument to another function to be executed once an event has occurred or a certain task is complete, often used in asynchronous code. Callback functions are invoked later by a piece of code but can be declared on initialization without being invoked.
As an example, event listeners are callbacks that are only executed when a specific event occurs.
function onClick() {
console.log("The user clicked on the page.")
}
document.addEventListener("click", onClick)
Good to hear
- Functions are first-class objects in JavaScript
- Callbacks vs Promises
Additional links
What is the DOM?
View answer
The DOM (Document Object Model) is a cross-platform API that treats HTML and XML documents as a tree structure consisting of nodes. These nodes (such as elements and text nodes) are objects that can be programmatically manipulated and any visible changes made to them are reflected live in the document. In a browser, this API is available to JavaScript where DOM nodes can be manipulated to change their styles, contents, placement in the document, or interacted with through event listeners.
Good to hear
- The DOM was designed to be independent of any particular programming language, making the structural representation of the document available from a single, consistent API.
- The DOM is constructed progressively in the browser as a page loads, which is why scripts are often placed at the bottom of a page, in the
<head>
with adefer
attribute, or inside aDOMContentLoaded
event listener. Scripts that manipulate DOM nodes should be run after the DOM has been constructed to avoid errors. document.getElementById()
anddocument.querySelector()
are common functions for selecting DOM nodes.- Setting the
innerHTML
property to a new value runs the string through the HTML parser, offering an easy way to append dynamic HTML content to a node.
Additional links
var
, let
, const
and no keyword statements?
What are the differences between View answer
No keyword
When no keyword exists before a variable assignment, it is either assigning a global variable if one does not exist, or reassigns an already declared variable. In non-strict mode, if the variable has not yet been declared, it will assign the variable as a property of the global object (window
in browsers). In strict mode, it will throw an error to prevent unwanted global variables from being created.
var
var
was the default statement to declare a variable until ES2015. It creates a function-scoped variable that can be reassigned and redeclared. However, due to its lack of block scoping, it can cause issues if the variable is being reused in a loop that contains an asynchronous callback because the variable will continue to exist outside of the block scope.
Below, by the time the the setTimeout
callback executes, the loop has already finished and the i
variable is 10
, so all ten callbacks reference the same variable available in the function scope.
for (var i = 0; i < 10; i++) {
setTimeout(() => {
// logs `10` ten times
console.log(i)
})
}
/* Solutions with `var` */
for (var i = 0; i < 10; i++) {
// Passed as an argument will use the value as-is in
// that point in time
setTimeout(console.log, 0, i)
}
for (var i = 0; i < 10; i++) {
// Create a new function scope that will use the value
// as-is in that point in time
;(i => {
setTimeout(() => {
console.log(i)
})
})(i)
}
let
let
was introduced in ES2015 and is the new preferred way to declare variables that will be reassigned later. Trying to redeclare a variable again will throw an error. It is block-scoped so that using it in a loop will keep it scoped to the iteration.
for (let i = 0; i < 10; i++) {
setTimeout(() => {
// logs 0, 1, 2, 3, ...
console.log(i)
})
}
const
const
was introduced in ES2015 and is the new preferred default way to declare all variables if they won't be reassigned later, even for objects that will be mutated (as long as the reference to the object does not change). It is block-scoped and cannot be reassigned.
const myObject = {}
myObject.prop = "hello!" // No error
myObject = "hello" // Error
Good to hear
- All declarations are hoisted to the top of their scope.
- Show a common issue with using
var
and howlet
can solve it, as well as a solution that keepsvar
. var
should be avoided whenever possible and preferconst
as the default declaration statement for all variables unless they will be reassigned later, then uselet
if so.
Additional links
Generate an array, containing the Fibonacci sequence, up until the nth term.
View answer
Initialize an empty array of length n
. Use Array.prototype.reduce()
to add values into the array, using the sum of the last two values, except for the first two.
const fibonacci = n =>
[...Array(n)].reduce(
(acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i),
[]
)
Good to hear
Additional links
0.1 + 0.2 === 0.3
evaluate to?
What does View answer
It evaluates to false
because JavaScript uses the IEEE 754 standard for Math and it makes use of 64-bit floating numbers. This causes precision errors when doing decimal calculations, in short, due to computers working in Base 2 while decimal is Base 10.
0.1 + 0.2 // 0.30000000000000004
A solution to this problem would be to use a function that determines if two numbers are approximately equal by defining an error margin (epsilon) value that the difference between two values should be less than.
const approxEqual = (n1, n2, epsilon = 0.0001) => Math.abs(n1 - n2) < epsilon
approxEqual(0.1 + 0.2, 0.3) // true
Good to hear
- A simple solution to this problem
Additional links
map()
and forEach()
?
What is the difference between the array methods View answer
Both methods iterate through the elements of an array. map()
maps each element to new element by invoking the callback function on each element and returns a new array. On the other hand, forEach()
invokes the callback function for each element but does not return a new array. forEach()
is generally used when causing a side effect on each iteration, whereas map()
is a common functional programming technique.
Good to hear
- Use
forEach()
if you need to iterate over an array and cause mutations to the elements without needing to return values to generate a new array. map()
is the right choice to keep data immutable where each value of the original array is mapped to a new array.
Additional links
What will the console log in this example?
var foo = 1
var foobar = function() {
console.log(foo)
var foo = 2
}
foobar()
View answer
Due to hoisting, the local variable foo
is declared before the console.log
method is called. This means the local variable foo
is passed as an argument to console.log()
instead of the global one declared outside of the function. However, since the value is not hoisted with the variable declaration, the output will be undefined
, not 2
.
Good to hear
- Hoisting is JavaScript’s default behavior of moving declarations to the top
- Mention of
strict
mode
Additional links
How does hoisting work in JavaScript?
View answer
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 global or local.
However, the value is not hoisted with the declaration.
The following snippet:
console.log(hoist)
var hoist = "value"
is equivalent to:
var hoist
console.log(hoist)
hoist = "value"
Therefore logging hoist
outputs undefined
to the console, not "value"
.
Hoisting also allows you to invoke a function declaration before it appears to be declared in a program.
myFunction() // No error; logs "hello"
function myFunction() {
console.log("hello")
}
But be wary of function expressions that are assigned to a variable:
myFunction() // Error: `myFunction` is not a function
var myFunction = function() {
console.log("hello")
}
Good to hear
- Hoisting is JavaScript’s default behavior of moving declarations to the top
- Functions declarations are hoisted before variable declarations
Additional links
What is the reason for wrapping the entire contents of a JavaScript source file in a function that is immediately invoked?
View answer
This technique is very common in JavaScript libraries. It creates a closure around the entire contents of the file which creates a private namespace and thereby helps avoid potential name clashes between different JavaScript modules and libraries. The function is immediately invoked so that the namespace (library name) is assigned the return value of the function.
const myLibrary = (function() {
var privateVariable = 2
return {
publicMethod: () => privateVariable
}
})()
privateVariable // ReferenceError
myLibrary.publicMethod() // 2
Good to hear
- Used among many popular JavaScript libraries
- Creates a private namespace
Additional links
#
except for the last four (4) characters.
Create a function that masks a string of characters with mask("123456789") // "#####6789"
View answer
There are many ways to solve this problem, this is just one one of them.
Using String.prototype.slice()
, we can grab a portion of the string from index 0
(first character) to index -4
(5th last character) and calculate the resulting length, using String.prototype.repeat()
to repeat the mask character that many times. Then, using String.prototype.slice()
once more, we can concatenate the last 4 characters by passing -4
as an argument.
const mask = (str, maskChar = "#") =>
maskChar.repeat(str.slice(0, -4).length) + str.slice(-4)
Good to hear
- Short, one-line functional solutions to problems should be preferred provided they are efficient
Additional links
NodeJS uses a callback pattern in many instances where if an error were returned it will pass it as the first argument to the callback. What are the advantages of this pattern?
fs.readFile(filePath, function(err, data) {
if (err) {
// handle the error, the return is important here
// so execution stops here
return console.log(err)
}
// use the data object
console.log(data)
})
View answer
Advantages include:
- Not needing to process data if there is no need to even reference it
- Having a consistent API leads to more adoption
- Ability to easily adapt a callback pattern that will lead to more maintainable code
As you can see from below example, the callback is called with null as its first argument if there is no error. However, if there is an error, you create an Error object, which then becomes the callback's only parameter. The callback function allows a user to easily know whether or not an error occurred.
This practice is also called the Node.js error convention, and this kind of callback implementations are called error-first callbacks.
var isTrue = function(value, callback) {
if (value === true) {
callback(null, "Value was true.")
} else {
callback(new Error("Value is not true!"))
}
}
var callback = function(error, retval) {
if (error) {
console.log(error)
return
}
console.log(retval)
}
isTrue(false, callback)
isTrue(true, callback)
/*
{ stack: [Getter/Setter],
arguments: undefined,
type: undefined,
message: 'Value is not true!' }
Value was true.
*/
Good to hear
- This is just a convention. However, you should stick to it.
Additional links
How do you clone an object in JavaScript?
View answer
Using the object spread operator ...
, the object's own enumerable properties can be copied
into the new object. This creates a shallow clone of the object.
const obj = { a: 1, b: 2 }
const shallowClone = { ...obj }
With this technique, prototypes are ignored. In addition, nested objects are not cloned, but rather their references get copied, so nested objects still refer to the same objects as the original. Deep-cloning is much more complex in order to effectively clone any type of object (Date, RegExp, Function, Set, etc) that may be nested within the object.
Other alternatives include:
JSON.parse(JSON.stringify(obj))
can be used to deep-clone a simple object, but it is CPU-intensive and only accepts valid JSON (therefore it strips functions and does not allow circular references).Object.assign({}, obj)
is another alternative.Object.keys(obj).reduce((acc, key) => (acc[key] = obj[key], acc), {})
is another more verbose alternative that shows the concept in greater depth.
Good to hear
- JavaScript passes objects by reference, meaning that nested objects get their references copied, instead of their values.
- The same method can be used to merge two objects.
Additional links
null
and undefined
?
What is the difference between View answer
In JavaScript, two values discretely represent nothing - undefined
and null
. The concrete difference between them is that null
is explicit, while undefined
is implicit. When a property does not exist or a variable has not been given a value, the value is undefined
. null
is set as the value to explicitly indicate “no value”. In essence, undefined
is used when the nothing is not known, and null
is used when the nothing is known.
Good to hear
typeof undefined
evaluates to"undefined"
.typeof null
evaluates"object"
. However, it is still a primitive value and this is considered an implementation bug in JavaScript.undefined == null
evaluates totrue
.
Additional links
Describe the different ways to create an object. When should certain ways be preferred over others?
View answer
Object literal
Often used to store one occurrence of data.
const person = {
name: "John",
age: 50,
birthday() {
this.age++
}
}
person.birthday() // person.age === 51
Constructor
Often used when you need to create multiple instances of an object, each with their own data that other instances of the class cannot affect. The new
operator must be used before invoking the constructor or the global object will be mutated.
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.birthday = function() {
this.age++
}
const person1 = new Person("John", 50)
const person2 = new Person("Sally", 20)
person1.birthday() // person1.age === 51
person2.birthday() // person2.age === 21
Factory function
Creates a new object similar to a constructor, but can store private data using a closure. There is also no need to use new
before invoking the function or the this
keyword. Factory functions usually discard the idea of prototypes and keep all properties and methods as own properties of the object.
const createPerson = (name, age) => {
const birthday = () => person.age++
const person = { name, age, birthday }
return person
}
const person = createPerson("John", 50)
person.birthday() // person.age === 51
Object.create()
Sets the prototype of the newly created object.
const personProto = {
birthday() {
this.age++
}
}
const person = Object.create(personProto)
person.age = 50
person.birthday() // person.age === 51
A second argument can also be supplied to Object.create()
which acts as a descriptor for the new properties to be defined.
Object.create(personProto, {
age: {
value: 50,
writable: true,
enumerable: true
}
})
Good to hear
- Prototypes are objects that other objects inherit properties and methods from.
- Factory functions offer private properties and methods through a closure but increase memory usage as a tradeoff, while classes do not have private properties or methods but reduce memory impact by reusing a single prototype object.
Additional links
What is the difference between a parameter and an argument?
View answer
Parameters are the variable names of the function definition, while arguments are the values given to a function when it is invoked.
function myFunction(parameter1, parameter2) {
console.log(arguments[0]) // "argument1"
}
myFunction("argument1", "argument2")
Good to hear
arguments
is an array-like object containing information about the arguments supplied to an invoked function.myFunction.length
describes the arity of a function (how many parameters it has, regardless of how many arguments it is supplied).
Additional links
Does JavaScript pass by value or by reference?
View answer
JavaScript always passes by value. However, with objects, the value is a reference to the object.
Good to hear
- Difference between pass-by-value and pass-by-reference
Additional links
How do you compare two objects in JavaScript?
View answer
Even though two different objects can have the same properties with equal values, they are not considered equal when compared using ==
or ===
. This is because they are being compared by their reference (location in memory), unlike primitive values which are compared by value.
In order to test if two objects are equal in structure, a helper function is required. It will
iterate through the own properties of each object to test if they have the same values, including nested objects.
Optionally, the prototypes of the objects may also be tested for equivalence by passing true
as the 3rd argument.
Note: this technique does not attempt to test equivalence of data structures other than plain objects, arrays, functions, dates and primitive values.
function isDeepEqual(obj1, obj2, testPrototypes = false) {
if (obj1 === obj2) {
return true
}
if (typeof obj1 === "function" && typeof obj2 === "function") {
return obj1.toString() === obj2.toString()
}
if (obj1 instanceof Date && obj2 instanceof Date) {
return obj1.getTime() === obj2.getTime()
}
const prototypesAreEqual = testPrototypes
? isDeepEqual(
Object.getPrototypeOf(obj1),
Object.getPrototypeOf(obj2),
true
)
: true
const obj1Props = Object.getOwnPropertyNames(obj1)
const obj2Props = Object.getOwnPropertyNames(obj2)
return (
obj1Props.length === obj2Props.length &&
prototypesAreEqual &&
obj1Props.every(prop => isDeepEqual(obj1[prop], obj2[prop]))
)
}
Good to hear
- Primitives like strings and numbers are compared by their value
- Objects on the other hand are compared by their reference (location in memory)
Additional links
What are Promises?
View answer
The Promise
object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
An example can be the following snippet, which after 100ms prints out the result string to the standard output. Also, note the catch, which can be used for error handling. Promise
s are chainable.
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("result")
}, 100)
})
.then(console.log)
.catch(console.error)
Good to hear
- Take a look into the other questions regarding
Promise
s!
Additional links
How does prototypal inheritance differ from classical inheritance?
View answer
In the classical inheritance paradigm, object instances inherit their properties and functions from a class, which acts as a blueprint for the object. Object instances are typically created using a constructor and the new
keyword.
In the prototypal inheritance paradigm, object instances inherit directly from other objects and are typically created using factory functions or Object.create()
. Finally, object instances can be composed from many different objects, allowing for selective inheritance.
Good to hear
- Classes create hierarches and taxonomies.
- Prototypal inheritance allows for a flat prototype delegation hierarchy.
Additional links
What is the output of the following code?
const a = [1, 2, 3]
const b = [1, 2, 3]
const c = "1,2,3"
console.log(a == c)
console.log(a == b)
View answer
The first console.log
outputs true
because JavaScript's compiler performs type conversion and therefore it compares to strings by their value. On the other hand, the second console.log
outputs false
because Arrays are Objects and Objects are compared by reference.
Good to hear
- JavaScript performs automatic type conversion
- Objects are compared by reference
- Primitives are compared by value
Additional links
What does the following function return?
function greet() {
return
{
message: "hello"
}
}
View answer
Because of JavaScript's automatic semicolon insertion (ASI), the compiler places a semicolon after return
keyword and therefore it returns undefined
without an error being thrown.
Good to hear
- Automatic semicolon placement can lead to time-consuming bugs
Additional links
What is the difference between synchronous and asynchronous code in JavaScript?
View answer
Synchronous means each operation must wait for the previous one to complete.
Asynchronous means an operation can occur while another operation is still being processed.
In JavaScript, all code is synchronous due to the single-threaded nature of it. However, asynchronous operations not part of the program (such as XMLHttpRequest
or setTimeout
) are processed outside of the main thread because they are controlled by native code (browser APIs), but callbacks part of the program will still be executed synchronously.
Good to hear
- JavaScript has a concurrency model based on an "event loop".
- Functions like
alert
block the main thread so that no user input is registered until the user closes it.
Additional links
What does the following code evaluate to?
typeof typeof 0
View answer
It evaluates to "string"
.
typeof 0
evaluates to the string "number"
and therefore typeof "number"
evaluates to "string"
.
Good to hear
Additional links
What are JavaScript data types?
View answer
The latest ECMAScript standard defines seven data types, six of them being primitive: Boolean
, Null
, Undefined
, Number
, String
, Symbol
and one non-primitive data type: Object
.
Good to hear
- Mention of newly added
Symbol
data type Array
,Date
andfunction
are all of typeobject
- Functions in JavaScript are objects with the capability of being callable
Additional links
How can you avoid callback hells?
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
getMoreData(c, function(d) {
getMoreData(d, function(e) {
// ...
})
})
})
})
})
View answer
Refactoring the functions to return promises and using async/await
is usually the best option. Instead of supplying the functions with callbacks that cause deep nesting, they return a promise that can be await
ed and will be resolved once the data has arrived, allowing the next line of code to be evaluated in a sync-like fashion.
The above code can be restructured like so:
async function asyncAwaitVersion() {
const a = await getData()
const b = await getMoreData(a)
const c = await getMoreData(b)
const d = await getMoreData(c)
const e = await getMoreData(e)
// ...
}
There are lots of ways to solve the issue of callback hells:
- Modularization: break callbacks into independent functions
- Use a control flow library, like async
- Use generators with Promises
- Use async/await (from v7 on)
Good to hear
- As an efficient JavaScript developer, you have to avoid the constantly growing indentation level, produce clean and readable code and be able to handle complex flows.
Additional links
What is event-driven programming?
View answer
Event-driven programming is a paradigm that involves building applications that send and receive events. When the program emits events, the program responds by running any callback functions that are registered to that event and context, passing in associated data to the function. With this pattern, events can be emitted into the wild without throwing errors even if no functions are subscribed to it.
A common example of this is the pattern of elements listening to DOM events such as click
and mouseenter
, where a callback function is run when the event occurs.
document.addEventListener("click", function(event) {
// This callback function is run when the user
// clicks on the document.
})
Without the context of the DOM, the pattern may look like this:
const hub = createEventHub()
hub.on("message", function(data) {
console.log(`${data.username} said ${data.text}`)
})
hub.emit("message", {
username: "John",
text: "Hello?"
})
With this implementation, on
is the way to subscribe to an event, while emit
is the way to publish the event.
Good to hear
- Follows a publish-subscribe pattern.
- Responds to events that occur by running any callback functions subscribed to the event.
- Show how to create a simple pub-sub implementation with JavaScript.
Additional links
What is a pure function?
View answer
A pure function is function that satisfies these two conditions:
- Given the same input, the function returns the same output.
- The function doesn't cause side effects outside of the function's scope (i.e. mutate data outside the function or data supplied to the function).
Pure functions can mutate local data within the function as long as it satisfies the two conditions above.
Pure
const a = (x, y) => x + y
const b = (arr, value) => arr.concat(value)
const c = arr => [...arr].sort((a, b) => a - b)
Impure
const a = (x, y) => x + y + Math.random()
const b = (arr, value) => (arr.push(value), arr)
const c = arr => arr.sort((a, b) => a - b)
Good to hear
- Pure functions are easier to reason about due to their reliability.
- All functions should be pure unless explicitly causing a side effect (i.e.
setInnerHTML
). - If a function does not return a value, it is an indication that it is causing side effects.
Additional links
What is functional programming?
View answer
Functional programming is a paradigm in which programs are built in a declarative manner using pure functions that avoid shared state and mutable data. Functions that always return the same value for the same input and don't produce side effects are the pillar of functional programming. Many programmers consider this to be the best approach to software development as it reduces bugs and cognitive load.
Good to hear
- Cleaner, more concise development experience
- Simple function composition
- Features of JavaScript that enable functional programming (
.map
,.reduce
etc.) - JavaScript is multi-paradigm programming language (Object-Oriented Programming and Functional Programming live in harmony)
Additional links
Explain the difference between mutability and immutability, and mutating vs non-mutating methods.
View answer
"Mutability" means a value is subject to change. "Immutability" means a value cannot change.
Objects are mutable, while primitive values (strings, numbers, etc) are immutable. This means any operation performed on a primitive value does not change the original value.
All String.prototype
methods do not have an effect on the original string and return a new string. On the other hand, while some methods of Array.prototype
do not mutate the original array reference and produce a fresh array, some cause mutations.
const myString = "hello!"
myString.replace("!", "") // returns a new string, cannot mutate the original value
const originalArray = [1, 2, 3]
originalArray.push(4) // mutates originalArray, now [1, 2, 3, 4]
originalArray.concat(4) // returns a new array, does not mutate the original
Good to hear
- List of mutating and non-mutating array methods
Additional links
Explain the difference between a static method and an instance method.
View answer
Static methods belong to a class and don't act on instances, while instance methods belong to the class prototype which is inherited by all instances of the class and acts on them.
Array.isArray // static method of Array
Array.prototype.push // instance method of Array
In this case, the Array.isArray
method does not make sense as an instance method of arrays because we already know the value is an array when working with it.
Instance methods could technically work as static methods, but provide terser syntax:
const arr = [1, 2, 3]
arr.push(4)
Array.push(arr, 4)
Good to hear
- How to create static and instance methods with ES2015 class syntax
Additional links
What is the only value not equal to itself in JavaScript?
View answer
NaN
(Not-a-Number) is the only value not equal to itself when comparing with any of the comparison operators. NaN
is often the result of meaningless math computations, so two NaN
values make no sense to be considered equal.
Good to hear
- The difference between
isNaN()
andNumber.isNaN()
const isNaN = x => x !== x
Additional links
this
keyword and how does it work?
What is the View answer
The this
keyword is an object that represents the context of an executing function. Regular functions can have their this
value changed with the methods call()
, apply()
and bind()
. Arrow functions implicitly bind this
so that it refers to the context of its lexical environment, regardless of whether or not its context is set explicitly with call()
.
Here are some common examples of how this
works:
Object literals
this
refers to the object itself inside regular functions if the object precedes the invocation of the function.
Properties set as this
do not refer to the object.
var myObject = {
property: this,
regularFunction: function() {
return this
},
arrowFunction: () => {
return this
},
iife: (function() {
return this
})()
}
myObject.regularFunction() // myObject
myObject["regularFunction"]() // my Object
myObject.property // NOT myObject; lexical `this`
myObject.arrowFunction() // NOT myObject; lexical `this`
myObject.iife() // NOT myObject; lexical `this`
const regularFunction = myObject.regularFunction
regularFunction() // NOT myObject; lexical `this`
Event listeners
this
refers to the element listening to the event.
document.body.addEventListener("click", function() {
console.log(this) // document.body
})
Constructors
this
refers to the newly created object.
class Example {
constructor() {
console.log(this) // myExample
}
}
const myExample = new Example()
Manual
With call()
and apply()
, this
refers to the object passed as the first argument.
var myFunction = function() {
return this
}
myFunction.call({ customThis: true }) // { customThis: true }
this
Unwanted Because this
can change depending on the scope, it can have unexpected values when using regular functions.
var obj = {
arr: [1, 2, 3],
doubleArr() {
return this.arr.map(function(value) {
// this is now this.arr
return this.double(value)
})
},
double() {
return value * 2
}
}
obj.doubleArr() // Uncaught TypeError: this.double is not a function
Good to hear
- In non-strict mode, global
this
is the global object (window
in browsers), while in strict mode globalthis
isundefined
. Function.prototype.call
andFunction.prototype.apply
set thethis
context of an executing function as the first argument, withcall
accepting a variadic number of arguments thereafter, andapply
accepting an array as the second argument which are fed to the function in a variadic manner.Function.prototype.bind
returns a new function that enforces thethis
context as the first argument which cannot be changed by other functions.- If a function requires its
this
context to be changed based on how it is called, you must use thefunction
keyword. Use arrow functions when you wantthis
to be the surrounding (lexical) context.
Additional links
pipe
that performs left-to-right function composition by returning a function that accepts one argument.
Create a function const square = v => v * v
const double = v => v * 2
const addOne = v => v + 1
const res = pipe(square, double, addOne)
res(3) // 19; addOne(double(square(3)))
View answer
Gather all supplied arguments using the rest operator ...
and return a unary function that uses Array.prototype.reduce()
to run the value through the series of functions before returning the final value.
const pipe = (...fns) => x => fns.reduce((v, fn) => fn(v), x)
Good to hear
- Function composition is the process of combining two or more functions to produce a new function.
Additional links
What is a closure? Can you give a useful example of one?
View answer
A closure is a function defined inside another function and has access to its lexical scope even when it is executing outside its lexical scope. The closure has access to variables in three scopes:
- Variables declared in its own scope
- Variables declared in the scope of the parent function
- Variables declared in the global scope
In JavaScript, all functions are closures because they have access to the outer scope, but most functions don't utilise the usefulness of closures: the persistence of state. Closures are also sometimes called stateful functions because of this.
In addition, closures are the only way to store private data that can't be accessed from the outside in JavaScript. They are the key to the UMD (Universal Module Definition) pattern, which is frequently used in libraries that only expose a public API but keep the implementation details private, preventing name collisions with other libraries or the user's own code.
Good to hear
- Closures are useful because they let you associate data with a function that operates on that data.
- A closure can substitute an object with only a single method.
- Closures can be used to emulate private properties and methods.
Additional links
What is the purpose of JavaScript UI libraries/frameworks like React, Vue, Angular, Hyperapp, etc?
View answer
The main purpose is to avoid manipulating the DOM directly and keep the state of an application in sync with the UI easily. Additionally, they provide the ability to create components that can be reused when they have similar functionality with minor differences, avoiding duplication which would require multiple changes whenever the structure of a component which is reused in multiple places needs to be updated.
When working with DOM manipulation libraries like jQuery, the data of an application is generally kept in the DOM itself, often as class names or data
attributes. Manipulating the DOM to update the UI involves many extra steps and can introduce subtle bugs over time. Keeping the state separate and letting a framework handle the UI updates when the state changes reduces cognitive load. Saying you want the UI to look a certain way when the state is a certain value is the declarative way of creating an application, instead of the imperative way of manually updating the UI to reflect the new state.
Good to hear
- The virtual DOM is a representation of the real DOM tree in the form of plain objects, which allows a library to write code as if the entire document is thrown away and rebuilt on each change, while the real DOM only updates what needs to be changed. Comparing the new virtual DOM against the previous one leads to high efficiency as changing real DOM nodes is costly compared to recalculating the virtual DOM.
- JSX is an extension to JavaScript that provides XML-like syntax to create virtual DOM objects which is transformed to function calls by a transpiler. It simplifies control flow (if statements/ternary expressions) compared to tagged template literals.
Additional links
'use strict'
do and what are some of the key benefits to using it?
What does View answer
Including 'use strict'
at the beginning of your JavaScript source file enables strict mode, which enfores more strict parsing and error handling of JavaScript code. It is considered a good practice and offers a lot of benefits, such as:
- Easier debugging due to eliminating silent errors.
- Disallows variable redefinition.
- Prevents accidental global variables.
- Oftentimes provides increased performance over identical code that is not running in strict mode.
- Simplifies
eval()
andarguments
. - Helps make JavaScript more secure.
Good to hear
- Eliminates
this
coercion, throwing an error whenthis
references a value ofnull
orundefined
. - Throws an error on invalid usage of
delete
. - Prohibits some syntax likely to be defined in future versions of ECMAScript
Additional links
What is the event loop in Node.js?
View answer
The event loop handles all async callbacks. Callbacks are queued in a loop, while other code runs, and will run one by one when the response for each one has been received.
Good to hear
- The event loop allows Node.js to perform non-blocking I/O operations, despite the fact that JavaScript is single-threaded
Additional links
HTML
<header>
elements? What about <footer>
elements?
Can a web page contain multiple View answer
Yes to both. The W3 documents state that the tags represent the header(<header>
) and footer(<footer>
) areas of their nearest ancestor "section". So not only can the page <body>
contain a header and a footer, but so can every <article>
and <section>
element.
Good to hear
- W3 recommends having as many as you want, but only 1 of each for each "section" of your page, i.e. body, section etc.
Additional links
<header>
, <article>
,<section>
, <footer>
Briefly describe the correct usage of the following HTML5 semantic elements: View answer
-
<header>
is used to contain introductory and navigational information about a section of the page. This can include the section heading, the author’s name, time and date of publication, table of contents, or other navigational information. -
<article>
is meant to house a self-contained composition that can logically be independently recreated outside of the page without losing it’s meaining. Individual blog posts or news stories are good examples. -
<section>
is a flexible container for holding content that shares a common informational theme or purpose. -
<footer>
is used to hold information that should appear at the end of a section of content and contain additional information about the section. Author’s name, copyright information, and related links are typical examples of such content.
Good to hear
- Other semantic elements are
<form>
and<table>
Additional links
alt
attribute on images?
What is the purpose of View answer
The alt
attribute provides alternative information for an image if a user cannot view it. If the image is for decorative purposes only, the alt
attribute should be empty. On the other hand, if image contains information the alt
attribute should describe image.
Good to hear
- Decorative images should have empty
alt
tag
Additional links
defer
and async
attributes on a <script>
tag?
What are View answer
If neither attribute is present, the script is downloaded and executed synchronously, and will halt parsing of the document until it has finished executing (default behavior). Scripts are downloaded and executed in the order they are encountered.
The defer
attribute downloads the script while the document is still parsing but waits until the document has finished parsing before executing it, equivalent to executing inside a DOMContentLoaded
event listener. defer
scripts will execute in order.
The async
attribute downloads the script during parsing the document but will pause the parser to execute the script before it has fully finished parsing. async
scripts will not necessarily execute in order.
Note: both attributes must only be used if the script has a src
attribute (i.e. not an inline script).
<script src="myscript.js"></script>
<script src="myscript.js" defer></script>
<script src="myscript.js" async></script>
Good to hear
- Placing a
defer
script in the<head>
allows the browser to download the script while the page is still parsing, and is therefore a better option than placing the script before the end of the body. - If the scripts rely on each other, use
defer
. - If the script is independent, use
async
. - Use
defer
if the DOM must be ready and the contents are not placed within aDOMContentLoaded
listener.
Additional links
What is the DOM?
View answer
The DOM (Document Object Model) is a cross-platform API that treats HTML and XML documents as a tree structure consisting of nodes. These nodes (such as elements and text nodes) are objects that can be programmatically manipulated and any visible changes made to them are reflected live in the document. In a browser, this API is available to JavaScript where DOM nodes can be manipulated to change their styles, contents, placement in the document, or interacted with through event listeners.
Good to hear
- The DOM was designed to be independent of any particular programming language, making the structural representation of the document available from a single, consistent API.
- The DOM is constructed progressively in the browser as a page loads, which is why scripts are often placed at the bottom of a page, in the
<head>
with adefer
attribute, or inside aDOMContentLoaded
event listener. Scripts that manipulate DOM nodes should be run after the DOM has been constructed to avoid errors. document.getElementById()
anddocument.querySelector()
are common functions for selecting DOM nodes.- Setting the
innerHTML
property to a new value runs the string through the HTML parser, offering an easy way to append dynamic HTML content to a node.
Additional links
Discuss the differences between an HTML specification and a browser’s implementation thereof.
View answer
HTML specifications such as HTML5
define a set of rules that a document must adhere to in order to be “valid” according to that specification. In addition, a specification provides instructions on how a browser must interpret and render such a document.
A browser is said to “support” a specification if it handles valid documents according to the rules of the specification. As of yet, no browser supports all aspects of the HTML5
specification (although all of the major browser support most of it), and as a result, it is necessary for the developer to confirm whether the aspect they are making use of will be supported by all of the browsers on which they hope to display their content. This is why cross-browser support continues to be a headache for developers, despite the improved specificiations.
Good to hear
HTML5
defines some rules to follow for an invalidHTML5
document (i.e., one that contains syntactical errors)- However, invalid documents may contain anything, so it's impossible for the specification to handle all possibilities comprehensively.
- Thus, many decisions about how to handle malformed documents are left up to the browser.
Additional links
What are some differences that XHTML has compared to HTML?
View answer
Some of the key differences are:
- An XHTML element must have an XHTML
<DOCTYPE>
- Attributes values must be enclosed in quotes
- Attribute minimization is forbidden (e.g. one has to use
checked="checked"
instead ofchecked
) - Elements must always be properly nested
- Elements must always be closed
- Special characters must be escaped
Good to hear
- Any element can be self-closed
- Tags ands attributes are case-sensitive, usually lowercase
Additional links
rel="noopener"
attribute used?
Where and why is the View answer
The rel="noopener"
is an attribute used in <a>
elements (hyperlinks). It prevents pages from having a window.opener
property, which would otherwise point to the page from where the link was opened and would allow the page opened from the hyperlink to manipulate the page where the hyperlink is.
Good to hear
rel="noopener"
is applied to hyperlinks.rel="noopener"
prevents opened links from manipulating the source page.
Additional links
localStorage
and sessionStorage
.
What is HTML5 Web Storage? Explain View answer
With HTML5, web pages can store data locally within the user’s browser. The data is stored in name/value pairs, and a web page can only access data stored by itself.
Differences between localStorage
and sessionStorage
regarding lifetime:
- Data stored through
localStorage
is permanent: it does not expire and remains stored on the user’s computer until a web app deletes it or the user asks the browser to delete it. sessionStorage
has the same lifetime as the top-level window or browser tab in which the data got stored. When the tab is permanently closed, any data stored throughsessionStorage
is deleted.
Differences between localStorage
and sessionStorage
regarding storage scope:
Both forms of storage are scoped to the document origin so that documents with different origins will never share the stored objects.
sessionStorage
is also scoped on a per-window basis. Two browser tabs with documents from the same origin have separatesessionStorage
data.- Unlike in
localStorage
, the same scripts from the same origin can't access each other'ssessionStorage
when opened in different tabs.
Good to hear
- Earlier, this was done with cookies.
- The storage limit is far larger (at least 5MB) than with cookies and its faster.
- The data is never transferred to the server and can only be used if the client specifically asks for it.
Additional links
CSS
What is CSS BEM?
View answer
The BEM methodology is a naming convention for CSS classes in order to keep CSS more maintainable by defining namespaces to solve scoping issues. BEM stands for Block Element Modifier which is an explanation for its structure. A Block is a standalone component that is reusable across projects and acts as a "namespace" for sub components (Elements). Modifiers are used as flags when a Block or Element is in a certain state or is different in structure or style.
/* block component */
.block {
}
/* element */
.block__element {
}
/* modifier */
.block__element--modifier {
}
Here is an example with the class names on markup:
<nav class="navbar">
<a href="/" class="navbar__link navbar__link--active"></a>
<a href="/" class="navbar__link"></a>
<a href="/" class="navbar__link"></a>
</nav>
In this case, navbar
is the Block, navbar__link
is an Element that makes no sense outside of the navbar
component, and navbar__link--active
is a Modifier that indicates a different state for the navbar__link
Element.
Since Modifiers are verbose, many opt to use is-*
flags instead as modifiers.
<a href="/" class="navbar__link is-active"></a>
These must be chained to the Element and never alone however, or there will be scope issues.
.navbar__link.is-active {
}
Good to hear
- Alternative solutions to scope issues like CSS-in-JS
Additional links
What are the advantages of using CSS preprocessors?
View answer
CSS preprocessors add useful functionality that native CSS does not have, and generally make CSS neater and more maintainable by enabling DRY (Don't Repeat Yourself) principles. Their terse syntax for nested selectors cuts down on repeated code. They provide variables for consistent theming (however, CSS variables have largely replaced this functionality) and additional tools like color functions (lighten
, darken
, transparentize
, etc), mixins, and loops that make CSS more like a real programming language and gives the developer more power to generate complex CSS.
Good to hear
- They allow us to write more maintainable and scalable CSS
- Some disadvantages of using CSS preprocessors (setup, re-compilation time can be slow etc.)
Additional links
col-{n} / 12
ratio of the container.
Using flexbox, create a 3-column layout where each column takes up a <div class="row">
<div class="col-2"></div>
<div class="col-7"></div>
<div class="col-3"></div>
</div>
View answer
Set the .row
parent to display: flex;
and use the flex
shorthand property to give the column classes a flex-grow
value that corresponds to its ratio value.
.row {
display: flex;
}
.col-2 {
flex: 2;
}
.col-7 {
flex: 7;
}
.col-3 {
flex: 3;
}
Good to hear
Additional links
@media
properties?
Can you name the four types of View answer
all
, which applies to all media type devicesprint
, which only applies to printersscreen
, which only applies to screens (desktops, tablets, mobile etc.)speech
, which only applies to screenreaders
Good to hear
Additional links
What are the advantages of using CSS sprites and how are they utilized?
View answer
CSS sprites combine multiple images into one image, limiting the number of HTTP requests a browser has to make, thus improving load times. Even under the new HTTP/2 protocol, this remains true.
Under HTTP/1.1, at most one request is allowed per TCP connection. With HTTP/1.1, modern browsers open multiple parallel connections (between 2 to 8) but it is limited. With HTTP/2, all requests between the browser and the server are multiplexed on a single TCP connection. This means the cost of opening and closing multiple connections is mitigated, resulting in a better usage of the TCP connection and limits the impact of latency between the client and server. It could then become possible to load tens of images in parallel on the same TCP connection.
However, according to benchmark results, although HTTP/2 offers 50% improvement over HTTP/1.1, in most cases the sprite set is still faster to load than individual images.
To utilize a spritesheet in CSS, one would use certain properties, such as background-image
, background-position
and background-size
to ultimately alter the background
of an element.
Good to hear
background-image
,background-position
andbackground-size
can be used to utilize a spritesheet.
Additional links
Can you describe how CSS specificity works?
View answer
Assuming the browser has already determined the set of rules for an element, each rule is assigned a matrix of values, which correspond to the following from highest to lowest specificity:
- Inline rules (binary - 1 or 0)
- Number of id selectors
- Number of class, pseudo-class and attribute selectors
- Number of tags and pseudo-element selectors
When two selectors are compared, the comparison is made on a per-column basis (e.g. an id selector will always be higher than any amount of class selectors, as ids have higher specificity than classes). In cases of equal specificity between multiple rules, the rules that comes last in the page's style sheet is deemed more specific and therefore applied to the element.
Good to hear
- Specificity matrix: [inline, id, class/pseudo-class/attribute, tag/pseudo-element]
- In cases of equal specificity, last rule is applied
Additional links
What is a focus ring? What is the correct solution to handle them?
View answer
A focus ring is a visible outline given to focusable elements such as buttons and anchor tags. It varies depending on the vendor, but generally it appears as a blue outline around the element to indicate it is currently focused.
In the past, many people specified outline: 0;
on the element to remove the focus ring. However, this causes accessibility issues for keyboard users because the focus state may not be clear. When not specified though, it causes an unappealing blue ring to appear around an element.
In recent times, frameworks like Bootstrap have opted to use a more appealing box-shadow
outline to replace the default focus ring. However, this is still not ideal for mouse users.
The best solution is an upcoming pseudo-selector :focus-visible
which can be polyfilled today with JavaScript. It will only show a focus ring if the user is using a keyboard and leave it hidden for mouse users. This keeps both aesthetics for mouse use and accessibility for keyboard use.
Good to hear
Additional links
Node
NodeJS uses a callback pattern in many instances where if an error were returned it will pass it as the first argument to the callback. What are the advantages of this pattern?
fs.readFile(filePath, function(err, data) {
if (err) {
// handle the error, the return is important here
// so execution stops here
return console.log(err)
}
// use the data object
console.log(data)
})
View answer
Advantages include:
- Not needing to process data if there is no need to even reference it
- Having a consistent API leads to more adoption
- Ability to easily adapt a callback pattern that will lead to more maintainable code
As you can see from below example, the callback is called with null as its first argument if there is no error. However, if there is an error, you create an Error object, which then becomes the callback's only parameter. The callback function allows a user to easily know whether or not an error occurred.
This practice is also called the Node.js error convention, and this kind of callback implementations are called error-first callbacks.
var isTrue = function(value, callback) {
if (value === true) {
callback(null, "Value was true.")
} else {
callback(new Error("Value is not true!"))
}
}
var callback = function(error, retval) {
if (error) {
console.log(error)
return
}
console.log(retval)
}
isTrue(false, callback)
isTrue(true, callback)
/*
{ stack: [Getter/Setter],
arguments: undefined,
type: undefined,
message: 'Value is not true!' }
Value was true.
*/
Good to hear
- This is just a convention. However, you should stick to it.
Additional links
How can you avoid callback hells?
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
getMoreData(c, function(d) {
getMoreData(d, function(e) {
// ...
})
})
})
})
})
View answer
Refactoring the functions to return promises and using async/await
is usually the best option. Instead of supplying the functions with callbacks that cause deep nesting, they return a promise that can be await
ed and will be resolved once the data has arrived, allowing the next line of code to be evaluated in a sync-like fashion.
The above code can be restructured like so:
async function asyncAwaitVersion() {
const a = await getData()
const b = await getMoreData(a)
const c = await getMoreData(b)
const d = await getMoreData(c)
const e = await getMoreData(e)
// ...
}
There are lots of ways to solve the issue of callback hells:
- Modularization: break callbacks into independent functions
- Use a control flow library, like async
- Use generators with Promises
- Use async/await (from v7 on)
Good to hear
- As an efficient JavaScript developer, you have to avoid the constantly growing indentation level, produce clean and readable code and be able to handle complex flows.
Additional links
What is the event loop in Node.js?
View answer
The event loop handles all async callbacks. Callbacks are queued in a loop, while other code runs, and will run one by one when the response for each one has been received.
Good to hear
- The event loop allows Node.js to perform non-blocking I/O operations, despite the fact that JavaScript is single-threaded
Additional links
License
MIT. Copyright (c) Stefan Feješ.