So, JavaScript has three ways to declare variables - and honestly, it's a bit confusing at first. It's short. But, if you're new to JavaScript, you're probably wondering why you need var, let, and const - what's the point, right? It's not just about using the latest keywords, it's about how they interact with JavaScript's execution model, which is pretty complex. Think of it like a conversation - you need to understand the context, the tone, and the nuances to really get what's being said. And, that's basically what JavaScript's doing when you declare a variable - it's creating a whole environment, with its own set of rules and structures. So, here's what happens: JavaScript creates a Lexical Environment, sets up an Environment Record to store variables and functions, and links to the parent environment for scope - it's like setting up a whole new world, with its own geography and history. Now, var, let, and const work differently with these structures - they're like different personalities, each with their own quirks and traits. Let's look at var: it creates a property in the Environment Record and sets it to undefined - it's like reserving a seat at a table, but not actually sitting down yet. The assignment happens later, during the execution phase - it's like the food is being served, but you're not eating it yet. This is why var is "hoisted" - it exists from the start, but its value is undefined until assigned - it's like having a placeholder, a temporary stand-in until the real thing arrives. Let and const are different - they create a new Lexical Environment with its own Environment Record - it's like starting a new conversation, with its own set of rules and assumptions. The variable exists in the record, but accessing it before initialization throws an error - it's like trying to start a conversation before you've introduced yourself. This is called the Temporal Dead Zone (TDZ) - it's like a no-man's land, where you can't go until you've been properly introduced. For example, let x = 10 in a block creates a new environment for that block - it's like creating a whole new world, with its own rules and structures. Const x = 10 creates a binding that is immutable - it's like setting something in stone, so it can't be changed. Understanding how var, let, and const work with JavaScript's Lexical Environment system helps you predict behavior and debug issues - it's like having a map, to navigate the complex world of JavaScript. So, it's worth taking the time to learn about it - trust me, it's worth it. Source: https://lnkd.in/g72BVQUZ #JavaScript #Variables #Coding
JavaScript Variable Declaration: var, let, and const Explained
More Relevant Posts
-
Part 1: Why JavaScript Why? 🚨 JavaScript Question (surprisingly tricky) What will be the result of this code? 🤔 const initialGameBoard = [ [null, null, null], [null, null, null], [null, null, null], ]; const copiedArray = [...initialGameBoard]; copiedArray[0][0] = 'X'; console.log(initialGameBoard[0][0]); ⬇️ ⬇️ ⬇️ Most people expect null. But the actual output is: 👉 'X' Why does this happen? [...] creates a shallow copy, not a deep one. That means: The outer array is copied The inner arrays are NOT copied Both arrays still reference the same nested arrays in memory So changing copiedArray[0][0] also changes initialGameBoard[0][0]. The correct way (for a 2D array) const copiedArray = initialGameBoard.map(row => [...row]); Now: The outer array is new Each inner array is also new No shared references ✅ Why doesn’t JavaScript do a deep copy automatically? Because predictability > magic. If JavaScript auto-deep-copied: How deep should it go? What about circular references? What about functions, Dates, Maps, Sets, DOM nodes? There’s no single “correct” answer. So JavaScript makes this rule very explicit: Copying is shallow by default. Always one level. This keeps behavior: predictable performant explicit (you control when deep copies happen) Key takeaway 🔑 Spread (...) copies values — and for objects/arrays, the value is a reference. If you want a deep copy, you must say so explicitly. Curious how many people got this right on the first try 👇 What would you have answered?
To view or add a comment, sign in
-
𝗪𝗵𝘆 𝗝𝗮𝘃𝗮𝗦𝗰𝗿𝗶𝗽𝘁 𝗕𝗲𝗵𝗮𝘃𝗲𝘀 𝘁𝗵𝗲 𝗪𝗮𝘆 𝗜𝘁 𝗗𝗼𝗲𝘀 (𝗘𝘅𝗲𝗰𝘂𝘁𝗶𝗼𝗻 𝗖𝗼𝗻𝘁𝗲𝘅𝘁 𝗘𝘅𝗽𝗹𝗮𝗶𝗻𝗲𝗱) Ever wondered what actually happens when JavaScript runs your code? It’s not magic, it’s the 𝗘𝘅𝗲𝗰𝘂𝘁𝗶𝗼𝗻 𝗖𝗼𝗻𝘁𝗲𝘅𝘁. Once you understand it, concepts like hoisting, scope, and closures finally make sense. 𝗪𝗵𝗮𝘁 𝗜𝘀 𝗮𝗻 𝗘𝘅𝗲𝗰𝘂𝘁𝗶𝗼𝗻 𝗖𝗼𝗻𝘁𝗲𝘅𝘁? An Execution Context is the environment where JavaScript code is evaluated and executed. Think of it as a stage where your code performs. • When a script loads → 𝗚𝗹𝗼𝗯𝗮𝗹 𝗘𝘅𝗲𝗰𝘂𝘁𝗶𝗼𝗻 𝗖𝗼𝗻𝘁𝗲𝘅𝘁 is created • Every time a function is called → a new 𝗙𝘂𝗻𝗰𝘁𝗶𝗼𝗻 𝗘𝘅𝗲𝗰𝘂𝘁𝗶𝗼𝗻 𝗖𝗼𝗻𝘁𝗲𝘅𝘁 is created • These contexts are managed by the 𝗖𝗮𝗹𝗹 𝗦𝘁𝗮𝗰𝗸 Each context contains an 𝗲𝗻𝘃𝗶𝗿𝗼𝗻𝗺𝗲𝗻𝘁 𝗿𝗲𝗰𝗼𝗿𝗱, which keeps track of variables, functions, and their bindings. 𝗧𝗵𝗲 𝗧𝘄𝗼-𝗣𝗵𝗮𝘀𝗲 𝗣𝗿𝗼𝗰𝗲𝘀𝘀: 𝗖𝗿𝗲𝗮𝘁𝗶𝗼𝗻 𝗮𝗻𝗱 𝗘𝘅𝗲𝗰𝘂𝘁𝗶𝗼𝗻 Every execution context goes through 2 phases: 𝟭. 𝗖𝗿𝗲𝗮𝘁𝗶𝗼𝗻 𝗣𝗵𝗮𝘀𝗲 In this phase, before any code runs, the engine: • Allocates memory for variables, functions and other identifiers within the context • Registers identifiers in the environment record Important details: • 𝘃𝗮𝗿 → initialized as 𝘂𝗻𝗱𝗲𝗳𝗶𝗻𝗲𝗱 • 𝗹𝗲𝘁 & 𝗰𝗼𝗻𝘀𝘁 → hoisted but uninitialized (Temporal Dead Zone) • Function declarations → fully initialized and ready to use 𝟮. 𝗘𝘅𝗲𝗰𝘂𝘁𝗶𝗼𝗻 𝗣𝗵𝗮𝘀𝗲 The engine: • Adds execution context to the call stack • Executes code line by line • Assigns actual values to variables • Runs your logic This two-step process explains much of JavaScript’s behavior. 𝗣𝗿𝗮𝗰𝘁𝗶𝗰𝗮𝗹 𝗜𝗺𝗽𝗹𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀: 𝗧𝗵𝗲 "𝗦𝗼 𝗪𝗵𝗮𝘁?" 𝟭. 𝗛𝗼𝗶𝘀𝘁𝗶𝗻𝗴 Hoisting happens because declarations are processed during the creation phase. • 𝘃𝗮𝗿 → accessible as undefined • 𝗹𝗲𝘁 & 𝗰𝗼𝗻𝘀𝘁 → inaccessible until declared (TDZ → 𝗥𝗲𝗳𝗲𝗿𝗲𝗻𝗰𝗲𝗘𝗿𝗿𝗼𝗿) • 𝗙𝘂𝗻𝗰𝘁𝗶𝗼𝗻 𝗱𝗲𝗰𝗹𝗮𝗿𝗮𝘁𝗶𝗼𝗻𝘀 → callable before their declaration 𝟮. 𝗧𝗵𝗲 𝗦𝗰𝗼𝗽𝗲 𝗖𝗵𝗮𝗶𝗻 The scope chain is made possible by the outer environment property on an environment record. When the engine needs to find the value of a variable: • It looks in the current context • Then follows the outer environment • All the way up to the global context That traversal is the scope chain. 𝟯. 𝗖𝗹𝗼𝘀𝘂𝗿𝗲𝘀 A 𝗰𝗹𝗼𝘀𝘂𝗿𝗲 exists when a function retains access to its outer scope after that outer function has finished executing. Functions store a reference to the environment where they were created, preventing that environment from being garbage-collected. 𝗖𝗼𝗻𝗰𝗹𝘂𝘀𝗶𝗼𝗻 & 𝗞𝗲𝘆 𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆 The Execution Context is the heart of JavaScript. Its two-phase lifecycle and environment records are the foundation behind: • Hoisting • Scope • Closures #JavaScript #SoftwareEngineering #JS
To view or add a comment, sign in
-
-
JavaScript’s eval() — the feature everyone avoids, but few truly understand.. There’s a reason eval() has a bad reputation in JavaScript. But instead of just accepting “never use it”, I wanted to understand why. So I explored it—not for production use, but to understand how JavaScript actually thinks at runtime. What eval() really does At its core, eval() takes a string and executes it as JavaScript code in the current execution context. const x = 10; console.log(eval("x + 5")); // 15 This isn’t magic—it’s JavaScript dynamically injecting code into the engine’s execution phase. The real eye-opener: scope awareness What surprised me most is that direct eval has access to local scope: function testEval() { const secret = "hidden"; eval("console.log(secret)"); } testEval(); // "hidden" This single behavior explains both its power and its danger. It operates inside the scope chain, not outside it. Direct vs Indirect eval — a deep JS concept This distinction reveals how execution context is resolved: const x = 10; // Direct eval eval("x + 5"); // 15 // Indirect eval (0, eval)("x + 5"); // ReferenceError Indirect eval runs in the global scope, not the local one. This subtle difference says a lot about how JavaScript binds scope at runtime. Why JavaScript engines hate it. After experimenting, the concerns make total sense: Executes arbitrary code (huge security risk) Breaks JIT optimizations Defeats static analysis and makes debugging painful eval(userInput); // never trust runtime strings This is why linters, compilers, and senior engineers all warn against it. Does it have any valid use? In rare, tightly controlled scenarios—yes. For example, evaluating validated math expressions: function safeMath(expr) { if (!/^[0-9+\-*/() ]+$/.test(expr)) { throw new Error("Unsafe input"); } return eval(expr); } Even then, safer alternatives usually exist. My key takeaway Exploring eval() taught me far more than avoiding it ever could: How JavaScript resolves scope How execution contexts work Why some features exist even if we rarely use them How runtime behavior impacts performance and security Understanding what not to use is part of becoming a stronger engineer. I won’t use eval() in production—but I’m glad I understood it. Curiosity like this is what helps me write safer, more predictable JavaScript. #JavaScript #FrontendEngineering #WebDevelopment #JSInternals #LearningByDoing #SoftwareEngineering
To view or add a comment, sign in
-
How JavaScript’s sort() actually works Most developers use array.sort() regularly, but its internal behavior often surprises people. Here is a simple explanation: Default sorting is string-based When you call sort() without a compare function, JavaScript converts values to strings and compares them lexicographically. Example: ["100", "20", "5"].sort() → ["100", "20", "5"] This happens because "1" comes before "2" and "5" when compared as characters. For numeric sorting, always use a compare function Example: arr.sort((a, b) => a - b); This sorts based on numeric values and produces the correct order: [5, 20, 100]. JavaScript uses TimSort internally Modern JavaScript engines (like V8 in Chrome/Node.js) use TimSort, a hybrid algorithm that combines MergeSort and Insertion Sort. It is stable, efficient, and optimized for real-world data. Sorting happens in-place sort() modifies the original array instead of creating a new one, which is important when working with shared references. Key takeaway: Default sort → string comparison Numeric sort → provide a compare function Internally → TimSort Sorting → in-place A small but essential detail that helps avoid unexpected bugs and improves your understanding of the language.
To view or add a comment, sign in
-
Garbage Collection (GC) in JavaScript is often simplified to the notion that "JavaScript automatically frees memory." While this is true, it is an incomplete explanation. The essence of GC is that it removes memory that your program can no longer access. The core concept is straightforward: - If an object is reachable, it remains in memory. - If it is unreachable, it can be collected. Garbage Collection is based on reachability rather than whether you still "use" something conceptually. Here's a simplified overview of how the GC process works: - JavaScript maintains a set of roots, which include global variables, active function scopes, closures, and the call stack. - The GC starts from these roots and marks everything they reference. - Anything that cannot be reached from these roots is deemed garbage, and that memory is reclaimed. This method is known as mark-and-sweep, forming the foundation of modern JavaScript engines. A common misunderstanding arises with examples like: ```javascript let user = { name: "Kishor" }; user = null; ``` In this case, the object becomes unreachable and is eligible for GC. However, consider: ```javascript let cache = []; cache.push({ data: 123 }); ``` Even if you "stop using" that object, it remains reachable through the cache, preventing GC from removing it. This is a primary cause of memory leaks in JavaScript. Closures also play a significant role in memory management. They can extend the lifetime of memory; if a closure references a large object, that object stays in memory as long as the closure exists. This can be powerful but potentially dangerous if not properly understood. While GC is automatic, it is not without cost. It runs when the engine determines it can pause execution briefly, and large object graphs can make GC more resource-intensive. This is why long-running applications still require memory awareness. The key takeaway is that Garbage Collection does not prevent memory leaks; it only cleans up memory
To view or add a comment, sign in
-
💛 Creating Promises & Mastering Promise Chaining in JavaScript 🔗⚡ Now that we know what Promises are and why they exist, let’s go one level deeper 👇 👉 How do we create a promise? 👉 How does promise chaining actually work? 👉 What happens in real-world + edge cases? ♦️ How to Create a Promise 🛠️ A promise is created using the Promise constructor. const promise = new Promise((resolve, reject) => { // async operation if (success) { resolve(result); } else { reject(error); } }); 💡 Key points: ▪️ resolve() → fulfilled state ▪️ reject() → rejected state ▪️ Only one of them runs once ▪️ Promise becomes immutable ♦️ Simple Example const fetchData = new Promise((resolve, reject) => { setTimeout(() => { resolve("Data received"); }, 1000); }); Usage: fetchData.then(data => console.log(data)); ♦️ What Is Promise Chaining? 🔗 👉 Returning a value or a promise from .then() creates a chain. fetchUser() .then(user => getOrders(user.id)) .then(orders => getOrderDetails(orders)) .then(details => console.log(details)); ✔️ Each .then() waits for the previous one ✔️ Output becomes input for the next ♦️ Why Chaining Works 🧠 (Important Concept) .then() always returns a new promise then(() => value); // wrapped in Promise.resolve(value) then(() => promise); // waits for promise This is the foundation of chaining. ♦️ Handling Errors in Chains 🚨 ❌ Wrong Way (callback style) .then(data => { if (!data) { throw new Error("No data"); } }) ✅ Right Way (Promise chain) fetchData() .then(data => processData(data)) .then(result => saveData(result)) .catch(err => console.error(err)); 👉 Any error: ▪️ thrown ▪️ or rejected ➡️ skips all .then() ➡️ lands in nearest .catch() ♦️ Advanced Promise Chaining Scenarios 🔥 1️⃣ Returning a Value .then(res => res * 2) .then(val => console.log(val)); 👉 Value auto-wrapped in a promise 2️⃣ Returning a Promise .then(res => { return fetchDetails(res); }) .then(details => console.log(details)); 👉 Chain waits automatically 3️⃣ Conditional Chaining .then(res => { if (!res.isValid) { return Promise.reject("Invalid"); } return process(res); }) 🧠 Mental Model Promise chaining is: 👉 A controlled async pipeline 👉 Each step depends on previous output 👉 Errors flow automatically 🥇 Interview One-Liner Promise chaining works because .then() always returns a new promise, allowing values or async operations to flow sequentially with centralized error handling. Please Check This blog for more detailed Explanation 👇 🔗https://lnkd.in/gHvu3qGu If this helped, drop a 💛 or share 🔁 Next deep dive 👉 async/await — Internals & Error Handling 🔥
To view or add a comment, sign in
-
-
𝗪𝗲𝗹𝗹-𝗞𝗻𝗼𝘄𝗻 𝗦𝘆𝗺𝗯𝗼𝗹𝘀 𝗮𝗻𝗱 𝗧𝗵𝗲𝗶𝗿 𝗔𝗽𝗽𝗹𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀 JavaScript has evolved over time. One major update was the introduction of Symbols in ECMAScript 2015. Well-Known Symbols provide a unique way to define behavior and properties in JavaScript. To understand Well-Known Symbols, you need to know what symbols are. Before ECMAScript 5, JavaScript did not have a way to create private object properties. Developers used tricks like prefixes or closures to manage uniqueness. Here are some key Well-Known Symbols: - Symbol.hasInstance: customizes the behavior of the instanceof operator - Symbol.isConcatSpreadable: determines if an object should be flattened when using Array.prototype.concat - Symbol.iterator: defines the default iterator for an object - Symbol.match: specifies a function used for pattern matching with regex - Symbol.replace: customizes the behavior of String.prototype.replace - Symbol.search: customizes the behavior of String.prototype.search - Symbol.split: determines how String.prototype.split performs on an object You can use Symbol.hasInstance to define custom behaviors for the instanceof operator. For example: class MyArray { static [Symbol.hasInstance](instance) { return Array.isArray(instance) && instance.length > 0; } } You can also use Symbol.iterator to define object iteration. For example: class Fibonacci { constructor() { this.current = 0; this.next = 1; } [Symbol.iterator]() { return this; } next() { const current = this.current; [this.current, this.next] = [this.next, this.current + this.next]; return { value: current, done: false }; } } Well-Known Symbols can streamline code and improve architecture. However, they can also affect performance if used excessively. Source: https://lnkd.in/d_8if4qz
To view or add a comment, sign in
-
Code Reviewing AI-Generated JavaScript: What I Found - Part 1 What I learned reviewing AI-generated JavaScript: real-world issues, code review tips, and ways to ensure robust, production-ready code. https://lnkd.in/d_A-TttG #codingwithai
To view or add a comment, sign in
-
JavaScript Promises are not just syntax. They are a way to manage TIME in JavaScript. Let’s break it down clearly 👇 🔹 What is a Promise? A Promise is an object that represents the eventual result of an asynchronous operation. That result can be: • successful • failed • or still waiting Think of a Promise as a “future value”. --- 🔹 Promise States (VERY IMPORTANT) A Promise has exactly THREE states: 1️⃣ Pending → Initial state → Neither fulfilled nor rejected 2️⃣ Fulfilled → Operation completed successfully → A value is available 3️⃣ Rejected → Operation failed → An error reason is available A promise can change state ONLY ONCE. --- 🔹 Creating a Promise const promise = new Promise((resolve, reject) => { const success = true; if (success) { resolve("Data received"); } else { reject("Something went wrong"); } }); --- 🔹 Consuming a Promise promise .then(data => { console.log(data); }) .catch(error => { console.log(error); }); • `.then()` → runs when fulfilled • `.catch()` → runs when rejected --- 🔹 Important Rule (Many Miss This) Promises themselves are NOT async. The callbacks registered by `.then()` and `.catch()` run asynchronously as MICROTASKS. That’s why: Promise.resolve().then(() => console.log("Promise")); setTimeout(() => console.log("Timeout"), 0); Output: Promise Timeout Promises have higher priority than timers. --- 🔹 Promise Chaining Promises can be chained to avoid callback hell. fetch("/api") .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.error(err)); Each `.then()` returns a NEW promise. --- 🔹 Promise Utilities (Common Interview Topic) • Promise.all() → waits for ALL promises → fails if ANY fails • Promise.allSettled() → waits for ALL → never fails • Promise.race() → resolves/rejects with the FIRST result • Promise.any() → resolves with FIRST fulfilled promise --- 🔹 async / await (Promise Syntax Sugar) async function loadData() { try { const data = await fetch("/api"); console.log(data); } catch (err) { console.error(err); } } `await` pauses the function. The rest runs as a microtask. --- 🔹 Common Mistakes ❌ Assuming promises run immediately ❌ Forgetting error handling ❌ Mixing callbacks and promises ❌ Not returning promises in `.then()` --- 🔹 Mental Model (Senior-Level) 1️⃣ Create a promise 2️⃣ Promise settles (fulfilled/rejected) 3️⃣ `.then()` / `.catch()` queued as microtasks 4️⃣ Event Loop decides execution --- 🔹 Why Promises Matter for Frontend Developers • Data fetching • React side effects • Performance optimization • Predictable async logic Frameworks depend heavily on promises. --- Once you truly understand promises, async code becomes predictable. Follow me for more **ultra-clear JavaScript & frontend explanations**🚀 #javascript #frontend #webdevelopment #interview
To view or add a comment, sign in
-
JavaScript usually feels fine until the same function suddenly behaves differently, and nothing makes sense. 👀 The code looks identical, nothing was touched, and yet the result changed. Frustration usually shows up right there. Not because of broken logic, but because 'this' isn't what it looked like. 🎭 And that's the tricky part. It's not a syntax problem; it's about execution context. In JavaScript, 'this' isn't locked in when the function is written. Its value is determined when the function runs. Change how it's called, and the behavior shifts with it. Same code, different call. Once that clicks, those "why is this undefined?" moments stop feeling random. They start feeling predictable. 🧠 The confusion fades because there's finally a mental model behind it. So here's the question worth pausing on: When exactly does JavaScript decide what 'this' points to? This is where it starts to feel obvious: https://lnkd.in/dWpngz9z
To view or add a comment, sign in
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development