This error will come while doing git commit. Temporary fix for this error is
git commit -m "message" --no-verify
Above solution will also work for the following error too.
husky – pre-commit script failed(code 127)
We can use query parameter with Model.find() method as follows.
userRouter.route('/users').get((req, res) => {
const { query } = req;
Users.find(query).then((err, books) => {
if(err){
return res.send(err)
}
return res.json(books)
});
})
The use of callback functions has been deprecated in the latest version of Mongoose.
we need to use either Promises or async/await syntax.
Particularly if Model.find throws an error then we can replace it as follows.
Model.find().then((err, data) => {
if(err){
return res.send(err)
}
return res.json(data)
});
Hoisting is the process of moving declarations to the top of their scope, prior to the execution of the code. JavaScript only hoists declarations, not initializations.
Example 1:message = "Hello World";console.log(message);var message;in Example 1, The variable Has been hoisted and consoles output as "Hello World";Example 2:console.log(message);var message = "Hello World";in Example 2, The variable Has been hoisted but not initialization. So consoles output as undefined.Example 3:var message;console.log(message);message = "Hello World";Example 3 also consoles the output as undefined because JavaScript only hoists declarations, not initializations.
The equality (==) operator simply compares the operands (values) and returns result in a boolean format. If two operands are equal, then it returns true otherwise returns false. Type conversion will takes place based on values.
Example:1 == "1" (true)0 == false (true)
The strict equality(===) operator compares both operands(values) and data types and returns result in a boolean format.
Example:1 === "1" (false)0 === false (false)
In javascript both Addition and Concatenation uses the same ‘+’ operator.
Addition : If both operands are numbers, then only it will perform Addition operation.
Example 1:let x = 5;let y = 7;let z = x + y; // output is 12.Example 2:let x = 3;x = x + 5 ; // output is 8.
Concatenation: If any of the operand is string, then it performs the Concatenation operation.
Example 1: let x = 5;let y = "10";let z = x + y; // output is 510.Example 2;let x = 5;let y = "a";let z = x + y; // output is 5a.Example 3;let x = 6;x += "7"; // output is 67.
Example 1 : (Using Call() method to invoke a function and specifying the this value )
function greeting() { console.log(this.greet, "learnersstore.com");}const obj1 = { greet: 'Hi'}const obj2 = { greet: 'Hello'}greeting.call(obj1);greeting.call(obj2);Output : Hi learnersstore.comHello learnersstore.com
Example 2 : (Using Call() method to invoke a function without first argument)
function greeting() { console.log(this.greet, "learnersstore.com");}const obj1 = { greet: 'Hi'}greeting.call();Output :undefined learnersstore.com
Note: If we are omitting the first parameter, then it returns undefined.
Example 3 : (Using Call() method to invoke a function without first argument But with globalThis)
globalThis.greet = "Hello";function greeting() { console.log(this.greet, "learnersstore.com");}const obj1 = { greet: 'Hi'}greeting.call();Output: Hello learnersstore.com
Example 4 : (Using Call() method to invoke a function with multiple arguments)
function display(name, age) { console.log(`Name : ${name}, Age: ${age}, Location: ${this.location}`);}const obj1 = { location: 'India',}display.call(obj1, "Smith", 26);Output :Name : Smith, Age: 26, Location: India
5. What are different ways to create an object in JavaScript ?
There are multiple ways:
(i) Object literal:
const obj = { name: "Alice", age: 25 };
👉 Most common, clean, and easy to read.
(ii) Constructor function:
const obj = new Object();obj.name = "Alice";
👉 Rarely used directly, but new Object() works like {}.
(iii) Object.create
const obj = Object.create(null);
👉 Creates an object with a specified prototype (or no prototype at all).
(iv) Object() function call:
const obj = Object();
👉 Same as new Object(), creates an empty object.
6. Which way is the most recommended in practice to create an object in JavaScript ?
{}) are preferred for simple object creation — cleaner and faster.Object.create() is useful when you want to set a custom prototype (e.g., for inheritance patterns).new Object() and Object() are rarely used directly — they add unnecessary verbosity.7. Is Object.create(null) the same as {} ?
No ❌
{} creates an object with Object.prototype.Object.create(null) creates a prototype-less object, meaning:const obj1 = {};console.log(obj1.toString); // [Function: toString]const obj2 = Object.create(null);console.log(obj2.toString); // ❌ undefined
👉 Useful for creating pure dictionary objects without risk of key collisions with toString, hasOwnProperty, etc.
8. What happens if you call Object() without new?
Object() behaves the same as new Object().
const a = Object();const b = new Object();console.log(typeof a, typeof b); // both "object"
👉 Calling it as a function automatically creates an object.
9. Can you explain a real-world use case of Object.create() ?
we can create multiple user objects with shared behavior:
const userPrototype = { greet() { return `Hello, my name is ${this.name}`; }};const user1 = Object.create(userPrototype);user1.name = "Alice";const user2 = Object.create(userPrototype);user2.name = "Bob";console.log(user1.greet()); // Hello, my name is Aliceconsole.log(user2.greet()); // Hello, my name is Bob
👉 Object.create() allows you to create objects that share a prototype, without needing classes.
10. What is event capturing ?
Event Capturing is one of the phase in event propagation. Event Capturing means an event travels down from the outermost element (Generally window object) to the target element.
11. What is the difference between var, let, and const in JavaScript?
In JavaScript, var, let, and const are used to declare variables, but they differ in scope, hoisting, and reassignment.
| Keyword | Scope Type | Explanation |
|---|---|---|
| var | Function scope | Accessible anywhere inside the function where it is declared. |
| let | Block scope | Accessible only inside the block { } where it is declared. |
| const | Block scope | Same as let. Restricted to the block { }. |
Example:
if (true) { var a = 10; // function scoped let b = 20; // block scoped const c = 30; // block scoped}console.log(a); // 10console.log(b); // errorconsole.log(c); // error
All three (var, let, const) get hoisted, but behave differently.
| Keyword | Hoisted? | Access Before Declaration |
|---|---|---|
| var | Yes | Allowed → returns undefined (not recommended) |
| let | Yes | Not allowed → throws error (temporal dead zone) |
| const | Yes | Not allowed → throws error |
Example:
console.log(x); // undefinedvar x = 10;console.log(y); // errorlet y = 20;console.log(z); // errorconst z = 30;
| Keyword | Reassign? | Redeclare? |
|---|---|---|
| var | ✔ Yes | ✔ Yes |
| let | ✔ Yes | ✖ No |
| const | ✖ No (value cannot change) | ✖ No |
Example:
var a = 1;var a = 2; // allowedlet b = 3;b = 4; // allowed// let b = 5; // errorconst c = 6;// c = 7; // error
Note:
constmeans the variable binding cannot change,
but object properties can still change:
const obj = { name: "Raj" };obj.name = "Kumar"; // allowed
const → Block-scoped, hoisted but in temporal dead zone, no reassign, no redeclare.
var → Function-scoped, hoisted with undefined, allows redeclare & reassign.
let → Block-scoped, hoisted but in temporal dead zone, allows reassign, no redeclare.
12. What is a Closure in JavaScript ? Explain with an Example .
A closure in JavaScript is a function that remembers and accesses variables from its outer (parent) function, even after the parent function has finished executing.
In simple words:
➡️ A closure gives you access to a parent function’s scope from a child function.
Closures are created automatically whenever a function is defined inside another function.
Closures allow:
function outerFunction() { let count = 0; // variable in outer function function innerFunction() { count++; // inner function uses outer variable console.log(count); } return innerFunction; // returning the inner function}const counter = outerFunction();counter(); // 1counter(); // 2counter(); // 3
outerFunction() creates a variable count.innerFunction() accesses count, even after outerFunction() has returned.counter() is called, it increments the same count variable.This is the essence of a closure.
A closure is formed when an inner function remembers variables from its outer function’s scope, even after the outer function has executed.
Creating private variables:
function createBankAccount() { let balance = 1000; // private variable return { deposit(amount) { balance += amount; console.log("Balance:", balance); }, withdraw(amount) { balance -= amount; console.log("Balance:", balance); } };}const account = createBankAccount();account.deposit(500); // Balance: 1500account.withdraw(300); // Balance: 1200
Here, balance is private — it cannot be accessed directly, only through closure functions.
Arrow functions (introduced in ES6) are a shorter and cleaner way to write functions in JavaScript.
They use the => (fat arrow) syntax and do not have their own this, arguments, super, or new.target.
const functionName = (parameters) => { // function body};
Example:
const add = (a, b) => a + b;console.log(add(2, 3)); // 5
Arrow functions reduce code size significantly.
// Normal functionfunction greet() { return "Hello!";}// Arrow functionconst greet = () => "Hello!";
this bindingArrow functions do not have their own this.
They inherit this from the surrounding (lexical) scope.
Example:
function Person() { this.name = "Raj"; setTimeout(() => { console.log(this.name); }, 1000);}new Person(); // Raj
If we used a normal function inside setTimeout, this would NOT work correctly.
Arrow functions cannot be used with new.
const Person = () => {};// new Person(); // ❌ TypeError
arguments objectArrow functions do not have arguments.
You must use rest parameters:
const sum = (...nums) => nums.reduce((a, b) => a + b);console.log(sum(1, 2, 3)); // 6
const numbers = [1, 2, 3];const doubled = numbers.map(n => n * 2);console.log(doubled); // [2, 4, 6]
Arrow functions are a concise way to write functions in JavaScript. They do not have their own this or arguments and use lexical scoping, making them ideal for callbacks and shorter functions.
In JavaScript, this refers to the object that is currently executing the function.
Its value changes based on how and where a function is called — not where it is written.
Understanding this is important because it behaves differently in:
this Works in Different Contextsi). this in Global Scope
In a browser:
console.log(this);
Output: window object.
this Inside an Object MethodWhen a function is called as a method, this refers to the object.
const person = { name: "Raj", greet() { console.log(this.name); }};person.greet(); // Raj
Here, this → person object.
this in a Regular FunctionIn non-strict mode, this refers to the global object.
function test() { console.log(this);}test(); // window (in browser)
In strict mode, it becomes undefined.
"use strict";function test() { console.log(this);}test(); // undefined
this Inside an Event Handler (Browser)button.addEventListener("click", function () { console.log(this); // refers to the button element});
In event listeners, this → element that triggered the event.
this in Constructor FunctionsWhen using new, this refers to the newly created object.
function Person(name) { this.name = name;}const p = new Person("Raj");console.log(p.name); // Raj
this in Arrow Functions ➡️ Arrow functions do NOT have their own this.
➡️ They inherit this from the parent (lexical) scope.
const person = { name: "Raj", showName: () => { console.log(this.name); }};person.showName(); // undefined
Because arrow functions take this from the outer scope (not the object).
Better version:
const person = { name: "Raj", showName() { console.log(this.name); }};person.showName(); // Raj
this in JavaScript refers to the object that is executing the current function. Its value depends on how the function is called, not where it is defined. Arrow functions do not have their own this and instead inherit it from the surrounding scope.
In JavaScript, call(), apply(), and bind() are methods used to control the value of this inside a function.
They belong to all functions because every function in JavaScript internally has access to Function.prototype.
1. call() Method
Usage:
Immediately invokes the function with a specified this value and arguments passed individually.
Syntax:
func.call(thisArg, arg1, arg2, ...)
function greet(city) { console.log(`Hello ${this.name} from ${city}`);}const user = { name: "Raj" };greet.call(user, "India");// Output: Hello Raj from India
Usage:
Immediately invokes the function with a specified this value and arguments passed as an array.
Syntax:
func.apply(thisArg, [arg1, arg2, ...])
function greet(city, country) { console.log(`Hello ${this.name} from ${city}, ${country}`);}const user = { name: "Raj" };greet.apply(user, ["Hyderabad", "India"]);// Output: Hello Raj from Hyderabad, India
Usage:
Does not call the function immediately.
Instead, it returns a new function with the this value permanently set.
Syntax:
const newFunc = func.bind(thisArg, arg1, arg2, ...)
function greet() { console.log(`Hello ${this.name}`);}const user = { name: "Raj" };const greetUser = greet.bind(user);greetUser(); // Output: Hello Raj
| Method | When It Executes | Arguments Format | Returns |
|---|---|---|---|
| call() | Immediately | Pass as comma-separated | Result of function |
| apply() | Immediately | Pass as an array | Result of function |
| bind() | Later (when invoked) | Pass individually (when calling) | New function with fixed this |
call() → invokes function immediately, arguments individually
apply() → invokes function immediately, arguments as array
bind() → returns a new function with this permanently set (does not run immediately)
The DOM (Document Object Model) and Virtual DOM are both used for rendering UI, but they work in very different ways.
The DOM is the actual structure of your webpage, created by the browser.
It represents HTML elements as a tree and allows JavaScript to modify them.
document.getElementById("title").innerHTML = "Hello World";
The Virtual DOM is a lightweight, in-memory copy of the real DOM.
Libraries like React use it to optimize updates.
setState({ name: "John" });
React updates the Virtual DOM → compares differences → updates only the changed part in the real DOM.
| Feature | DOM | Virtual DOM |
|---|---|---|
| Definition | Browser’s actual UI structure | Lightweight copy of DOM in memory |
| Update Speed | Slow (direct updates) | Fast (virtual updates first) |
| Re-rendering | Entire UI can re-render | Only changed nodes update |
| Performance | Less optimized | Highly optimized |
| Used In | All web pages | React, Vue, and similar libraries |
| Cost of Manipulation | High | Low |
DOM is the browser’s actual document structure. Virtual DOM is an in-memory representation used by frameworks like React to optimize UI updates. Virtual DOM compares old and new states, finds differences, and updates only the necessary parts of the real DOM, improving performance.
JavaScript is a high-level, flexible, and interpreted programming language used to make web pages dynamic and interactive. It is one of the core technologies of the web, along with HTML and CSS.
When you click a button, slide an image, show a popup, validate a form, or fetch API data — all of this is powered by JavaScript.
JavaScript runs directly in the browser (Chrome, Firefox, Safari, etc.) without needing installation.
With Node.js, JavaScript can run on servers to build backend applications.
It uses an event loop, callbacks, promises, and async/await to handle asynchronous operations efficiently.
JavaScript supports prototype-based object-oriented programming.
Used for:
JavaScript is a high-level, dynamic, and interpreted scripting language used to build interactive and dynamic web pages. It runs in the browser and, with Node.js, can also be used for server-side development.
An interpreted programming language is a language where the code is executed line by line by an interpreter instead of being converted to machine code before execution.
In simple words:
Interpreted languages run the code directly without a separate compilation step like C or Java.
There is no need to compile the entire program before running it.
The interpreter reads code one line at a time, translates it, and executes it immediately.
Errors are detected at runtime, making debugging simpler.
As long as the machine has the correct interpreter (like a browser for JavaScript), the code will run on any OS.
JavaScript code is executed by the browser’s JavaScript engine (like Chrome’s V8), which interprets and runs it instantly.
console.log("Hello World");
The browser executes this line immediately without compiling the entire file beforehand.
An interpreted programming language executes code line-by-line at runtime instead of compiling it beforehand. JavaScript is interpreted because the browser runs its code directly using a JavaScript engine.
A compiler and an interpreter are both used to translate high-level programming code into machine-understandable code.
However, they work differently.
| Feature | Compiler | Interpreter |
|---|---|---|
| Execution Method | Translates the entire program at once | Translates and executes code line-by-line |
| Speed | Faster (because entire code is pre-compiled) | Slower (because each line is interpreted at runtime) |
| Error Detection | Shows all errors after full compilation | Stops immediately when an error is found |
| Output | Produces an executable file (e.g., .exe) | Does not produce an executable file |
| Examples | C, C++, Java | JavaScript, Python, PHP |
A compiler converts the entire source code into machine code before execution.
An interpreter translates and executes the program line-by-line.
Imagine reading a book written in another language:
You translate the entire book first, then read it.
You translate line by line as you read.
A compiler translates the entire program into machine code at once and creates an executable file. An interpreter translates and executes code line-by-line during runtime. Compiled programs run faster, while interpreted programs are easier to debug.
The Event Loop is the heart of JavaScript’s asynchronous behavior.
Since JavaScript is single-threaded, it cannot run multiple tasks at the same time.
However, the event loop allows JavaScript to handle asynchronous operations like:
This makes JavaScript appear non-blocking even though it has only one main thread.
The event loop continuously checks the Call Stack and the Callback Queue.
If the Call Stack is empty, it pushes the next pending callback into it, allowing JavaScript to handle asynchronous operations efficiently.
Where JavaScript executes code line-by-line.
Browser/Javascript engine features like:
These run outside the main thread.
When async operations finish, their callbacks are placed in the queue.
The event loop constantly checks:
This is how asynchronous code executes without blocking.
┌───────────────┐
│ Call Stack │ ← Executes code
└───────────────┘
↑
┌───────────────┐
│ Event Loop │ ← Moves tasks when stack is empty
└───────────────┘
↑
┌───────────────┐
│ Callback Queue │ ← Pending async callbacks
└───────────────┘
console.log("Start");
setTimeout(() => {
console.log("Inside Timeout");
}, 0);
console.log("End");
Start
End
Inside Timeout
Even though setTimeout is 0 ms:
The event loop enables JavaScript to handle asynchronous operations. It checks whether the call stack is empty, and if so, moves pending callbacks from the event queue into the stack. This allows JavaScript to remain non-blocking even though it is single-threaded.
Answer:
Asynchronous operations allow JavaScript to start a task and continue executing other code without waiting for that task to finish.
JavaScript runs on a single thread.
If it waits for slow tasks (API calls, timers), the whole app would freeze.
console.log("Start");
setTimeout(() => {
console.log("Async task done");
}, 2000);
console.log("End");
Output:
Start
End
Async task done
👉 JavaScript didn’t wait — that’s asynchronous behavior.
Answer:
To keep applications responsive while performing time-consuming operations.
Asynchronous programming is like ordering food and sitting comfortably instead of standing in the kitchen until it’s cooked.
That’s async programming.
Answer:
A Promise is an object that represents a value that will be available now, later, or never.
“I promise to deliver your order.”
It can be:
- Pending (preparing)
- Fulfilled (delivered)
- Rejected (failed)
Answer:
A Promise has three states:
Once fulfilled or rejected, the state never changes again.
const promise = new Promise((resolve, reject) => {
resolve("Data received");
});
promise
.then(result => console.log(result))
.catch(error => console.error(error));
👉 .then() runs on success
👉 .catch() runs on failure
Answer:
Callback hell happens when callbacks are nested inside callbacks, making code unreadable.
login(user, () => {
getProfile(() => {
getOrders(() => {
getPayments(() => {
console.log("Done");
});
});
});
});
❌ Hard to read
❌ Hard to debug
❌ Hard to maintain
Answer:
Promises flatten nested callbacks into a clean, linear structure.
login()
.then(getProfile)
.then(getOrders)
.then(getPayments)
.then(() => console.log("Done"))
.catch(err => console.error(err));
✔ Clean
✔ Readable
✔ One place for error handling
Answer:
Promise chaining means running promises one after another, where each step depends on the previous one.
Each .then():
Answer:
If any promise fails, the chain immediately jumps to .catch().
fetchUser()
.then(fetchOrders)
.then(fetchPayments)
.catch(err => console.error("Error occurred:", err));
👉 One error handler is enough.
async / await?Answer:async / await is a modern way to write promise-based code that looks like synchronous code.
async function loadData() {
try {
const user = await fetchUser();
const orders = await fetchOrders(user);
const payments = await fetchPayments(orders);
console.log(payments);
} catch (err) {
console.error(err);
}
}
✔ Easier to read
✔ Easier to debug
✔ Cleaner logic
async / await blocking?Answer:
No. async / await is non-blocking internally and still uses promises.
👉 It only looks synchronous.
.then() and async / await| Feature | .then() | async / await |
|---|---|---|
| Style | Promise chaining | Sync-like |
| Error handling | .catch() | try / catch |
| Readability | Medium | High |
| Debugging | Harder | Easier |
Answer:
Use Promise.all().
const [users, orders] = await Promise.all([
fetchUsers(),
fetchOrders()
]);
✔ Faster
✔ Efficient
Promise.all()?Answer:
The entire Promise.all() fails immediately and goes to catch.
.then() and async / await?Answer:
Yes, but it’s not recommended because it reduces readability.
?.)Optional chaining (?.) safely accesses nested properties without throwing errors when values are null or undefined.
Example:
const user = {};console.log(user.profile?.name);
✅ Output:
undefined
Check this for Detailed Explanation
sort() method with a simple example.The sort() method is used to sort elements of an array in place.
By default, it converts elements to strings and sorts them lexicographically (dictionary order).
const values = [32, 25, 120];values.sort();console.log(values);
Output:
[120, 25, 32]
Reason:
Numbers are converted to strings: "32", "25", "120" and sorted alphabetically.
values.sort((a, b) => a - b);
Output:
[25, 32, 120]
JavaScript’s
sort()method sorts array elements as strings by default, so a compare function is required for numeric sorting.