485 lines
11 KiB
Markdown
485 lines
11 KiB
Markdown
# Lesson 00: Getting Started & Assessment Review
|
||
|
||
**Duration:** 45 minutes
|
||
**Objective:** Understand JavaScript fundamentals and identify key areas for focused study
|
||
|
||
---
|
||
|
||
## Introduction
|
||
|
||
Welcome to your JavaScript interview preparation curriculum! This lesson reviews the diagnostic assessment and establishes foundational knowledge that will be built upon in subsequent lessons.
|
||
|
||
Based on common evaluation results, most developers need focused review in:
|
||
- Type coercion and equality
|
||
- Closures and scope
|
||
- The `this` keyword and context binding
|
||
- Prototypes and inheritance
|
||
- Modern ES6+ syntax
|
||
- Asynchronous execution patterns
|
||
|
||
---
|
||
|
||
## Part 1: JavaScript Type System Fundamentals
|
||
|
||
### 1.1 Primitive Types
|
||
|
||
JavaScript has 7 primitive types:
|
||
|
||
```javascript
|
||
typeof undefined; // "undefined"
|
||
typeof true; // "boolean"
|
||
typeof 42; // "number"
|
||
typeof 9007199254740991n; // "bigint"
|
||
typeof "hello"; // "string"
|
||
typeof Symbol(); // "symbol"
|
||
typeof null; // "object" ⚠️ This is a bug in JavaScript!
|
||
```
|
||
|
||
**The `null` Bug:**
|
||
`typeof null` returning `"object"` is a historical bug that can't be fixed without breaking existing code. `null` represents the intentional absence of any object value.
|
||
|
||
```javascript
|
||
// Checking for null correctly
|
||
const value = null;
|
||
console.log(value === null); // true
|
||
console.log(typeof value === "object" && value === null); // true
|
||
```
|
||
|
||
### 1.2 Reference Types
|
||
|
||
Objects, Arrays, and Functions are reference types:
|
||
|
||
```javascript
|
||
typeof {}; // "object"
|
||
typeof []; // "object" (arrays are objects)
|
||
typeof function(){}; // "function"
|
||
```
|
||
|
||
**Key Difference:**
|
||
- **Primitives** are compared by value
|
||
- **References** are compared by reference (memory location)
|
||
|
||
```javascript
|
||
// Primitives - value comparison
|
||
const a = 42;
|
||
const b = 42;
|
||
console.log(a === b); // true
|
||
|
||
// References - memory location comparison
|
||
const arr1 = [1, 2, 3];
|
||
const arr2 = [1, 2, 3];
|
||
console.log(arr1 === arr2); // false (different objects in memory)
|
||
console.log(arr1 === arr1); // true (same reference)
|
||
|
||
const arr3 = arr1;
|
||
console.log(arr3 === arr1); // true (same reference)
|
||
```
|
||
|
||
---
|
||
|
||
## Part 2: Floating-Point Precision
|
||
|
||
### 2.1 The 0.1 + 0.2 Problem
|
||
|
||
JavaScript uses IEEE 754 double-precision floating-point format. Some decimal numbers cannot be represented exactly in binary.
|
||
|
||
```javascript
|
||
console.log(0.1 + 0.2); // 0.30000000000000004
|
||
console.log(0.1 + 0.2 === 0.3); // false ⚠️
|
||
```
|
||
|
||
**Why?**
|
||
- 0.1 in binary: `0.0001100110011...` (repeating)
|
||
- Computer must round, introducing tiny errors
|
||
- These errors accumulate during operations
|
||
|
||
**Solutions:**
|
||
|
||
```javascript
|
||
// 1. Use epsilon comparison
|
||
function areClose(a, b, epsilon = 0.0001) {
|
||
return Math.abs(a - b) < epsilon;
|
||
}
|
||
console.log(areClose(0.1 + 0.2, 0.3)); // true
|
||
|
||
// 2. Use Number.EPSILON
|
||
console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON); // true
|
||
|
||
// 3. Work with integers (convert to cents, etc.)
|
||
const price1 = 10; // 10 cents
|
||
const price2 = 20; // 20 cents
|
||
const total = price1 + price2; // 30 cents (exact)
|
||
|
||
// 4. Round to fixed decimals
|
||
const result = Math.round((0.1 + 0.2) * 100) / 100; // 0.3
|
||
```
|
||
|
||
**Interview Tip:** Always mention this caveat when working with money or precise calculations. Suggest using integers or decimal libraries.
|
||
|
||
---
|
||
|
||
## Part 3: Var, Let, and Const
|
||
|
||
### 3.1 The Problem with `var`
|
||
|
||
```javascript
|
||
// Function scope (not block scope)
|
||
function example() {
|
||
if (true) {
|
||
var x = 5;
|
||
}
|
||
console.log(x); // 5 (var leaks out of the block!)
|
||
}
|
||
|
||
// Hoisting
|
||
console.log(y); // undefined (not an error!)
|
||
var y = 10;
|
||
|
||
// What actually happens:
|
||
var y;
|
||
console.log(y); // undefined
|
||
y = 10;
|
||
```
|
||
|
||
**The Classic Loop Problem:**
|
||
|
||
```javascript
|
||
for (var i = 0; i < 3; i++) {
|
||
setTimeout(() => console.log(i), 100);
|
||
}
|
||
// Logs: 3, 3, 3
|
||
// Why? All callbacks share the same 'i' variable
|
||
// By the time they execute, the loop finished and i = 3
|
||
```
|
||
|
||
### 3.2 Let and Const (ES6+)
|
||
|
||
```javascript
|
||
// Block scope
|
||
if (true) {
|
||
let x = 5;
|
||
const y = 10;
|
||
}
|
||
console.log(x); // ReferenceError
|
||
console.log(y); // ReferenceError
|
||
|
||
// No hoisting issues
|
||
console.log(z); // ReferenceError (temporal dead zone)
|
||
let z = 15;
|
||
|
||
// Loop with let creates a new binding per iteration
|
||
for (let i = 0; i < 3; i++) {
|
||
setTimeout(() => console.log(i), 100);
|
||
}
|
||
// Logs: 0, 1, 2 ✅
|
||
```
|
||
|
||
**Const Rules:**
|
||
|
||
```javascript
|
||
const x = 10;
|
||
x = 20; // TypeError: Assignment to constant variable
|
||
|
||
// But objects are mutable!
|
||
const obj = { name: "Alice" };
|
||
obj.name = "Bob"; // ✅ Allowed (modifying property)
|
||
obj = {}; // ❌ TypeError (reassigning variable)
|
||
|
||
// Use Object.freeze() for immutability
|
||
const frozen = Object.freeze({ name: "Alice" });
|
||
frozen.name = "Bob"; // Silently fails (throws in strict mode)
|
||
console.log(frozen.name); // "Alice"
|
||
```
|
||
|
||
**Best Practice:** Use `const` by default, `let` when you need reassignment, avoid `var`.
|
||
|
||
---
|
||
|
||
## Part 4: Array Behavior and Holes
|
||
|
||
### 4.1 Sparse Arrays
|
||
|
||
```javascript
|
||
const arr = [1, 2, 3];
|
||
arr[10] = 11;
|
||
|
||
console.log(arr.length); // 11 (not 4!)
|
||
console.log(arr); // [1, 2, 3, empty × 7, 11]
|
||
console.log(arr[5]); // undefined (hole in array)
|
||
```
|
||
|
||
**Array Length:**
|
||
- Length is always the highest index + 1
|
||
- Creating holes doesn't initialize elements
|
||
|
||
```javascript
|
||
const sparse = new Array(5);
|
||
console.log(sparse.length); // 5
|
||
console.log(sparse[0]); // undefined
|
||
console.log(0 in sparse); // false (hole, not undefined value)
|
||
|
||
const filled = [undefined, undefined];
|
||
console.log(0 in filled); // true (actual undefined value)
|
||
```
|
||
|
||
**Array Methods and Holes:**
|
||
|
||
```javascript
|
||
const arr = [1, , 3]; // Array with hole
|
||
|
||
arr.forEach(x => console.log(x)); // 1, 3 (skips holes)
|
||
arr.map(x => x * 2); // [2, empty, 6] (preserves holes)
|
||
Array.from(arr); // [1, undefined, 3] (converts holes)
|
||
```
|
||
|
||
---
|
||
|
||
## Part 5: Type Coercion Essentials
|
||
|
||
### 5.1 Truthy and Falsy Values
|
||
|
||
**Falsy values** (8 total):
|
||
```javascript
|
||
if (false) {} // false
|
||
if (0) {} // 0
|
||
if (-0) {} // -0
|
||
if (0n) {} // 0n (BigInt zero)
|
||
if ("") {} // empty string
|
||
if (null) {} // null
|
||
if (undefined) {} // undefined
|
||
if (NaN) {} // NaN
|
||
```
|
||
|
||
Everything else is **truthy**, including:
|
||
```javascript
|
||
if ("0") {} // truthy (non-empty string)
|
||
if ("false") {} // truthy
|
||
if ([]) {} // truthy (empty array)
|
||
if ({}) {} // truthy (empty object)
|
||
if (function(){}) {} // truthy
|
||
```
|
||
|
||
### 5.2 Unary Plus Operator
|
||
|
||
```javascript
|
||
console.log(+"42"); // 42
|
||
console.log(+"3.14"); // 3.14
|
||
console.log(+"hello"); // NaN
|
||
console.log(+true); // 1
|
||
console.log(+false); // 0
|
||
console.log(+null); // 0
|
||
console.log(+undefined); // NaN
|
||
|
||
// Quick number conversion
|
||
const input = "123";
|
||
const num = +input; // Same as Number(input)
|
||
```
|
||
|
||
### 5.3 Addition Coercion
|
||
|
||
```javascript
|
||
// String concatenation wins
|
||
console.log("" + 1 + 2); // "12" (1 converts to string first)
|
||
console.log(1 + 2 + ""); // "3" (addition happens first)
|
||
console.log("" + []); // "" (array becomes empty string)
|
||
console.log("" + {}); // "[object Object]"
|
||
|
||
// Arrays
|
||
console.log([] + []); // "" (both arrays convert to empty strings)
|
||
console.log([1] + [2]); // "12"
|
||
console.log([1, 2] + [3]); // "1,23"
|
||
```
|
||
|
||
---
|
||
|
||
## Part 6: Essential Function Concepts
|
||
|
||
### 6.1 Function Declarations vs Expressions
|
||
|
||
```javascript
|
||
// Declaration - hoisted
|
||
foo(); // ✅ Works
|
||
function foo() {
|
||
console.log("I'm hoisted!");
|
||
}
|
||
|
||
// Expression - not hoisted
|
||
bar(); // ❌ ReferenceError
|
||
const bar = function() {
|
||
console.log("I'm not hoisted!");
|
||
};
|
||
```
|
||
|
||
### 6.2 Arrow Functions Preview
|
||
|
||
Arrow functions have important differences (covered in Lesson 02):
|
||
|
||
```javascript
|
||
// No 'this' binding
|
||
const obj = {
|
||
value: 42,
|
||
regularFunc: function() {
|
||
console.log(this.value); // 42
|
||
},
|
||
arrowFunc: () => {
|
||
console.log(this.value); // undefined (or global value)
|
||
}
|
||
};
|
||
|
||
obj.regularFunc(); // 42
|
||
obj.arrowFunc(); // undefined
|
||
```
|
||
|
||
**Key Differences:**
|
||
- Arrow functions inherit `this` from outer scope
|
||
- Cannot be used as constructors
|
||
- No `arguments` object
|
||
- Cannot use `yield` (not generators)
|
||
|
||
---
|
||
|
||
## Part 7: Common Interview Gotchas
|
||
|
||
### 7.1 Object Property Duplicates
|
||
|
||
```javascript
|
||
const obj = { a: 1, b: 2, a: 3 };
|
||
console.log(obj.a); // 3 (last value wins)
|
||
```
|
||
|
||
In modern JavaScript, duplicate keys are allowed. The last value overwrites previous ones.
|
||
|
||
### 7.2 Automatic Semicolon Insertion (ASI)
|
||
|
||
```javascript
|
||
// This looks fine...
|
||
function getData() {
|
||
return
|
||
{
|
||
name: "Alice"
|
||
}
|
||
}
|
||
console.log(getData()); // undefined ⚠️
|
||
|
||
// JavaScript interprets it as:
|
||
function getData() {
|
||
return; // semicolon inserted!
|
||
{
|
||
name: "Alice"
|
||
}
|
||
}
|
||
|
||
// Fix: Keep opening brace on same line
|
||
function getData() {
|
||
return {
|
||
name: "Alice"
|
||
};
|
||
}
|
||
```
|
||
|
||
### 7.3 Implicit Global Variables
|
||
|
||
```javascript
|
||
function oops() {
|
||
x = 10; // ⚠️ Creates global variable (no var/let/const)
|
||
}
|
||
oops();
|
||
console.log(x); // 10 (global!)
|
||
|
||
// Even worse:
|
||
let x = y = 10;
|
||
// This is really: let x = (y = 10)
|
||
// x is local, y is global!
|
||
|
||
function example() {
|
||
let x = y = 20;
|
||
}
|
||
example();
|
||
console.log(y); // 20 (global!)
|
||
```
|
||
|
||
**Fix:** Always use `"use strict";` and declare all variables.
|
||
|
||
```javascript
|
||
"use strict";
|
||
function safe() {
|
||
x = 10; // ReferenceError: x is not defined
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Part 8: Preparing for Deep Dive Topics
|
||
|
||
### Topics Covered in Upcoming Lessons
|
||
|
||
**Lesson 01 - Type System & Coercion:**
|
||
- Double equals vs triple equals
|
||
- Type conversion rules
|
||
- Advanced coercion scenarios
|
||
|
||
**Lesson 02 - This Binding:**
|
||
- How `this` is determined
|
||
- Call, apply, and bind
|
||
- Arrow functions and `this`
|
||
|
||
**Lesson 03 - Closures:**
|
||
- Lexical scope
|
||
- Practical closure patterns
|
||
- Memory implications
|
||
|
||
**Lesson 04 - Event Loop:**
|
||
- Call stack, task queue, microtask queue
|
||
- Understanding async execution order
|
||
|
||
**Lesson 05 - Promises:**
|
||
- Promise states and chaining
|
||
- Error handling
|
||
- Async/await patterns
|
||
|
||
**Lesson 06 - Prototypes:**
|
||
- Prototype chain
|
||
- Constructor functions vs classes
|
||
- Inheritance patterns
|
||
|
||
**Lesson 07 - ES6+ Features:**
|
||
- Destructuring
|
||
- Spread/rest operators
|
||
- Template literals, default parameters
|
||
|
||
**Lesson 08 - Array Methods:**
|
||
- Map, filter, reduce
|
||
- ForEach vs for loops
|
||
- Functional programming concepts
|
||
|
||
---
|
||
|
||
## Key Takeaways
|
||
|
||
✅ **Remember:**
|
||
1. `typeof null` returns `"object"` (historical bug)
|
||
2. Never use `===` with floating-point decimals
|
||
3. `var` is function-scoped, `let`/`const` are block-scoped
|
||
4. Arrays are compared by reference, not value
|
||
5. Use `const` by default, `let` when needed, avoid `var`
|
||
6. Arrow functions don't have their own `this` binding
|
||
7. Array length = highest index + 1
|
||
8. Always declare variables to avoid implicit globals
|
||
|
||
---
|
||
|
||
## Practice Tips
|
||
|
||
1. **Run code examples** - Don't just read them
|
||
2. **Predict output** before running code
|
||
3. **Understand "why"** - Memorization isn't enough
|
||
4. **Practice explaining** concepts out loud
|
||
5. **Focus on weak areas** identified in your evaluation
|
||
|
||
---
|
||
|
||
## Next Steps
|
||
|
||
Complete the medium-difficulty quiz to test your understanding of these fundamentals. Then proceed to Lesson 01 to dive deeper into the type system.
|
||
|
||
**Time to complete quiz:** 10-15 minutes
|