This study guide focuses on commonly discussed, yet powerful features of JavaScript. Understanding these can showcase a deeper grasp of the language during technical and improve code elegance and efficiency. These features area frequently explored in interviews with companies like Netflix, Airbnb, and Stripe, often presented as coding challenges or conceptual questions.
JavaScript, despite being a widely used language, contains several "hidden gems" – features that aren't always immediately obvious or frequently utilized by developers. These include concepts like prototypal inheritance nuances, the workings of closures in greater detail, advanced array methods, the power of Symbols, and clever uses of destructuring and the spread operator. Mastering these techniques demonstrates a strong understanding of JavaScript’s core principles and ability to write more robust and maintainable code. This guide targets an intermediate level, assuming familiarity with basic JavaScript syntax and core concepts.
Object.getPrototypeOf(obj) returns the prototype of an object.obj.hasOwnProperty(prop) checks if a property is defined directly on the object, not inherited.__proto__ (though its use is generally discouraged in favor of Object.getPrototypeOf) is helpful.function Animal(name) { this.name = name; } Animal.prototype.sayHello = function() { console.log(`Hello, my name is ${this.name}`); }; function Dog(name, breed) { Animal.call(this, name); // Call the Animal constructor to set the name this.breed = breed; } Dog.prototype = Object.create(Animal.prototype); // Set up the prototype chain Dog.prototype.constructor = Dog; // Reset the constructor to Dog Dog.prototype.bark = function() { console.log("Woof!"); }; const myDog = new Dog("Buddy", "Golden Retriever"); myDog.sayHello(); // Output: Hello, my name is Buddy myDog.bark(); // Output: Woof! console.log(myDog.hasOwnProperty('name')); // true console.log(myDog.hasOwnProperty('breed')); // true console.log(myDog.hasOwnProperty('sayHello')); // false (inherited)
function outerFunction(outerVar) { function innerFunction(innerVar) { console.log(`Outer variable: ${outerVar}, Inner variable: ${innerVar}`); } return innerFunction; } const myClosure = outerFunction("Hello"); myClosure("World"); // Output: Outer variable: Hello, Inner variable: World
Symbols are primitive values that are guaranteed to be unique. They provide a way to create private properties on objects.Symbols are often used as keys for object properties to avoid naming collisions.Symbol keys are not enumerable by default.Symbol.for() creates a global, shared Symbol. Symbol.keyFor() retrieves the key associated with a global Symbol.const mySymbol = Symbol('myKey'); const obj = { [mySymbol]: 'myValue', name: 'John' }; console.log(obj[mySymbol]); // Output: myValue console.log(obj.name); // Output: John for (let key in obj) { console.log(key); // Output: name (Symbol key is not enumerable) }
forEach, map, and filter. These offer concise and efficient ways to manipulate arrays.reduce(): Applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.reduceRight(): Same as reduce(), but iterates from right to left.find(): Returns the first element in the array that satisfies a provided testing function.findIndex(): Returns the index of the first element in the array that satisfies a provided testing function.includes(): Checks if an array contains a specified element.const numbers = [1, 2, 3, 4, 5]; const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0); //Output: 15 const firstEven = numbers.find(number => number % 2 === 0); // Output: 2 const indexOfThree = numbers.findIndex(number => number === 3); // Output: 2
Explain the difference between null and undefined in JavaScript.
undefined means a variable has been declared but hasn't been assigned a value. null is an assignment value that represents the intentional absence of any object value. Understanding how they are treated in comparisons (e.g. null == undefined is true, but null === undefined is false) is key.What is a closure? Give an example of how it can be used to create data privacy.
How does prototypal inheritance work in JavaScript? What are its advantages and disadvantages compared to class-based inheritance?
What are Symbols, and what problem do they solve?
Describe the reduce() method. When would you use it, and what are its potential use cases?
reduce() is used when you need to consolidate an array into a single value. Use cases include summing numbers, flattening arrays, grouping objects, and calculating complex statistics.What’s the difference between == and === in JavaScript? Why is it generally recommended to use ===?
== performs type coercion before comparison, while === checks for both value and type equality without coercion. === is recommended because it avoids unexpected behavior due to type coercion, leading to more predictable code.Explain the purpose of the spread operator (...). Provide examples of its usage.
const arr1 = [1, 2, 3]; const arr2 = [...arr1, 4, 5]; // Concatenate arrays console.log(arr2); // Output: [1, 2, 3, 4, 5] function sum(a, b, c) { return a + b + c; } const nums = [1, 2, 3]; const result = sum(...nums); // Pass array elements as arguments console.log(result); // Output: 6
How can you prevent accidental modifications to an object's properties?
Object.freeze() prevents new properties from being added, existing properties from being removed, and values of existing properties from being changed. Symbols also contribute to better isolation.function createCounter() { let count = 0; // Private variable return { increment: function() { count++; }, decrement: function() { count--; }, getValue: function() { return count; } }; } const counter = createCounter(); counter.increment(); counter.increment(); console.log(counter.getValue()); // Output: 2 //Attempting to directly modify count will fail: //counter.count = 10; // will not affect the true value. console.log(counter.getValue()); // Output: 2
This demonstrates data encapsulation. The count variable is not directly accessible from outside the createCounter function, ensuring its integrity.
const COMPONENT_KEY = Symbol('componentKey'); function createComponent(name) { return { [COMPONENT_KEY]: name, render: function() { console.log(`Rendering component: ${this[COMPONENT_KEY]}`); } }; } const myComponent = createComponent('MyButton'); myComponent.render(); // Output: Rendering component: MyButton console.log(myComponent[COMPONENT_KEY]); // Output: MyButton
This example shows how Symbols can guarantee unique property names, avoiding conflicts when creating reusable components.
(Easy) Create a function called every that mimics the behavior of the Array.every() method, but without using the built-in every() method.
function every(arr, callback) { // Your code here }
Hint: You'll need to iterate through the array and check if the callback returns false for any element. If it does, immediately return false.
(Intermediate) Write a function that takes an object and a Symbol as arguments and adds a new property to the object using the Symbol as the key.
function addSymbolProperty(obj, symbol) { // Your code here }
Hint: Use bracket notation to assign a value to a property with a Symbol key.
(Intermediate) Implement a function that uses reduce to group an array of objects by a specified key.
function groupBy(arr, key) { // Your Code Here }
Hint: The initial value for reduce should be an empty object {}. The callback function should build up the result object by adding properties based on the key.
reduce, find, and includes can significantly simplify array operations.Do you want to:
reduce examples, a deeper dive into Symbol's use cases)Start a new session to explore different topics or increase the difficulty level.
Start New Session