AlixPartners Flashcards

(81 cards)

1
Q

What is the V8 engine in the context of JavaScript?

A

It’s a JavaScript engine developed by Google that makes JavaScript run fast, especially in Chrome and on servers like Node.js.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Is JavaScript single-threaded or multi-threaded?

A

JavaScript is single-threaded.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What does JavaScript use to handle asynchronous operations?

A

A callback queue.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Is JavaScript interpreted or compiled?

A

It’s often referred to as an interpreted language, though modern engines compile parts of it at runtime.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Can a computer understand JavaScript directly?

A

No, computers understand only binary (ones and zeros), so JavaScript must be translated.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What role does a JavaScript engine play?

A

It acts as a translator that turns JavaScript code into machine-understandable instructions.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Name three JavaScript engines besides V8.

A

SpiderMonkey, Chakra, and JavaScriptCore.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What language is the V8 engine written in?

A

C++.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Why did Google develop the V8 engine?

A

To improve the performance of JavaScript-heavy applications like Google Maps in their Chrome browser.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What happened in 2008 related to JavaScript performance?

A

Google released the V8 engine, significantly improving JavaScript speed in browsers.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Why are JavaScript engines crucial for modern computing?

A

They make JavaScript run efficiently on browsers, servers, and various devices.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q
A
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What does the JavaScript engine do with your JavaScript code?

A

It processes the code and translates it into instructions that the computer can understand and execute.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

What is the V8 engine written in?

A

C++, a low-level programming language.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What is the first step the JavaScript engine takes when processing code?

A

Lexical analysis — it breaks the code into tokens.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What is an Abstract Syntax Tree (AST)?

A

A tree-like structure created from tokens that represents the structure of the code.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

What tool can visualize an AST?

A

AST Explorer (https://astexplorer.net).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

What happens after the AST is created?

A

The code passes through an interpreter, a profiler, and a compiler.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

What is the final output of the JavaScript engine’s process?

A

CPU-understandable machine code that can be executed.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Can anyone create their own JavaScript engine?

A

Yes, technically anyone can, though it’s complex and requires deep programming knowledge.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

What is a simple analogy for what a JS engine does?

A

It breaks code into parts like a sentence and understands what each part means (e.g., variables, functions).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

What basic technique can simulate a simple JS engine in code?

A

Writing a function that splits a string of code and interprets parts like variable declarations.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

What is the purpose of lexical analysis in a JS engine?

A

To identify the meaningful parts (tokens) of the code.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Why is the process more complex than just splitting strings?

A

Real JS engines handle syntax rules, performance optimizations, and many edge cases.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
What are the two main ways programming languages like JavaScript get translated into machine code?
Through **interpreters** and **compilers**. Interpreters translate code **line-by-line on the fly** as the program runs, while compilers **analyze and translate the whole code ahead of time** into a lower-level language (like machine code) that the computer can understand and execute directly.
26
How does an interpreter work when running JavaScript code?
An interpreter processes the code **sequentially** — reading and executing one line at a time. It doesn’t produce a separate machine-language file. Instead, it reads the source, interprets it, and runs it immediately, making it easy to test and debug but generally slower in performance because it repeatedly processes the same lines during loops or repeated calls.
27
What does a compiler do differently than an interpreter?
A compiler **analyzes the entire program in advance**, understands what it's supposed to do, and translates it into **another lower-level language**, such as machine code. This results in a separate executable program that can run much faster, as the translation step is already done before execution.
28
Why is it said that all languages are both interpreted and compiled in some way?
Because ultimately, **all code must be translated into machine instructions** that a CPU understands. High-level code might first be **compiled** into bytecode or machine code, but even that code must eventually be **interpreted** or further compiled by the CPU (often into microcode). So in reality, modern execution involves **layers** of both interpretation and compilation.
29
What’s the final takeaway about interpreters vs. compilers in JavaScript engines?
Both interpreters and compilers play essential roles. JavaScript engines often use a **hybrid approach**, where an interpreter starts executing code quickly, and a compiler (like Just-In-Time, or JIT) **optimizes** parts of the code on the fly for better performance. This balances **speed of startup** with **runtime efficiency**.
30
31
What is the benefit of interpreters?
Interpreters are known for their speed when it comes to getting started. They don't require a separate compilation step and execute code line-by-line, making them ideal for languages like JavaScript in web environments where responsiveness is critical. ## Footnote For example, when JavaScript is sent from a server to a user's browser, it needs to execute immediately to make the webpage interactive without delay.
32
Why was JavaScript originally designed to use interpreters?
JavaScript was originally designed to run in browsers, where speed and responsiveness were crucial. Interpreters execute code right away without needing to convert it into another language first, making them a perfect fit for dynamic web applications.
33
What is a major drawback of interpreters?
One major drawback of interpreters is performance, especially with repeated operations. When the same piece of code runs many times, the interpreter must re-interpret each time, leading to slower execution compared to compiled code.
34
How do compilers optimize repeated code?
Compilers translate the entire program into machine code before execution, allowing them to apply optimizations. For instance, if a function is run in a loop and always returns the same result, a compiler can replace repeated function calls with the final output directly.
35
What are the trade-offs between compilers and interpreters?
Compilers take longer to start because they must analyze and convert the entire codebase into machine code, resulting in optimized and faster code. Interpreters start quickly for immediate execution but do not optimize the code, leading to slower performance over time.
36
What is the role of JIT compilers?
To balance the strengths and weaknesses of both interpreters and compilers, engineers developed Just-In-Time (JIT) compilers. JIT compilers, like those in the V8 engine, begin by interpreting code for quick startup, then compile and optimize parts of the code while it's running.
37
How does the V8 engine use Ignition and TurboFan?
The V8 engine in Chrome uses a hybrid approach. It first sends code through an interpreter called Ignition, which turns it into bytecode for quick execution. While the code runs, a profiler identifies frequently-used sections, which are passed to a JIT compiler called TurboFan for optimization.
38
What is bytecode in the context of V8?
Bytecode is an intermediate representation of the code that is more abstract than machine code but easier to run than raw JavaScript. Ignition generates this bytecode, which TurboFan then optimizes based on insights from the profiler.
39
What is the role of the profiler in the optimization process?
In the V8 engine, the profiler monitors how the code runs, observing function usage, data types, and bottlenecks. This information helps the JIT compiler decide which parts of the code should be optimized into faster machine code.
40
What is de-optimization and its impact?
De-optimization occurs when the JIT compiler must undo optimizations due to incorrect assumptions about code behavior. This process reverts the machine code back to the original interpreted version, which can slow down performance.
41
Why is understanding V8 important for developers?
Knowing how the JavaScript engine works allows developers to write more efficient and predictable code. Understanding the interplay of interpreters, compilers, and profilers in the V8 engine helps developers structure programs to leverage JIT optimizations.
42
Why Learning About Compiler Optimizations Matters
Understanding how the JavaScript engine works, particularly how the compiler optimizes code, is critical for writing efficient programs. As developers, we want to write code that helps the engine make optimizations, not code that works against it. By following best practices, we can ensure our code runs faster and is more maintainable, especially as projects grow in complexity.
43
Common JavaScript Features That Hurt Performance
There are specific JavaScript features that can interfere with compiler optimizations. These include: * `eval()` – Executes code from a string, which makes code unpredictable and difficult to optimize. * `arguments` – The special object in functions can confuse the compiler and prevent optimization. * `for...in` loops – Especially when used to iterate over objects, they can be slow and unpredictable. * `with` statements – Rarely used today, but they obscure variable scopes and are hard to optimize. * `delete` keyword – Removing properties from objects changes their internal structure, which breaks compiler assumptions.
44
What Is Inline Caching and Why It Improves Performance
Inline caching is a performance technique used by JavaScript engines like V8 to speed up repeated method calls or property access. For example, if a function repeatedly accesses `user.firstName`, the engine remembers the location of `firstName` in memory. Instead of looking it up each time, it can 'inline' the result.
45
How Inline Caching Works in Practice
Suppose you have a function `findUser(user)` that returns a string using `user.firstName`. If you call this function multiple times with similar objects, the engine optimizes it by caching the memory address of `firstName`. It no longer has to search the object structure each time.
46
What Are Hidden Classes in JavaScript Engines
Hidden classes are internal representations that JavaScript engines use to optimize objects. When two objects are created with the same structure and property order, the engine assumes they are the same 'class' under the hood. This allows the engine to apply optimizations such as fast property access.
47
How Hidden Classes Can Slow Down Your Code
If you create two objects using the same constructor function but assign properties to them in a different order, the JavaScript engine sees them as having different hidden classes. This prevents certain optimizations because it breaks the assumption that the objects are structurally identical.
48
Best Practices for Maintaining Hidden Class Consistency
To help the JavaScript engine keep hidden classes consistent: * Always initialize all object properties inside the constructor function. * Avoid adding new properties after object creation. * Add properties in the same order across all instances. * Avoid deleting properties once objects are created.
49
Why Predictability Matters for Performance
Predictable code is not just easier for humans to read—it's easier for compilers to optimize. When the JavaScript engine encounters code that behaves consistently, it can apply powerful performance enhancements like inline caching and shared hidden classes.
50
You Don’t Need to Optimize Everything Manually
While understanding compiler optimizations is valuable, you don’t need to obsess over every detail. Most of the time, simply following best practices—like initializing properties in constructors and avoiding discouraged features—will naturally lead to fast, maintainable code.
51
Compiler Optimization Summary and Developer Mindset
In modern JavaScript development, you don’t always need to think about inline caching or hidden classes explicitly. But having a general awareness of how compilers work helps you make smarter choices. It’s about adopting a mindset that prioritizes clarity, consistency, and structure.
52
Why can't JavaScript be compiled to machine code ahead of time like other languages, and how is this changing?
JavaScript can't be precompiled to machine code because it must run in different browsers, and early on (especially in 1995), browsers couldn’t agree on a single binary format and compilation was too slow. Each browser had its own engine and no shared executable standard. However, WebAssembly is changing this by providing a standardized, fast, binary format for the web that all modern browsers support—making ahead-of-time compilation feasible and potentially faster.
53
Why haven't topics like interpreters and compilers been the main focus until now? What shift happens in this section of the course?
Until now, the course covered foundational concepts like interpreters and compilers, which are useful for understanding how JavaScript runs under the hood but don't frequently appear in day-to-day coding or job interviews. Starting in this section, the focus shifts to crucial JavaScript internals like the call stack and memory heap—core concepts that are not only foundational to the language but also show up repeatedly throughout a JavaScript developer’s career and interviews.
54
What are the call stack and memory heap in JavaScript, and why are they important?
The call stack and memory heap are two critical components of the JavaScript engine. The memory heap is where memory allocation happens—it stores variables, objects, and data for the app. The call stack, on the other hand, keeps track of the point of execution in your code—what function is currently running and where to return after it completes. Together, they enable JavaScript to read, write, and execute code in the correct order.
55
What happens when we declare a variable in JavaScript in terms of memory management?
When you declare a variable, such as const number = 610, the JavaScript engine allocates memory in the memory heap for that variable and points it to the actual value stored. For example, with const string = "Hello", the engine stores "Hello" in memory and the variable string references it. For objects, memory is allocated for each property and value, and the variable pointing to the object references that memory location.
56
What is the call stack and how does it behave during function execution?
The call stack is a region in memory that keeps track of function calls in a Last-In, First-Out (LIFO) manner. When a function is invoked, it’s pushed onto the stack. Once the function completes, it’s popped off the stack. This helps JavaScript track where it is during execution. For example, if function A() calls function B(), B gets pushed on top of A. When B completes, it’s removed, and the engine continues executing A.
57
Can you describe what happens in the call stack during nested function calls using an example?
Yes. Suppose we have two functions: calculate() and subtractTwo(num). Inside calculate, we call subtractTwo(sumTotal). Here's what happens: 1. calculate is called → it's pushed onto the stack. 2. Inside calculate, subtractTwo is called → it's pushed on top. 3. subtractTwo returns → it's popped off the stack. 4. Execution continues in calculate → it then completes and is popped off. 5. The program returns to the global execution context. This nesting is like "Inception"—functions within functions—tracked cleanly by the stack.
58
What is the global execution context, and how is it represented in the call stack?
The global execution context is the default context in which any JavaScript code runs. In the call stack, it's typically the first item and is labeled as "anonymous" if the script file has no name. It represents the outermost environment and stays at the bottom of the stack throughout execution. All functions are stacked on top of this global context during program execution.
59
What is the difference between the memory heap and the call stack in JavaScript?
The memory heap is an unordered region for storing objects, variables, and data. It’s where memory is dynamically allocated and managed (allocation, use, garbage collection). The call stack is a structured stack that tracks function execution order using a LIFO system. It ensures that JavaScript knows what to execute next and where to return once a function completes. While the heap stores data, the stack manages the execution flow.
60
What happens in the call stack when a function calls another function before completing?
When a function A calls another function B, before A finishes, JavaScript pauses A, pushes B onto the call stack, and starts executing B. Once B returns, it's popped off, and execution resumes in A. This stacking ensures functions execute in the correct order and return to the right place, like a well-organized to-do list.
61
How do JavaScript engines handle memory for simple variables versus complex structures?
Simple values (like numbers or booleans) are often stored directly on the stack for fast access. Complex structures like objects, arrays, and functions are stored in the memory heap. The stack holds references (pointers) to these heap allocations. This separation improves performance and supports efficient memory management through techniques like garbage collection.
62
Why are the call stack and memory heap considered universal concepts across programming languages?
Most programming languages implement a call stack and memory heap to manage function execution and data storage, respectively. While implementations vary, the underlying principles are consistent. These structures help organize code flow and memory management, which are fundamental to any language that supports functions and dynamic memory allocation, including JavaScript, Python, C++, and Java.
63
Stack Overflow
When functions continuously call themselves or are deeply nested (e.g., a function calling another which calls another, and so on), the call stack keeps growing. Each function call is added to the stack, and unless one returns, the stack keeps building up. If this continues indefinitely, it leads to a Stack Overflow—a condition where the call stack exceeds its limit. This can happen through recursion, where a function calls itself, such as in the example: function inception() { inception(); } Running this function keeps pushing inception() onto the stack repeatedly, eventually causing a "Maximum call stack size exceeded" error. JavaScript then prints a stack trace, showing each call entry that led to the error. This trace helps developers debug where the stack overflow occurred. Modern browsers like Chrome now display this error to prevent crashes. Historically, the browser would just freeze or crash with no helpful message.
64
What is garbage collection in JavaScript and why should developers still care about memory management?
JavaScript is a garbage-collected language, meaning it automatically allocates and frees memory. When you create objects (e.g., inside a function), they are stored in the memory heap. If nothing references an object anymore, JavaScript’s garbage collector will eventually remove it to free up space. It uses the Mark-and-Sweep algorithm: Mark: Traverse all variables and mark objects that are still referenced. Sweep: Remove any objects that weren’t marked (i.e., no longer in use). Example: js Copy Edit var human = { name: "Bobby" }; human = 5; // Now the original object is unreferenced and eligible for garbage collection While garbage collection is automatic, it isn’t perfect. Developers can still accidentally create memory leaks (e.g., keeping unused objects referenced) which fill up memory over time—just like stack overflow, but in the heap. Compared to lower-level languages like C (where developers manually manage memory), JavaScript provides convenience, but can give a false sense of security. It's still crucial to understand memory behavior to avoid performance issues.
65
Memory leaks
Memory leaks happen when unused memory isn’t released. Common causes: Global variables: Unintentionally declared globals stay in memory. Event listeners: Not removed when no longer needed. setInterval: Runs forever if not cleared. Fix: Clean up unused variables, listeners, and intervals to avoid crashes and slowdowns. SoundCloud had a memory leak in its JavaScript app on a gaming device. Because users left the app running in the background for hours, unused memory piled up, revealing a leak. They had to refactor the app to prevent long-term background memory buildup. Forgotten Event Listeners Adding event listeners (e.g., element.addEventListener('click', handler)) without removing them later keeps references alive—even if the DOM elements are removed. Uncleared setInterval Calls If you use setInterval() but never call clearInterval(), referenced objects stay in memory, causing leaks.
66
What does it mean that JavaScript is single-threaded?
JavaScript can only run one task at a time because it has a single call stack. It runs code synchronously, step by step — like eating with one hand: chew, then grab more food.
67
What is the "call stack" (pila de ejecución) in JavaScript and why is it important?
The call stack is a fundamental concept in JavaScript that refers to a data structure used by the JavaScript engine to keep track of function calls. It works like a stack of plates: the last function that is called is placed on top, and the first one to finish is the last one added. This structure is also known as LIFO (Last In, First Out). The call stack is important because it explains why JavaScript is single-threaded and how it handles function execution order. Only the function at the top of the stack can be executed at any given time, which is why JavaScript can only do one thing at a time.
68
What kind of information is stored in the call stack for each function?
Each function call creates a "frame" (also known as a record or context) that includes several pieces of information: The name of the function being executed. The line of code where the function was called. The file name where it lives. The execution context, which includes: Local variables. The this keyword (which refers to the object owning the function). The arguments object (a pseudo-array with the function parameters). These frames are pushed onto the stack as functions are called and popped off once they return or complete execution.
69
How does JavaScript handle nested or recursive function calls in the call stack?
Every time a function is called—even if it's the same function (like in recursion)—a new frame is added to the call stack. This frame is independent and contains its own execution context. For example, in a recursive function like mixIngredients(n), a new frame is created each time the function calls itself. These frames stack up until the base case is reached (e.g., n === 0). Then, as each function completes, its frame is removed (popped) from the stack, and control returns to the previous one. If there's no base case or a condition to stop the recursion, the call stack will keep growing until it hits the browser's maximum limit, resulting in a "Maximum call stack size exceeded" error.
70
What are "scopes" in JavaScript and how are they related to the call stack?
Scopes define the visibility and lifetime of variables. Every time a function is called and a frame is added to the call stack, a new scope is also created for that function. The scope contains: Local variables. Access to outer (parent) scopes. Special variables like this and arguments. In modern browsers’ developer tools, you can inspect the current function's scope by pausing execution (e.g., via a breakpoint) and looking under the "Scope" tab, which shows both local scope (variables defined inside the function) and global scope (available throughout the script).
71
What is the purpose of using breakpoints and how do they help understand the call stack?
Breakpoints are developer tool features that pause program execution at specific lines of code. When a breakpoint is hit, you can: Inspect the call stack to see the order of function calls. Check the values of variables in the current scope. Use step controls to move through execution line by line and observe how the stack changes. This allows developers to understand how their code is executed, identify where bugs occur, and see the exact flow of function calls and returns.
72
What happens when an error is thrown in JavaScript and how is it reflected in the call stack?
When an error occurs in a JavaScript program, an exception is thrown, and JavaScript provides a stack trace, which is essentially a snapshot of the current call stack at the moment of the error. This stack trace tells you: Which functions were called leading up to the error. The exact lines and files where those calls happened. This is extremely useful for debugging, as it lets you trace the chain of events that caused the problem.
73
How does the JavaScript engine prevent infinite recursion or excessive stack growth?
JavaScript engines define a maximum stack size limit to prevent a program from crashing the browser or the system. If a function keeps calling itself without a base case (infinite recursion), the call stack grows indefinitely until it reaches this limit. At that point, the engine throws an error: RangeError: Maximum call stack size exceeded This is a safety feature to ensure poorly written code doesn’t freeze the system. Developers must ensure that recursive functions include proper exit conditions.
74
Primitive Types in JavaScript
Primitive types are the most basic building blocks in JavaScript. They are immutable and copied by value, meaning when you assign them, the actual value is copied, not a reference. JavaScript has 7 primitive types: string – Text, e.g., 'hello' number – All numbers (integers, floats), e.g., 42 boolean – true or false undefined – A variable declared but not assigned null – Represents intentional "no value" bigint – For arbitrarily large integers, e.g., 123n symbol – Unique identifiers, often for object keys ✅ Primitive values are stored directly in memory.
75
Reference Types in JavaScript
Reference types include all non-primitive objects, like: Objects: { name: 'Alice' } Arrays: [1, 2, 3] Functions: function() {} Others: Map, Set, Date, RegExp, etc. ➡️ These are copied by reference, meaning when you assign them to another variable or pass them into a function, both variables point to the same underlying object in memory. ⚠️ Mutating one affects the other.
76
Type Checking in JavaScript
There are several ways to check types: typeof – For primitives and functions Examples: typeof "hi" → "string" typeof 5 → "number" typeof null → "object" (a legacy bug) typeof [] → "object" (arrays are objects too) Array.isArray() – Specifically checks for arrays Array.isArray([1,2,3]) → true instanceof – Checks prototype inheritance x instanceof Date → true if x is a Date object 🔎 Be cautious with typeof when dealing with objects and nulls.
77
== vs === and Type Coercion
== is the loose equality operator. It compares values but coerces types if they differ. === is the strict equality operator. It compares both value and type, with no coercion. 📌 Examples: js Copy Edit '5' == 5 // true (type coercion happens) '5' === 5 // false (different types) 0 == false // true (type coercion) 0 === false // false (number vs boolean) ✅ Use === for more predictable and bug-free comparison
78
null vs undefined
undefined means a variable has been declared but has no value assigned. null is an intentional absence of value, assigned by the developer. 📌 Examples: js Copy Edit let x; // x is undefined let y = null; // y is explicitly set to have "no value" ➡️ typeof undefined → "undefined" ➡️ typeof null → "object" (this is a historical bug) Both are falsy, but they are not equal in type: js Copy Edit null == undefined // true null === undefined // false
79
Deep Copy vs Shallow Copy
Shallow copy duplicates only the top-level structure. Nested objects still share the same references. Deep copy recursively copies all levels, including nested structures. 📌 Shallow Copy: let original = { a: 1, b: { c: 2 } }; let shallow = { ...original }; shallow.b.c = 42; console.log(original.b.c); // 42 (shared reference) 📌 Deep Copy: let deep = structuredClone(original); // or use JSON: let deep2 = JSON.parse(JSON.stringify(original)); deep.b.c = 99; console.log(original.b.c); // Still 2 ✅ Use deep copy when you want true independence from the original object
80
JavaScript Type Coercion Rules
JavaScript automatically converts types when using loose equality (==), mathematical operations, or in boolean contexts. 🧠 Key coercion rules: Strings and numbers: '5' == 5 → true (string '5' becomes number 5) Booleans in math: true + 1 → 2 (true becomes 1) null and undefined: null == undefined → true null == 0 → false Objects to primitives: [1] == 1 → true (array [1] becomes '1' → number 1) [] == false → true (empty array becomes '' → 0) 📌 Use === to avoid surprises from coercion.
81