All javascript prep guide
JavaScript is a dynamically typed language, which means that variables can hold values of any data type without explicitly specifying the data type. However, JavaScript has several built-in data types that can be broadly categorized into two main groups: primitive data types and object data types.
-
Number:
- Represents numeric values.
let num = 42;
-
String:
- Represents textual data.
let text = "Hello, World!";
-
Boolean:
- Represents either
true
orfalse
.
let isTrue = true;
- Represents either
-
Undefined:
- Represents the absence of a value or an uninitialized variable.
let undefinedVar;
-
Null:
- Represents the intentional absence of any object value.
let nullVar = null;
-
Symbol:
- Introduced in ECMAScript 6, symbols are unique and immutable primitive values.
let sym = Symbol("uniqueSymbol");
-
Object:
- Represents a collection of key-value pairs.
let person = { name: "John", age: 30 };
-
Array:
- Represents an ordered list of values.
let numbers = [1, 2, 3, 4, 5];
-
Function:
- Represents a reusable block of code.
function add(a, b) { return a + b; }
-
Date:
- Represents a date and time.
let currentDate = new Date();
-
RegExp:
- Represents a regular expression for pattern matching.
let pattern = /[0-9]+/;
Symbols in JavaScript are unique and immutable primitive values. They were introduced in ECMAScript 6 (ES6) to provide a way to create unique identifiers. Symbols are often used in scenarios where unique property keys are required. Here are some common use cases for symbols:
-
Object Property Keys: Symbols can be used as unique keys for object properties. Since symbols are guaranteed to be unique, they help prevent naming conflicts in objects.
const uniqueKey = Symbol("uniqueKey"); let obj = {}; obj[uniqueKey] = "Some value"; console.log(obj[uniqueKey]); // "Some value"
-
Private Object Properties: Symbols are often used to create private properties in JavaScript objects. By using a symbol as a key, you can make it less likely that these properties will be accidentally accessed or modified from outside the object.
const privateProperty = Symbol("privateProperty"); class MyClass { constructor() { this[privateProperty] = "This is private"; } getPrivateProperty() { return this[privateProperty]; } } let instance = new MyClass(); console.log(instance.getPrivateProperty()); // "This is private"
-
Enum-Like Behavior: Symbols can be used to create enum-like behavior, where each symbol represents a unique value. This is especially useful when defining constants with unique identifiers.
const Colors = { RED: Symbol("RED"), GREEN: Symbol("GREEN"), BLUE: Symbol("BLUE") }; let selectedColor = Colors.RED;
-
Avoiding Name Collisions: Symbols are useful in scenarios where you want to create extensions or plugins, and you need to ensure that the names or keys you introduce don't clash with existing properties.
const pluginSymbol = Symbol("pluginSymbol"); class MyLibrary { [pluginSymbol]() { // Plugin functionality } }
Keep in mind that symbols are not enumerable in for...in
loops, and they won't be included in Object.keys()
or Object.getOwnPropertyNames()
. This makes them suitable for scenarios where you want to hide certain properties or create unique identifiers without the risk of unintended interference.
Sure, let's delve into strings in JavaScript and explore some potential interview questions related to strings.
A string in JavaScript is a sequence of characters enclosed within single ('
) or double ("
) quotes. Strings are immutable, meaning that once a string is created, it cannot be changed. However, you can create new strings based on existing ones.
-
String Concatenation:
let str1 = "Hello"; let str2 = "World"; let result = str1 + " " + str2; // "Hello World"
-
String Length:
let str = "JavaScript"; let length = str.length; // 10
-
Accessing Characters:
let str = "Example"; let firstChar = str[0]; // "E"
-
Substring:
let str = "Hello World"; let substr = str.substring(0, 5); // "Hello"
-
String Methods:
let str = " Trim me "; let trimmed = str.trim(); // "Trim me"
-
What is the difference between
==
and===
when comparing strings?==
performs type coercion, attempting to convert the operands to the same type before making the comparison.===
(strict equality) checks both value and type without coercion.
"5" == 5 // true (coercion) "5" === 5 // false (strict equality)
-
How can you reverse a string in JavaScript?
let str = "Hello"; let reversed = str.split("").reverse().join(""); // "olleH"
-
Explain the difference between
charAt
and bracket notation for accessing characters.charAt(index)
returns the character at the specified index.- Bracket notation
str[index]
is more commonly used and achieves the same result.
let str = "Example"; str.charAt(0); // "E" str[0]; // "E"
-
What is the purpose of the
trim
method, and when might you use it?- The
trim
method removes whitespace from both ends of a string. - It's useful when dealing with user input to clean up leading and trailing spaces.
- The
-
How can you check if a string contains a specific substring?
- You can use the
includes
method orindexOf
.
let str = "Hello World"; str.includes("Hello"); // true str.indexOf("Hello") !== -1; // true
- You can use the
-
Explain the concept of string immutability in JavaScript.
- Once a string is created, its value cannot be changed.
- Operations on strings (concatenation, substring, etc.) return new strings without modifying the original.
-
What is a template literal, and how does it differ from regular string concatenation?
- Template literals use backticks (
) and allow embedding expressions inside
${}`. - They provide a cleaner syntax and support multiline strings.
let name = "John"; let greeting = `Hello, ${name}!`;
- Template literals use backticks (
-
How can you convert a string to uppercase or lowercase?
let str = "Hello"; let upper = str.toUpperCase(); // "HELLO" let lower = str.toLowerCase(); // "hello"
- Both methods extract a portion of a string.
slice(start, end)
extracts fromstart
toend-1
. Negative values count from the end.substring(start, end)
is similar but doesn't accept negative indices.
let str = "JavaScript";
str.slice(2, 5); // "vaS"
str.substring(2, 5); // "vaS"
- You can use the
split
method to convert a string into an array of characters.
let str = "Hello";
let charArray = str.split(""); // ["H", "e", "l", "l", "o"]
- The
replace
method is used to replace a specified substring or pattern with another string.
let sentence = "I love JavaScript";
let newSentence = sentence.replace("JavaScript", "Python"); // "I love Python"
- You can convert both strings to lowercase or uppercase using
toLowerCase()
ortoUpperCase()
before comparing.
let str1 = "Hello";
let str2 = "hello";
str1.toLowerCase() === str2.toLowerCase(); // true
- String interpolation involves embedding expressions inside string literals to produce a dynamic string.
let name = "Alice";
let greeting = `Hello, ${name}!`; // "Hello, Alice!"
- You can use the
startsWith
andendsWith
methods.
let str = "Hello, World";
str.startsWith("Hello"); // true
str.endsWith("World"); // true
localeCompare
compares strings based on the current locale and returns a value indicating their order.
let str1 = "apple";
let str2 = "banana";
str1.localeCompare(str2); // -1 (apple comes before banana)
- You can use the
indexOf
method.
let str = "Hello, World";
let index = str.indexOf("o"); // 4
- A regular expression (regex) is a powerful tool for pattern matching in strings.
- You can use the
RegExp
constructor or a regex literal (/pattern/
) to create a regular expression. - Methods like
test
andmatch
can be used for regex operations.
let str = "Hello, World";
let regex = /Hello/;
regex.test(str); // true
String.fromCharCode
converts Unicode values to characters and returns a string.
String.fromCharCode(72, 101, 108, 108, 111); // "Hello"
- Template literals, introduced in ECMAScript 6, use backticks and allow embedded expressions.
let name = "World";
let greeting = `Hello, ${name}!`;
- The
repeat
method allows you to create a new string by repeating the original string a specified number of times.
let str = "abc";
let repeatedStr = str.repeat(3); // "abcabcabc"
- String interpolation in template literals allows you to embed expressions inside
${}
.
let x = 5;
let y = 10;
console.log(`The sum of ${x} and ${y} is ${x + y}.`);
22. How does JavaScript handle strings internally, especially when they are long or contain Unicode characters?
- JavaScript uses UTF-16 encoding to represent characters in strings.
- Strings are sequences of 16-bit code units, but some characters may require more than one code unit.
String.raw
is a method that returns the raw string representation of a template literal, ignoring escape sequences.
String.raw`Line 1\nLine 2`; // "Line 1\\nLine 2"
- The
replace
method can take a regular expression as its first argument for more advanced search and replace operations.
let str = "apple apple apple";
let replacedStr = str.replace(/apple/g, "orange"); // "orange orange orange"
- The
Intl.Collator
object provides language-sensitive string comparison, useful for sorting strings based on locale-specific rules.
let names = ["Ă–mer", "Zara", "Ă„lbert"];
names.sort(new Intl.Collator().compare); // ["Ă„lbert", "Ă–mer", "Zara"]
-
What is an object in JavaScript?
- An object is a collection of key-value pairs where each key is a string (or Symbol) and each value can be any data type.
-
How do you create an object in JavaScript?
- Objects can be created using object literals, the
Object
constructor, or by creating instances of custom constructor functions.
let person = { name: "John", age: 30 };
- Objects can be created using object literals, the
-
What is the difference between dot notation and bracket notation when accessing object properties?
- Dot notation is used with literal property names, while bracket notation allows for dynamic property access using variables or expressions.
let person = { name: "John" }; person.name; // Dot notation person["name"]; // Bracket notation
-
How can you check if an object has a specific property?
- You can use the
hasOwnProperty
method or thein
operator.
let person = { name: "John" }; person.hasOwnProperty("name"); // true "name" in person; // true
- You can use the
-
Explain shallow vs. deep copy of objects. How would you create each?
- Shallow copy creates a new object with the same top-level properties. Deep copy creates a new object and recursively copies all nested objects.
// Shallow copy let shallowCopy = Object.assign({}, originalObject); // Deep copy (using a library like lodash) let deepCopy = _.cloneDeep(originalObject);
-
What is the purpose of the
delete
operator with objects?- The
delete
operator is used to remove a property from an object.
let person = { name: "John", age: 30 }; delete person.age;
- The
-
How can you iterate over the properties of an object?
- You can use
for...in
loop orObject.keys
,Object.values
, orObject.entries
methods.
let person = { name: "John", age: 30 }; for (let key in person) { console.log(key, person[key]); } Object.keys(person).forEach(key => console.log(key, person[key]));
- You can use
-
Explain the concept of prototypal inheritance in JavaScript.
- Prototypal inheritance is a way objects can inherit properties and methods from other objects through their prototype chain.
-
How do you create an object with a specific prototype?
- You can use
Object.create
to create an object with a specified prototype.
let personProto = { greet: function() { console.log("Hello!"); } }; let john = Object.create(personProto);
- You can use
-
What is the role of the
this
keyword in object methods?- The
this
keyword refers to the current instance of the object and is used to access or modify its properties within methods.
let person = { name: "John", greet: function() { console.log(`Hello, my name is ${this.name}.`); } };
- The
-
Explain the difference between
Object.freeze
andconst
in relation to objects.const
prevents the variable reference from being reassigned, but it doesn't make the object immutable.Object.freeze
makes the object itself immutable, preventing changes to its properties.
const person = { name: "John" }; person.age = 30; // Allowed with const Object.freeze(person); person.age = 31; // Not allowed with Object.freeze
-
How does ES6 shorthand syntax simplify object property assignments?
- ES6 introduced shorthand syntax for object property assignments when the property name and variable name are the same.
let name = "John"; let age = 30; // ES6 shorthand let person = { name, age };
- Object destructuring allows you to extract properties from an object and assign them to variables.
```javascript
let person = { name: "John", age: 30 };
let { name, age } = person;
```
- `Object.entries` returns an array of a given object's own enumerable property `[key, value]` pairs.
```javascript
let person = { name: "John", age: 30 };
let entries = Object.entries(person); // [["name", "John"], ["age", 30]]
```
- Setters and getters allow you to define the behavior of assigning and retrieving values for object properties.
```javascript
let person = {
_age: 30,
get age() {
return this._age;
},
set age(newAge) {
if (newAge > 0) {
this._age = newAge;
}
}
};
```
- The rest (`...`) and spread (`...`) operators can be used for gathering/resting and spreading elements in arrays and properties in objects.
```javascript
// Rest operator
let { name, ...rest } = { name: "John", age: 30, country: "USA" };
// Spread operator
let person = { name, ...rest };
```
- You can check the length of `Object.keys(obj)` or use `Object.entries(obj).length === 0`.
```javascript
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
```
- `Object.create` is used to create a new object with the specified prototype object.
```javascript
let personProto = { greet: function() { console.log("Hello!"); } };
let john = Object.create(personProto);
```
- In case of collisions, the most recently added property takes precedence. The order matters when iterating over object properties.
```javascript
let obj = { a: 1, b: 2, a: 3 };
console.log(obj); // { a: 3, b: 2 }
```
- `Object.seal` is used to prevent adding or removing properties, but you can still modify existing ones.
```javascript
let person = { name: "John", age: 30 };
Object.seal(person);
person.age = 31; // Allowed
person.country = "USA"; // Not allowed
```
- Object reflection involves examining or modifying the properties of an existing object.
- Object extension involves adding properties to an object.
- The `instanceof` operator tests if an object's prototype chain includes the prototype property of a constructor.
```javascript
function Dog() {}
let myDog = new Dog();
console.log(myDog instanceof Dog); // true
```
Absolutely! Let's explore some additional advanced interview questions related to JavaScript objects:
Object.getOwnPropertyDescriptors
returns all own property descriptors of a given object, including configurable, enumerable, value, and getter/setter information.
let person = { name: "John" };
let descriptors = Object.getOwnPropertyDescriptors(person);
- Object freezing using
Object.freeze
makes an object immutable, preventing the addition, deletion, or modification of its properties. - Deep freezing involves recursively applying
Object.freeze
to freeze nested objects.
let person = { name: "John", address: { city: "New York" } };
Object.freeze(person);
- Object literals with computed property names allow you to use expressions for property names.
let propName = "age";
let person = { name: "John", [propName]: 30 };
- Prototypal inheritance in JavaScript involves setting the
prototype
property of one object to another.
function Animal(name) {
this.name = name;
}
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Object.getOwnPropertyNames
returns an array of all own property names (enumerable or not) of a given object.
let person = { name: "John", age: 30 };
let propNames = Object.getOwnPropertyNames(person);
- Every object in JavaScript has a
constructor
property that refers to the constructor function used to create the object.
function Person(name) {
this.name = name;
}
let john = new Person("John");
console.log(john.constructor === Person); // true
- Object cloning involves creating a copy of an existing object. Common methods include using
Object.assign
, the spread operator (...
), or libraries like lodash.
let originalObject = { key: "value" };
// Using Object.assign
let clonedObject = Object.assign({}, originalObject);
// Using spread operator
let clonedObjectSpread = { ...originalObject };
Object.values
returns an array of a given object's own enumerable property values.Object.entries
returns an array of[key, value]
pairs for each enumerable property.
let person = { name: "John", age: 30 };
let values = Object.values(person); // ["John", 30]
let entries = Object.entries(person); // [["name", "John"], ["age", 30]]
Object.create
creates a new object with the specified prototype without invoking a constructor function, while thenew
keyword creates an instance of a constructor function.
let protoObj = { greet: function() { console.log("Hello!"); } };
// Using Object.create
let newObj1 = Object.create(protoObj);
// Using new keyword
function CustomObject() {}
let newObj2 = new CustomObject();
__proto__
is an object property that refers to the prototype of the object. It's used for prototypal inheritance, but its use is discouraged in favor ofObject.getPrototypeOf
andObject.setPrototypeOf
.
let person = { name: "John" };
let anotherPerson = { age: 30 };
anotherPerson.__proto__ = person;
Object.is
compares two values for equality, similar to===
, but with some differences in handling edge cases like NaN and -0.
Object.is(5, 5); // true
Object.is(NaN, NaN); // true
Object.is(0, -0); // false
Object.preventExtensions
prevents new properties from being added to an object but allows modifying or deleting existing properties.
let person = { name: "John" };
Object.preventExtensions(person);
Object.fromEntries
transforms a list of key-value pairs into an object.
let entries = [["name", "John"], ["age", 30]];
let person = Object.fromEntries(entries);
Object.isExtensible
checks if new properties can be added to an object.
let person = { name: "John" };
Object.isExtensible(person); // true
Object.getOwnPropertySymbols
returns an array of all own symbol properties of a given object.
let sym = Symbol("description");
let person = { name: "John", [sym]: "some description" };
let symbols = Object.getOwnPropertySymbols(person);
Object.assign
does not fully preserve property descriptors. It only copies values and does not copy properties with non-default descriptors (e.g., getters, setters).
let source = {
get prop() {
return "getter";
}
};
let target = {};
Object.assign(target, source);
console.log(target.prop); // undefined
Object.isFrozen
checks if an object is frozen (i.e., no new properties can be added, and existing ones cannot be modified or removed).
let person = { name: "John" };
Object.freeze(person);
Object.isFrozen(person); // true
- JSON.stringify doesn't handle circular references by default. Libraries like
circular-json
or custom serialization methods are often used to address this issue.
let obj = { prop: "value" };
obj.circularRef = obj;
JSON.stringify(obj); // Throws a TypeError
- The prototype chain is a mechanism where objects inherit properties and methods from their prototype. It forms a chain of objects linked through their prototypes.
function Animal(name) {
this.name = name;
}
function Dog(breed) {
this.breed = breed;
}
Dog.prototype = new Animal("Generic");
let myDog = new Dog("Labrador");
Object.keys
returns an array of a given object's own enumerable property names.for...in
loop iterates over all enumerable properties, including those inherited through the prototype chain.
let person = { name: "John" };
// Using Object.keys
let keysArray = Object.keys(person);
// Using for...in loop
for (let key in person) {
// Iterates over all enumerable properties
}
- JavaScript doesn't have built-in support for private variables, but closures or the use of symbols can be employed to achieve a level of privacy.
function createPerson() {
let privateVar = "secret";
return {
getPrivateVar: function() {
return privateVar;
}
};
}
let person = createPerson();
- Object augmentation involves adding new properties or methods to an existing object.
- Object extension refers to creating a new object with additional properties or methods.
- When merging objects with the same property names, the last one takes precedence.
let obj1 = { prop: "value1" };
let obj2 = { prop: "value2" };
let mergedObj = { ...obj1, ...obj2 };
console.log(mergedObj.prop); // "value2"
46. What is the purpose of the Object.getOwnPropertyNames
method in relation to property enumeration?
Object.getOwnPropertyNames
returns an array of all own (non-inherited) property names, including non-enumerable properties.
let person = { name: "John" };
let propertyNames = Object.getOwnPropertyNames(person);
47. Explain the difference between Object.assign
and the spread operator (...
) when merging objects.
Object.assign
is used for shallow copying and merging objects. The spread operator performs a shallow copy but is often used for merging.
let obj1 = { a: 1 };
let obj2 = { b: 2 };
// Using Object.assign
let mergedObj1 = Object.assign({}, obj1, obj2);
// Using spread operator
let mergedObj2 = { ...obj1, ...obj2 };
- Mixin patterns involve combining multiple objects to create a new object with the combined functionality.
function mixin(target, ...sources) {
Object.assign(target, ...sources);
}
let canEat = {
eat: function() {
console.log("Eating...");
}
};
let canSleep = {
sleep: function() {
console.log("Sleeping...");
}
};
let animal = {};
mixin(animal, canEat, canSleep);
- Method chaining involves calling multiple methods on an object in a single line, typically returning the object after each method call.
let calculator = {
value: 0,
add: function(x) {
this.value += x;
return this;
},
multiply: function(x) {
this.value *= x;
return this;
}
};
calculator.add(5).multiply(2);
Object.setPrototypeOf
is used to set the prototype of an object, changing its prototype chain.
let person = { name: "John" };
let employee = { role: "Developer" };
Object.setPrototypeOf(employee, person);
WeakMap
andWeakSet
are object collections where keys are weakly held, meaning they don't prevent the referenced objects from being garbage-collected.
let weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, "value");
- Symbols are not enumerable by default. They do not appear in
for...in
loops or in the result ofObject.keys
.
let obj = { key: "value", [Symbol("symbolKey")]: "symbolValue" };
for (let prop in obj) {
console.log(prop); // "key"
}
- Shallow copy creates a new object with the same top-level properties. Deep copy creates a new object and recursively copies all nested objects.
// Shallow copy
let shallowCopy = { ...originalObject };
// Deep copy (using a library like lodash)
let deepCopy = _.cloneDeep(originalObject);
Object.isSealed
checks if an object is sealed (i.e., no new properties can be added, but existing ones can be modified or removed).Object.isFrozen
checks if an object is frozen (i.e., no new properties can be added, and existing ones cannot be modified or removed).
let person = { name: "John" };
Object.seal(person);
Object.isSealed(person); // true
Object.isFrozen(person); // false
- The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance.
let Singleton = (function() {
let instance;
function createInstance() {
// private variables and methods
return {
// public methods and properties
};
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
- Object serialization is the process of converting an object into a format that can be easily stored or transmitted. JSON.stringify is commonly used for serialization.
let obj = { key: "value", num: 42 };
let jsonString = JSON.stringify(obj);
Object.entries
returns an array of[key, value]
pairs for each enumerable own property of an object. It does not include inherited properties.
let parent = { inherited: true };
let child = Object.create(parent, { own: { value: true } });
Object.entries(child); // [["own", true]]
58. Explain the purpose of the Object.getOwnPropertyDescriptors
method in the context of property descriptors.
Object.getOwnPropertyDescriptors
returns all own property descriptors of an object, including configurable, enumerable, value, and getter/setter information.
let person = { name: "John" };
let descriptors = Object.getOwnPropertyDescriptors(person);
Object.isExtensible
checks if new properties can be added to an object.
let person = { name: "John" };
Object.isExtensible(person); // true
- Creating a deep copy of an object with circular references requires handling those references explicitly, often using a map to track visited objects.
function deepCopy(obj, map = new WeakMap()) {
if (map.has(obj)) {
return map.get(obj);
}
let copy = Array.isArray(obj) ? [] : {};
map.set(obj, copy);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = typeof obj[key] === "object" ? deepCopy(obj[key], map) : obj[key];
}
}
return copy;
}
Object.setPrototypeOf
is used to set the prototype of an object, allowing for delegation of properties and methods.
let parent = { greet: function() { console.log("Hello!"); } };
let child = {};
Object.setPrototypeOf(child, parent);
child.greet(); // "Hello!"
Object.isSealed
checks if an object is sealed, meaning no new properties can be added, but existing ones can be modified or removed.
let person = { name: "John" };
Object.seal(person);
Object.isSealed(person); // true
- Property shadowing occurs when a property in a child object has the same name as a property in its prototype chain, causing the child property to "shadow" the parent property.
let parent = { prop: "parentValue" };
let child = Object.create(parent);
child.prop = "childValue"; // Shadowing
- Immutability can be achieved by freezing objects using
Object.freeze
or creating objects with constant values. Immutable objects simplify state management and help prevent unintended side effects.
const immutableObj = Object.freeze({ key: "value" });
65. Explain the purpose of the Object.fromEntries
method, and how does it relate to object creation?
Object.fromEntries
transforms an array of key-value pairs into an object.
let entries = [["name", "John"], ["age", 30]];
let person = Object.fromEntries(entries);
66. What is the role of the Object.getOwnPropertyNames
method in handling non-enumerable properties?
Object.getOwnPropertyNames
returns an array of all own property names of an object, including non-enumerable properties.
let person = { name: "John" };
Object.defineProperty(person, "age", { value: 30, enumerable: false });
let propertyNames = Object.getOwnPropertyNames(person);
- Object composition involves combining objects to create a new one with the combined functionality, while inheritance involves an object inheriting properties and methods from another object.
function canEat(obj) {
obj.eat = function() {
console.log("Eating...");
};
}
function canSleep(obj) {
obj.sleep = function() {
console.log("Sleeping...");
};
}
let animal = {};
canEat(animal);
canSleep(animal);
- You can use
Object.defineProperty
with{ writable: false }
to make a property read-only.
let person = { name: "John" };
Object.defineProperty(person, "name", { writable: false });
Object.is
compares two values for equality, similar to===
, but with some differences in handling edge cases like NaN and -0.
Object.is(5, 5); // true
Object.is(NaN, NaN); // true
Object.is(0, -0); // false
Object.entries
treats non-string keys as strings. It converts them to strings before including them in the result.
let obj = { 42: "value" };
let entries = Object.entries(obj); // [["42", "value"]]
- Prototype pollution occurs when an attacker manipulates an object's prototype, potentially leading to unexpected behavior.
// Example of prototype pollution
Object.prototype.myMaliciousFunction = function() {
console.log("Malicious code executed!");
};
let user = {};
user.myMaliciousFunction(); // Executes malicious code
- Symbols are unique and immutable data types. They can be used as keys for properties in objects to avoid naming conflicts.
const mySymbol = Symbol("description");
let obj = { [mySymbol]: "some value" };
Object.preventExtensions
prevents new properties from being added to an object, but existing properties can be modified or removed.
let person = { name: "John" };
Object.preventExtensions(person);
74. How does JavaScript handle asynchronous programming with objects, especially with the introduction of Promises and async/await?
- Asynchronous operations in JavaScript can be managed using Promises and async/await. Objects, such as Promises, play a crucial role in handling asynchronous code.
function fetchData() {
return new Promise((resolve, reject) => {
// Asynchronous code
});
}
async function fetchDataAsync() {
try {
let result = await fetchData();
console.log(result);
} catch (error) {
console.error(error);
}
}
75. Explain the concept of object iteration in JavaScript using the for...of
loop and how it differs from for...in
.
- The
for...of
loop iterates over iterable objects, such as arrays and strings, while thefor...in
loop iterates over enumerable properties of an object.
let arr = [1, 2, 3];
// Using for...of
for (let value of arr) {
console.log(value);
}
// Using for...in
for (let index in arr) {
console.log(index); // Outputs "0", "1", "2"
}
76. What is the purpose of the Object.values
method, and how does it handle non-enumerable properties?
Object.values
returns an array of a given object's own enumerable property values. It does not include non-enumerable properties.
let person = { name: "John" };
Object.defineProperty(person, "age", { value: 30, enumerable: false });
let values = Object.values(person); // ["John"]
77. Explain the concept of object memoization in JavaScript and its use in optimizing function performance.
- Object memoization involves caching the results of expensive function calls to avoid redundant calculations and improve performance.
function memoize(fn) {
let cache = {};
return function(...args) {
let key = JSON.stringify(args);
if (!(key in cache)) {
cache[key] = fn(...args);
}
return cache[key];
};
}
78. What is the purpose of the Object.getOwnPropertySymbols
method, and how does it interact with other property retrieval methods?
Object.getOwnPropertySymbols
returns an array of all own symbol properties of a given object. It complements other property retrieval methods likeObject.keys
.
let sym = Symbol("description");
let person = { name: "John", [sym]: "some description" };
let symbols = Object.getOwnPropertySymbols(person);
- A mixin pattern involves combining the properties and methods of multiple objects to create a new object with a specific set of functionalities.
function canFly(obj) {
obj.fly = function() {
console.log("Flying...");
};
}
function canSwim(obj) {
obj.swim = function() {
console.log("Swimming...");
};
}
let bird = {};
canFly(bird);
let fish = {};
canSwim(fish);
let flyingFish = {};
canFly(flyingFish);
canSwim(flyingFish);
80. What is the purpose of the Object.create
method, and how does it differ from other object creation methods?
Object.create
is used to create a new object with the specified prototype object. It differs from other methods likeObject.assign
as it allows explicit setting of the prototype.
let personProto = { greet: function() { console.log("Hello!"); } };
let john = Object.create(personProto);
-
What is an array in JavaScript?
- An array is a data structure that holds a collection of values, each identified by an index or a key.
-
How do you create an empty array in JavaScript?
let emptyArray = [];
-
What is the length property of an array, and how is it useful?
- The
length
property returns the number of elements in an array. It is useful for determining the size of the array.
let myArray = [1, 2, 3]; console.log(myArray.length); // Outputs 3
- The
-
How can you access the elements of an array in JavaScript?
- Array elements can be accessed using their index. The index starts from 0.
let myArray = [10, 20, 30]; console.log(myArray[1]); // Outputs 20
-
Explain the difference between
push
andpop
methods in JavaScript arrays.push
adds elements to the end of an array, whilepop
removes the last element from the end.
let myArray = [1, 2, 3]; myArray.push(4); // Adds 4 to the end myArray.pop(); // Removes the last element (4)
-
What are the
shift
andunshift
methods used for in JavaScript arrays?shift
removes the first element from the array, andunshift
adds elements to the beginning of the array.
let myArray = [1, 2, 3]; myArray.unshift(0); // Adds 0 to the beginning myArray.shift(); // Removes the first element (0)
-
Explain the difference between
slice
andsplice
methods.slice
creates a new array from a portion of an existing array without modifying the original array, whilesplice
changes the contents of an array by removing or replacing existing elements.
let originalArray = [1, 2, 3, 4, 5]; let slicedArray = originalArray.slice(1, 4); // [2, 3, 4] let splicedArray = originalArray.splice(1, 3); // [2, 3, 4], modifies originalArray
-
How can you iterate over elements in an array in JavaScript?
- You can use various methods like
for
loop,forEach
,map
,for...of
, andfor...in
to iterate over array elements.
let myArray = [1, 2, 3]; // Using forEach myArray.forEach(function(element) { console.log(element); });
- You can use various methods like
-
What is the
indexOf
method used for in JavaScript arrays?indexOf
returns the first index at which a specified element is found in the array. If the element is not present, it returns -1.
let myArray = [10, 20, 30, 40]; let index = myArray.indexOf(30); // Outputs 2
-
Explain the concept of array filtering using the
filter
method.- The
filter
method creates a new array with all elements that pass the provided function's test.
let numbers = [1, 2, 3, 4, 5]; let filteredNumbers = numbers.filter(function(number) { return number > 2; }); // filteredNumbers will be [3, 4, 5]
- The
-
What is the purpose of the
map
method in JavaScript arrays?- The
map
method creates a new array with the results of calling a provided function on every element in the array.
let numbers = [1, 2, 3]; let squaredNumbers = numbers.map(function(number) { return number * number; }); // squaredNumbers will be [1, 4, 9]
- The
-
Explain the concept of multidimensional arrays in JavaScript.
- Multidimensional arrays are arrays that contain other arrays. They are useful for representing matrices or tables.
let matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ];
-
How can you flatten a nested array in JavaScript?
- Flattening a nested array involves converting a multidimensional array into a single-dimensional array.
let nestedArray = [1, [2, [3, 4]]]; let flattenedArray = nestedArray.flat(Infinity); // [1, 2, 3, 4]
-
**Explain the concept of array destructuring in JavaScript.
** - Array destructuring allows you to extract values from arrays and assign them to variables in a concise way.
```javascript
let myArray = [1, 2, 3];
let [a, b, c] = myArray;
// a = 1, b = 2, c = 3
```
-
What is the purpose of the
reduce
method in JavaScript arrays, and how does it work?- The
reduce
method executes a reducer function on each element of the array, resulting in a single output value.
let numbers = [1, 2, 3, 4]; let sum = numbers.reduce(function(accumulator, current) { return accumulator + current; }, 0); // sum will be 10
- The
-
Explain the concept of the spread operator (
...
) and how it can be used with arrays.- The spread operator allows you to spread the elements of an array into a new array or function arguments.
let array1 = [1, 2, 3]; let array2 = [...array1, 4, 5]; // array2 will be [1, 2, 3, 4, 5]
-
How can you check if a variable is an array in JavaScript?
- You can use the
Array.isArray()
method to check if a variable is an array.
let myArray = [1, 2, 3]; Array.isArray(myArray); // true
- You can use the
Simple polyfill for the flat()
method:
// Check if flat method is supported
if (!Array.prototype.flat) {
Array.prototype.flat = function(depth = 1) {
// Ensure depth is a positive integer
depth = Math.floor(depth);
if (isNaN(depth) || depth < 1) {
return this.slice();
}
// Recursive flattening function
const flatten = (arr, currentDepth) => {
return arr.reduce((result, item) => {
if (Array.isArray(item) && currentDepth < depth) {
result.push(...flatten(item, currentDepth + 1));
} else {
result.push(item);
}
return result;
}, []);
};
// Start flattening with depth 1
return flatten(this, 1);
};
}
// Example usage:
const nestedArray = [1, [2, [3, 4], 5]];
const flattenedArray = nestedArray.flat(2);
console.log(flattenedArray); // Output: [1, 2, 3, 4, 5]
This polyfill checks if the flat()
method is already defined on the Array.prototype
. If not, it defines a new flat()
method that takes an optional depth
parameter for specifying how deep the flattening should occur. The recursive flatten
function is used to handle the actual flattening. The polyfill then allows you to use the flat()
method on arrays that might not have it natively.
Certainly! Here are some more advanced interview questions related to JavaScript arrays:
- The
some
method tests whether at least one element in the array passes the provided function's test, while theevery
method tests whether all elements pass the test.
let numbers = [1, 2, 3, 4, 5];
let isAnyGreaterThanTwo = numbers.some(function(number) {
return number > 2;
});
// isAnyGreaterThanTwo will be true
let areAllGreaterThanTwo = numbers.every(function(number) {
return number > 2;
});
// areAllGreaterThanTwo will be false
- The
find
method returns the first element in the array that satisfies the provided function's test, andfindIndex
returns the index of that element.
let numbers = [1, 2, 3, 4, 5];
let foundNumber = numbers.find(function(number) {
return number > 2;
});
// foundNumber will be 3
let foundIndex = numbers.findIndex(function(number) {
return number > 2;
});
// foundIndex will be 2
- You can use various methods, such as using
Set
orfilter
withindexOf
, to remove duplicate elements from an array.
let arrayWithDuplicates = [1, 2, 3, 1, 2, 4];
// Using Set
let uniqueArray = [...new Set(arrayWithDuplicates)];
// Using filter and indexOf
let uniqueArray2 = arrayWithDuplicates.filter((value, index, self) => {
return self.indexOf(value) === index;
});
- The
flatMap
method first maps each element using a mapping function, then flattens the result into a new array.
let numbers = [1, 2, 3];
let doubledAndFlattened = numbers.flatMap(function(number) {
return [number * 2, number * 3];
});
// doubledAndFlattened will be [2, 3, 4, 6, 6, 9]
- You can use the
reverse
method to reverse the elements of an array in place.
let myArray = [1, 2, 3];
myArray.reverse(); // myArray will be [3, 2, 1]
- The
sort
method sorts the elements of an array in place, converting elements to strings and comparing their sequences of UTF-16 code units values.
let fruits = ["apple", "banana", "orange", "grape"];
fruits.sort(); // fruits will be ["apple", "banana", "grape", "orange"]
- The
reduceRight
method applies a function against an accumulator and each element in the array (from right to left) to reduce it to a single value.
let numbers = [1, 2, 3, 4];
let result = numbers.reduceRight(function(acc, current) {
return acc - current;
});
// result will be -2
25. Explain the concept of the Array.from
method and its use in creating arrays from array-like objects.
- The
Array.from
method creates a new, shallow-copied array instance from an array-like or iterable object.
let arrayLike = { length: 3, 0: "a", 1: "b", 2: "c" };
let newArray = Array.from(arrayLike); // ["a", "b", "c"]
- Binary search is an efficient algorithm for finding an item from a sorted array.
function binarySearch(arr, target) {
let start = 0;
let end = arr.length - 1;
while (start <= end) {
let mid = Math.floor((start + end) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return -1;
}
ArrayBuffer
is a binary data buffer, andTypedArray
provides a view for accessing the raw binary data.
let buffer = new ArrayBuffer(8);
let int32View = new Int32Array(buffer);
int32View[0] = 42;
These advanced questions cover a variety of topics related to JavaScript arrays, including advanced array methods (some
, every
, `
find,
findIndex,
flatMap), array manipulations (removing duplicates, reversing, sorting), and more specialized topics like binary search and
ArrayBuffer`. Understanding these concepts will deepen your expertise in working with arrays in JavaScript.
Certainly! Here are some additional advanced interview questions related to JavaScript arrays:
28. Explain the concept of the ArrayBuffer
and DataView
in JavaScript, and how they relate to binary data handling.
ArrayBuffer
represents a fixed-length raw binary data buffer, andDataView
provides a way to read and write data in a buffer.
let buffer = new ArrayBuffer(16);
let dataView = new DataView(buffer);
dataView.setInt32(0, 42);
let value = dataView.getInt32(0);
- The Fisher-Yates shuffle is an algorithm for generating a random permutation of a finite sequence.
function fisherYatesShuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
- TypedArrays provide a way to view and manipulate raw binary data in the
ArrayBuffer
directly.
let buffer = new ArrayBuffer(16);
let int32View = new Int32Array(buffer);
int32View[0] = 42;
- You can use the
splice
method to efficiently remove elements from the middle of an array.
let myArray = [1, 2, 3, 4, 5];
myArray.splice(2, 2); // Removes elements starting at index 2, removes 2 elements
32. Explain the purpose of the Int8Array
, Uint8Array
, and Uint8ClampedArray
in JavaScript TypedArrays.
Int8Array
represents an array of 8-bit signed integers,Uint8Array
represents an array of 8-bit unsigned integers, andUint8ClampedArray
represents an array of 8-bit unsigned integers clamped to 0-255.
let int8Array = new Int8Array(4);
let uint8Array = new Uint8Array(4);
let uint8ClampedArray = new Uint8ClampedArray(4);
Set
is a built-in object that lets you store unique values of any type. It can be used to remove duplicates from an array.
let arrayWithDuplicates = [1, 2, 3, 1, 2, 4];
let uniqueSet = new Set(arrayWithDuplicates);
let uniqueArray = [...uniqueSet];
- You can use the
concat
method or the spread operator (...
) to efficiently concatenate arrays.
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
let concatenatedArray = array1.concat(array2);
// or
let concatenatedArray2 = [...array1, ...array2];
35. Explain the concept of the Array.prototype.includes
method and its use in searching for elements.
- The
includes
method determines whether an array includes a certain element, returningtrue
orfalse
as appropriate.
let myArray = [1, 2, 3];
let includesTwo = myArray.includes(2); // true
- You can use the
filter
method to find the common elements between two arrays.
let array1 = [1, 2, 3, 4];
let array2 = [3, 4, 5, 6];
let intersection = array1.filter(value => array2.includes(value));
- The
reduce
method applies a function against an accumulator and each element in the array to reduce it to a single value.
let numbers = [1, 2, 3, 4];
let sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
// sum will be 10
- You can use the
filter
method to find elements that exist in one array but not in the other.
let array1 = [1, 2, 3, 4];
let array2 = [3, 4, 5, 6];
let difference = array1.filter(value => !array2.includes(value));
- Array cloning involves creating a copy of an existing array. You can use methods like
slice
,concat
, or the spread operator ([...array]
) for cloning.
let originalArray = [1, 2, 3];
let clonedArray = originalArray.slice();
// or
let clonedArray2 = originalArray.concat();
// or
let clonedArray3 = [...originalArray];
These questions cover a range of advanced topics related to JavaScript arrays, including TypedArrays, binary data handling, array shuffling, intersection, difference, and efficient array manipulation. Understanding these concepts will enhance your proficiency in working with arrays in JavaScript.