Chapter 34 of 34
Top 193 JavaScript Interview Questions
A rapid-fire reference covering the questions most likely to come up in a real interview - organized by topic and difficulty, with explanations that go beyond a one-line definition and a runnable code example for each one, so the concept sticks. Search or filter to find what you need, and share a direct link to any question.
Showing 193 of 193 questions
The first 15 of 193 questions are free to read. Sign up free to unlock every answer and track your progress.
Unlock all 193In JavaScript, data types can be categorized into primitive and non-primitive types. Primitive data types: Number (represents both integers and floating-point numbers), String (represents sequences of characters), Boolean (represents true or false values), Undefined (a variable that has been declared but not assigned a value), Null (represents the intentional absence of any object value), Symbol (a unique and immutable value used as object property keys), BigInt (represents integers with arbitrary precision). Non-primitive (reference) data types: Object (used to store collections of data), Array (an ordered collection of data), Function (a callable object), Date (represents dates and times), RegExp (represents regular expressions), Map (a collection of keyed data items), Set (a collection of unique values). The primitive types store a single value, while non-primitive types can store collections of data or complex entities.
To check the data type of a variable in JavaScript, you can use the typeof operator. For example, typeof variableName will return a string indicating the type of the variable, such as "string", "number", "boolean", "object", "function", "undefined", or "symbol". For arrays and null, you can use Array.isArray(variableName) and variableName === null, respectively.
Comparing null, undefined, and an undeclared variable across meaning, type, and equality comparison: Meaning - null is explicitly set by the developer to indicate that a variable has no value; undefined means a variable has been declared but not assigned a value; an undeclared variable has not been declared at all. Type (via the typeof operator) - typeof null returns 'object'; typeof undefined returns 'undefined'; typeof on an undeclared variable also returns 'undefined'. Equality comparison - null == undefined is true, and undefined == null is true, but referencing an undeclared variable throws a ReferenceError.
In JavaScript, let, var, and const are all keywords used to declare variables, but they differ significantly in terms of scope, initialization rules, whether they can be redeclared or reassigned, and the behavior when they are accessed before declaration. Comparing var, let, and const: Scope - var is function or global scoped, while let and const are block scoped. Initialization - var and let initialization is optional, while const requires an initial value. Redeclaration - var can be redeclared, but let and const cannot. Reassignment - var and let can be reassigned, but const cannot. Accessing before declaration - var yields undefined, while both let and const throw a ReferenceError.
JavaScript that is executed in the browser has access to the global scope (the window object). In general it's a good software engineering practice to not pollute the global namespace unless you are working on a feature that truly needs to be global - it is needed by the entire page. Several reasons to avoid touching the global scope: naming conflicts (sharing the global scope across scripts can cause conflicts and bugs when new global variables or changes are introduced); a cluttered global namespace (keeping the global namespace minimal avoids making the codebase hard to manage and maintain); scope leaks (unintentional references to global variables in closures or event handlers can cause memory leaks and performance issues); modularity and encapsulation (good design promotes keeping variables and functions within their specific scopes, enhancing organization, reusability, and maintainability); security concerns (global variables are accessible by all scripts, including potentially malicious ones, posing security risks, especially if sensitive data is stored there); and compatibility and portability (heavy reliance on global variables reduces code portability and integration ease with other libraries or frameworks). Best practices to avoid global scope pollution include: using local variables (declare variables within functions or blocks using var, let, or const to limit their scope); passing variables as function parameters (maintain encapsulation by passing variables as parameters instead of accessing them globally); using immediately invoked function expressions - IIFEs (create new scopes with IIFEs to prevent adding variables to the global scope); and using modules (encapsulate code with module systems to maintain separate scopes and manageability).
In JavaScript, you can convert a string to a number using several methods. The most common ones are Number(), parseInt(), parseFloat(), and the unary plus operator (+). For example, Number("123") converts the string "123" to the number 123, and parseInt("123.45") converts the string "123.45" to the integer 123.
Template literals are a feature in JavaScript that allow for easier string interpolation and multi-line strings. They are enclosed by backticks (`) instead of single or double quotes. You can embed expressions within template literals using ${expression} syntax.
Example
const myName = 'John';
const greeting = `Hello, ${myName}!`;
console.log(greeting); // Output: Hello, John!Tagged templates in JavaScript allow you to parse template literals with a function. The function receives the literal strings and the values as arguments, enabling custom processing of the template.
Example
function tag(strings, ...values) {
return strings[0] + values[0] + strings[1] + values[1] + strings[2];
}
const result = tag`Hello ${'world'}! How are ${'you'}?`;
console.log(result); // "Hello world! How are you?"The spread operator, represented by three dots (...), is used in JavaScript to expand iterable objects like arrays or strings into individual elements. It can also be used to spread object properties. For example, you can use it to combine arrays, copy arrays, or pass array elements as arguments to a function.
Example
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const combinedObj = { ...obj1, ...obj2 };
console.log(combinedObj); // { a: 1, b: 2, c: 3, d: 4 }Symbols in JavaScript are a new primitive data type introduced in ES6 (ECMAScript 2015). They are unique and immutable identifiers used primarily for object property keys to avoid name collisions. These values can be created using the Symbol(...) function, and each Symbol value is guaranteed to be unique, even if they have the same key or description. Symbol properties are not enumerable in for...in loops or Object.keys(), making them suitable for creating private or internal object state. Note: the Symbol() function must be called without the new keyword - it is not exactly a constructor because it can only be called as a function instead of with new Symbol().
Example
let sym1 = Symbol();
let sym2 = Symbol('myKey');
console.log(typeof sym1); // "symbol"
console.log(sym1 === sym2); // false, because each symbol is unique
let obj = {};
let sym = Symbol('uniqueKey');
obj[sym] = 'value';
console.log(obj[sym]); // "value"In JavaScript, a proxy is an object that acts as an intermediary between an object and the code. Proxies are used to intercept and customize the fundamental operations of JavaScript objects, such as property access, assignment, function invocation, and more. Use cases include: property access interception (intercept and customize property access on an object), with sub-cases such as property assignment validation (validate property values before they are set on the target object), logging and debugging (create wrappers for logging and debugging interactions with an object), creating reactive systems (trigger updates in other parts of your application when object properties change, as in data binding), data transformation (transforming data being set or retrieved from an object), and mocking and stubbing in tests (create mock or stub objects for testing purposes, allowing you to isolate dependencies and focus on the unit under test); function invocation interception (used to cache and return the result of frequently accessed methods if they involve network calls or computationally intensive logic, improving performance); and dynamic property creation (useful for defining properties on-the-fly with default values and avoiding storing redundant data in objects).
Example
const myObject = {
name: 'John',
age: 42,
};
const handler = {
get: function (target, prop, receiver) {
console.log(`Someone accessed property "${prop}"`);
return target[prop];
},
};
const proxiedObject = new Proxy(myObject, handler);
console.log(proxiedObject.name);
// Someone accessed property "name"
// 'John'
console.log(proxiedObject.age);
// Someone accessed property "age"
// 42Hoisting is a JavaScript mechanism where variable and function declarations are moved ("hoisted") to the top of their containing scope during the compile phase. Variable declarations (var) - declarations are hoisted, but not initializations; the value of the variable is undefined if accessed before initialization. Variable declarations (let and const) - declarations are hoisted, but not initialized; accessing them results in a ReferenceError until the actual declaration is encountered. Function expressions assigned to var - declarations are hoisted, but not initializations; the value is undefined if accessed before initialization. Function declarations (function) - both the declaration and definition are fully hoisted. Class declarations (class) - declarations are hoisted, but not initialized; accessing them results in a ReferenceError until the actual declaration is encountered. Import declarations (import) - declarations are hoisted, and the side effects of importing the module are executed before the rest of the code. Summary of accessing before declaration: var foo results in undefined; let foo throws a ReferenceError; const foo throws a ReferenceError; class Foo throws a ReferenceError; var foo = function() {...} results in undefined; function foo() {...} works normally; and import works normally.
var declarations are hoisted to the top of their scope and initialized with undefined, allowing them to be used before their declaration. let and const declarations are also hoisted but are not initialized, resulting in a ReferenceError if accessed before their declaration. const additionally requires an initial value at the time of declaration.
Hoisting in JavaScript means that function declarations are moved to the top of their containing scope during the compile phase, making them available throughout the entire scope. This allows you to call a function before it is defined in the code. However, function expressions are not hoisted in the same way. If you try to call a function expression before it is defined, you will get an error because the variable holding the function is hoisted but not its assignment.
Example
// Function declaration
console.log(foo()); // Works fine
function foo() {
return 'Hello';
}
// Function expression
console.log(bar()); // Throws TypeError: bar is not a function
var bar = function () {
return 'Hello';
};Hoisting can lead to unexpected behavior in JavaScript because variable and function declarations are moved to the top of their containing scope during the compilation phase. This can result in undefined values for variables if they are used before their declaration and can cause confusion with function declarations and expressions.
Example
console.log(a); // undefined
var a = 5;
console.log(b);
// ReferenceError: Cannot access 'b' before initialization
let b = 10;