What is JavaScript and what is it used for?
JavaScript is a programming language that is commonly used to add interactivity and dynamic content to websites. It is typically used in conjunction with HTML and CSS to create web pages that are more interactive and engaging for users.
What is the difference between let and var?
The let
keyword is used to declare a block-scoped variable, while the var
keyword is used to declare a function-scoped variable. This means that a variable declared with let
is only accessible within the block that it is declared in, while a variable declared with var
is accessible within the entire function in which it is declared.
// let example
{
let x = 5;
console.log(x); // prints 5
}
console.log(x); // ReferenceError: x is not defined
// var example
{
var y = 5;
console.log(y); // prints 5
}
console.log(y); // prints 5
Can you explain the difference between null and undefined?
The let
keyword is used to declare a block-scoped variable, while the var
keyword is used to declare a function-scoped variable. This means that a variable declared with let
is only accessible within the block that it is declared in, while a variable declared with var
is accessible within the entire function in which it is declared.
let x;
console.log(x); // prints undefined
let y = null;
console.log(y); // prints null
What is a closure and how/why are they used?
A closure is a function that retains access to the variables in its lexical scope even when the function is executed outside of that scope. This allows the function to access those variables even if they are no longer in the same scope. Closures are commonly used to create private variables or to create functions with a specific context.
function createAdder(x) {
return function(y) {
return x + y;
}
}
let add5 = createAdder(5);
console.log(add5(3)); // prints 8
Can you describe the difference between classical inheritance and prototypal inheritance?
Classical inheritance involves creating classes that inherit from other classes, while prototypal inheritance involves creating objects that inherit from other objects. In classical inheritance, classes are defined using the class
keyword and inherit using the extends
keyword, while in prototypal inheritance, objects are created using the Object.create()
method and inherit using the prototype chain.
// classical inheritance example
class Shape {
constructor(color) {
this.color = color;
}
getColor() {
return this.color;
}
}
class Circle extends Shape {
constructor(color, radius) {
super(color);
this.radius = radius;
}
getArea() {
return Math.PI * this.radius ** 2;
}
}
let circle = new Circle('red', 5);
console.log(circle.getArea()); // prints 78.53981633974483
// prototypal inheritance example
let shape = {
color: 'blue',
getColor: function() {
return this.color;
}
};
let circle = Object.create(shape, {
radius: {
value: 5
},
getArea: {
value: function() {
return Math.PI * this.radius ** 2;
}
}
});
console.log(circle.getArea()); // prints 78.53981633974483
What is the event loop and how does it work?
The event loop is a mechanism that allows JavaScript to execute asynchronous code in a synchronous manner. It does this by adding asynchronous tasks to a queue and processing them one at a time in the order in which they were added. This ensures that asynchronous tasks are executed in the correct order and allows JavaScript to avoid being blocked by long-running tasks.
console.log('start');
setTimeout(() => {
console.log('setTimeout 1');
}, 0);
setTimeout(() => {
console.log('setTimeout 2');
}, 0);
console.log('end');
// the above code will print:
// start
// end
// setTimeout 1
// setTimeout 2
Can you describe the difference between synchronous and asynchronous code?
Synchronous code is executed in the order in which it is written, while asynchronous code is executed at a later time. Synchronous code blocks the execution of subsequent code until it has finished, while asynchronous code does not block the execution of subsequent code and allows it to continue while the asynchronous operation is being performed.
console.log('start');
// synchronous code
let result = 1 + 2;
console.log(result); // prints 3
// asynchronous code
setTimeout(() => {
console.log('setTimeout 1');
}, 0);
console.log('end');
// the above code will print:
// start
// 3
// end
// setTimeout 1
What is a promise and how is it used?
A promise is a placeholder for a value that may not be available yet. It allows you to write asynchronous code that looks like synchronous code by representing the future value that the asynchronous operation will produce. Promises can be in one of three states: pending, fulfilled, or rejected. Once a promise is fulfilled or rejected, it cannot change its state.
Promises are commonly used with asynchronous operations such as network requests or reading from a file. They allow you to handle the results of the asynchronous operation in a more elegant and concise way than using callback functions.
// example using a promise
function delay(ms) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, ms);
});
}
console.log('start');
delay(1000)
.then(() => {
console.log('delay 1');
return delay(500);
})
.then(() => {
console.log('delay 2');
});
console.log('end');
// the above code will print:
// start
// end
// delay 1
// delay 2
Can you explain how “this” works in JavaScript?
The this
keyword refers to the current object that the code is being executed in. Its value is determined by how the function is called. If the function is called as a method of an object, this
will be set to the object. If the function is called as a standalone function, this
will be set to the global object (in non-strict mode) or to undefined
(in strict mode).
let obj = {
x: 5,
getX: function() {
return this.x;
}
};
console.log(obj.getX()); // prints 5
let getX = obj.getX;
console.log(getX()); // prints undefined (this is the global object)
What is a pure function and why are they important?
A pure function is a function that always returns the same output for the same input, and has no side effects. This means that the function does not modify any external state and only depends on its input parameters. Pure functions are important because they are predictable and easy to test, and they allow for easier reasoning about code.
// example of a pure function
function add(x, y) {
return x + y;
}
console.log(add(1, 2)); // prints 3
console.log(add(1, 2)); // prints 3
// example of an impure function
let z = 0;
function add(x, y) {
z = x + y;
return z;
}
console.log(add(1, 2)); // prints 3
console.log(add(1, 2)); // prints 3
console.log(z); // prints 2 (z was changed by the previous call to add)
Can you explain how prototypal inheritance works in JavaScript?
In JavaScript, objects can inherit from other objects, rather than classes inheriting from classes like in classical inheritance. This is known as prototypal inheritance. To create an object that inherits from another object, the Object.create()
method is used, which takes the object to inherit from as an argument. The new object then has access to the methods and properties of the object it inherited from.
let animal = {
speak() {
console.log('animal speaking');
}
};
let dog = Object.create(animal);
dog.bark = function() {
console.log('bark bark');
};
dog.speak(); // prints 'animal speaking'
dog.bark(); // prints 'bark bark'
What is a higher-order function and why are they useful?
A higher-order function is a function that takes one or more functions as arguments, or returns a function as its output. This allows you to abstract common patterns and uses them in different situations. Higher-order functions are useful because they enable code reuse and make your code more modular and easier to read.
// example of a higher-order function
function add(x, y) {
return x + y;
}
function multiply(x, y) {
return x * y;
}
function operate(operator, x, y) {
return operator(x, y);
}
console.log(operate(add, 1, 2)); // prints 3
console.log(operate(multiply, 1, 2)); // prints 2
Can you describe the difference between == and ===?
The ==
operator is the equality operator, which compares the values of two operands for equality. The ===
operator is the strict equality operator, which compares the values and the types of the operands for equality. This means that ===
will only return true if the operands have the same value and are of the same type, while ==
will perform type coercion to try to compare the operands as equal.
console.log(1 == '1'); // prints true (1 and '1' are considered equal after type coercion)
console.log(1 === '1'); // prints false (1 and '1' are not the same type, so they are not considered equal)
What is a curry function and how is it used?
A curry function is a function that takes multiple arguments and returns a new function that takes the remaining arguments. This allows you to create a new function with some of the arguments already fixed, making it easier to reuse the function in different contexts.
// example of a curried function
function add(x) {
return function(y) {
return x + y;
}
}
let add5 = add(5);
console.log(add5(3)); // prints 8
Can you explain the difference between a static and non-static method?
A static method is a method that is associated with a class, rather than with an instance of the class. This means that static methods can be called on the class itself, rather than on an instance of the class. Non-static methods, on the other hand, are associated with instances of the class and can only be called on an instance of the class.
// example of static and non-static methods
class Counter {
static nextId = 0;
constructor() {
this.id = Counter.nextId++;
}
static getNextId() {
return Counter.nextId;
}
getId() {
return this.id;
}
}
let c1 = new Counter();
let c2 = new Counter();
console.log(Counter.getNextId()); // prints 2
console.log(c1.getId()); // prints 0
console.log(c2.getId()); // prints 1
What are the benefits of using functional programming techniques in JavaScript?
Functional programming is a programming paradigm that emphasizes the use of functions to manipulate data and avoid mutable state. Some benefits of using functional programming techniques in JavaScript include:
- easier reasoning about code
- improved code reusability
- increased code readability
- reduced likelihood of bugs due to the avoidance of mutable state
- easier parallelization and concurrency due to the lack of shared state
Can you describe the difference between a map and a reduce function?
The map
function is used to apply a transformation to each element of an array and return a new array with the transformed elements. The reduce
function is used to reduce an array to a single value by iteratively combining elements of the array using a provided function.
let numbers = [1, 2, 3, 4, 5];
// using map to transform the array
let doubled = numbers.map(n => n * 2);
console.log(doubled); // prints [2, 4, 6, 8, 10]
// using reduce to combine the array
let sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // prints 15
What is a WeakMap and why is it used?
A WeakMap is a collection of key-value pairs, similar to a Map, but the keys are weakly referenced. This means that the keys can be garbage collected if there are no other references to them. WeakMaps are used to store data associated with an object that should not prevent the object from being garbage collected.
let obj1 = { x: 5 };
let obj2 = { y: 6 };
let map = new WeakMap();
map.set(obj1, 'value for obj1');
map.set(obj2, 'value for obj2');
console.log(map.get(obj1)); // prints 'value for obj1'
console.log(map.get(obj2)); // prints 'value for obj2'
// once there are no other references to obj1, it can be garbage collected
obj1 = null;
console.log(map.has(obj1)); // prints false
Can you explain the difference between rest and spread syntax?
The rest syntax (...
) is used to represent an indefinite number of arguments as an array. It is commonly used in function definitions to represent an indefinite number of arguments.
// example of rest syntax
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // prints 15
// example of spread syntax
let numbers = [1, 2, 3, 4, 5];
console.log(sum(...numbers)); // prints 15
What is a generator function and how is it used?
A generator function is a function that can be paused and resumed, allowing it to produce a sequence of values. Generator functions are denoted by the *
symbol after the function keyword, and they use the yield
keyword to produce a value and pause the function. Generator functions can be resumed by calling the next()
method on the generator object, which returns an object with the value produced by the yield
expression and a done
property indicating whether the generator has been completed.
// example of a generator function
function* generateNumbers() {
let i = 0;
while (true) {
yield i++;
}
}
let generator = generateNumbers();
console.log(generator.next().value); // prints 0
console.log(generator.next().value); // prints 1
console.log(generator.next().value); // prints 2