📚 Học JavaScript Cơ Bản

Hướng dẫn học JavaScript từ cơ bản: Biến, Hàm, Array và Object dành cho người mới bắt đầu

📋 Buổi 1: Giới thiệu JavaScript và Biến

🎯 JavaScript là gì?

JavaScript là ngôn ngữ lập trình để làm website tương tác. Với JavaScript, bạn có thể:

  • Hiển thị thông báo: alert, console.log
  • Thay đổi nội dung: Thay đổi text, hình ảnh trên trang web
  • Xử lý sự kiện: Click button, gõ phím
  • Tính toán: Cộng, trừ, nhân, chia
  • Lưu trữ dữ liệu: Trong biến, array, object

📝 Những điều quan trọng khi học JavaScript:

  • Đặt tên biến rõ ràng: userName thay vì u
  • Viết code từ từ: Từng dòng một, test thường xuyên
  • Sử dụng console.log: Để xem kết quả
  • Thực hành nhiều: Càng code nhiều càng giỏi

📝 Cách đặt tên và khai báo biến

🎯 Tại sao cần đặt tên biến đúng cách?

Đặt tên biến rõ ràng giúp bạn và người khác dễ hiểu code. Giống như đặt tên file, tên biến phải nói lên nó chứa gì.

📝 Quy tắc đặt tên cơ bản

Naming Rules
javascript
// ✅ Đặt tên biến ĐÚNG - dễ hiểu
const userName = 'john';         // ✓ Rõ ràng: tên của user
const userAge = 25;              // ✓ Rõ ràng: tuổi của user  
const isLoggedIn = true;         // ✓ Rõ ràng: đã đăng nhập chưa

// ❌ Đặt tên biến SAI - khó hiểu
const u = 'john';               // ❌ u là gì? Không rõ
const x = 25;                   // ❌ x là gì? Không rõ
const flag = true;              // ❌ flag gì? Không rõ

// ✅ Quy tắc đặt tên
// - Chữ cái đầu viết thường
// - Từ thứ 2 trở đi viết hoa chữ cái đầu (camelCase)
const firstName = 'John';        // first + Name
const lastName = 'Doe';          // last + Name  
const fullName = 'John Doe';     // full + Name
const phoneNumber = '0123456789'; // phone + Number

// ✅ Tên hằng số - viết HOA tất cả
const MAX_AGE = 100;            // Tuổi tối đa
const MIN_SCORE = 0;            // Điểm tối thiểu

💡 Tại sao cần đặt tên biến rõ ràng?

  • Dễ nhớ: Bạn sẽ nhớ biến đó để làm gì
  • Dễ sửa: Khi có lỗi, bạn tìm được biến nhanh chóng
  • Dễ học: Người khác đọc code của bạn sẽ hiểu ngay
  • Tránh nhầm lẫn: Không bị confused giữa các biến

🔤 Cách khai báo biến

💡 3 cách tạo biến trong JavaScript

JavaScript có 3 từ khóa để tạo biến: const, letvar. Chúng ta sẽ học constlet vì chúng dễ hiểu và an toàn hơn.

Variable Best Practices
javascript
// ✅ Dùng CONST cho giá trị không thay đổi
const myName = 'John';                  // Tên không đổi
const myAge = 20;                       // Tuổi hiện tại  
const PI = 3.14;                        // Số pi không đổi

// ✅ Dùng LET cho giá trị sẽ thay đổi
let score = 0;                          // Điểm sẽ tăng giảm
let currentLevel = 1;                   // Level sẽ thay đổi
let isGameOver = false;                 // Trạng thái game

// ✅ Ví dụ thay đổi giá trị với LET
score = score + 10;                     // Tăng điểm
currentLevel = currentLevel + 1;        // Lên level
isGameOver = true;                      // Game kết thúc

// ❌ KHÔNG thể thay đổi CONST
// myName = 'Jane';  // ❌ Lỗi! Không thể thay đổi const

// ✅ Tạo từng biến trên 1 dòng (dễ đọc)
const userName = 'Alice';
const userEmail = 'alice@email.com';
const userPhone = '0123456789';

// ❌ Tạo nhiều biến trên 1 dòng (khó đọc)  
const a = 1, b = 2, c = 3;  // Khó hiểu a, b, c là gì

🤔 Khi nào dùng const, khi nào dùng let?

  • Dùng const khi: Giá trị không đổi (tên, tuổi, địa chỉ)
  • Dùng let khi: Giá trị sẽ thay đổi (điểm số, bộ đếm, trạng thái)
  • Tránh dùng var: Cũ và dễ gây nhầm lẫn
  • Mẹo: Luôn dùng const trước, nếu cần thay đổi thì chuyển sang let

📋 Buổi 2: Function (Hàm) trong JavaScript

🎯 Function là gì?

Function (hàm) là một đoạn code có thể tái sử dụng. Giống như một chiếc máy: bạn cho nguyên liệu vào, máy xử lý và cho ra kết quả.

🎪 Cách tạo Function đơn giản

Variable Best Practices
javascript
// ✅ Cách tạo function đơn giản
// Cú pháp: function tênFunction() { code }

// Function không có tham số (parameter)
function sayHello() {
  console.log('Xin chào!');
}

// Gọi function
sayHello(); // In ra: Xin chào!

// Function có tham số 
function greetUser(userName) {
  console.log('Xin chào ' + userName + '!');
}

// Gọi function với tham số
greetUser('John'); // In ra: Xin chào John!
greetUser('Mary'); // In ra: Xin chào Mary!

// Function có return (trả về giá trị)
function addTwoNumbers(a, b) {
  const sum = a + b;
  return sum; // Trả về kết quả
}

// Sử dụng function có return
const result = addTwoNumbers(5, 3);
console.log(result); // In ra: 8

// Function tính diện tích hình chữ nhật
function calculateArea(width, height) {
  const area = width * height;
  return area;
}

const myArea = calculateArea(10, 5);
console.log('Diện tích:', myArea); // In ra: Diện tích: 50

🎯 Tại sao dùng Function?

� Lợi ích của Function

  • Tái sử dụng: Viết 1 lần, dùng nhiều lần
  • Dễ sửa: Sửa lỗi ở 1 chỗ, mọi nơi được sửa
  • Dễ đọc: Code được chia thành từng phần nhỏ
  • Dễ test: Kiểm tra từng function riêng biệt
Ví dụ thực tế
javascript
// ❌ Không dùng function - Code lặp lại nhiều lần
const student1Score = 85;
const student1Grade = student1Score >= 90 ? 'A' : student1Score >= 80 ? 'B' : 'C';
console.log('Học sinh 1 được điểm:', student1Grade);

const student2Score = 92;
const student2Grade = student2Score >= 90 ? 'A' : student2Score >= 80 ? 'B' : 'C';
console.log('Học sinh 2 được điểm:', student2Grade);

// ✅ Dùng function - Code ngắn gọn, dễ sử dụng
function calculateGrade(score) {
  if (score >= 90) {
    return 'A';
  } else if (score >= 80) {
    return 'B';
  } else {
    return 'C';
  }
}

// Sử dụng function
const grade1 = calculateGrade(85);
const grade2 = calculateGrade(92);
const grade3 = calculateGrade(76);

console.log('Học sinh 1:', grade1); // B
console.log('Học sinh 2:', grade2); // A  
console.log('Học sinh 3:', grade3); // C

📋 Buổi 3: Array - Lỗi thường gặp và cách tránh

⚠️ Những lỗi phổ biến khi làm việc với Array

Dưới đây là các lỗi học sinh thường mắc phải và cách khắc phục:

❌ Lỗi 1: Truy cập Index không tồn tại

Array Index Errors
javascript
// ❌ LỖI: Truy cập index không tồn tại
const fruits = ['táo', 'cam', 'xoài'];

console.log(fruits[5]); // undefined - không có index 5!
console.log(fruits[-1]); // undefined - không có index âm!

// ❌ LỖI: Dùng length làm index
console.log(fruits[fruits.length]); // undefined - vì length = 3, nhưng index cuối là 2

// ✅ ĐÚNG: Kiểm tra trước khi truy cập
if (fruits.length > 0) {
  console.log('Phần tử đầu:', fruits[0]);
  console.log('Phần tử cuối:', fruits[fruits.length - 1]);
}

// ✅ ĐÚNG: Dùng optional chaining (ES2020)
console.log(fruits[5] ?? 'Không tồn tại');

// ✅ ĐÚNG: Kiểm tra index hợp lệ
function getItem(arr, index) {
  if (index >= 0 && index < arr.length) {
    return arr[index];
  }
  return 'Index không hợp lệ';
}

❌ Lỗi 2: Thay đổi Array trong vòng lặp

Loop Mutation Errors
javascript
// ❌ LỖI: Xóa phần tử trong vòng lặp for
const numbers = [1, 2, 3, 4, 5];

// KHÔNG làm thế này!
for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 === 0) {
    numbers.splice(i, 1); // Xóa số chẵn - GÂY LỖI!
    // Khi xóa, các phần tử sau sẽ dịch lên, làm bỏ sót
  }
}

// ❌ LỖI: Thêm phần tử trong forEach
const items = [1, 2, 3];
items.forEach(item => {
  items.push(item * 2); // Gây vòng lặp vô tận!
});

// ✅ ĐÚNG: Dùng filter để tạo array mới
const evenNumbers = numbers.filter(num => num % 2 === 0);

// ✅ ĐÚNG: Lặp ngược khi cần xóa
for (let i = numbers.length - 1; i >= 0; i--) {
  if (numbers[i] % 2 === 0) {
    numbers.splice(i, 1);
  }
}

// ✅ ĐÚNG: Tạo array mới thay vì sửa array cũ
const doubled = items.map(item => item * 2);

❌ Lỗi 3: So sánh Array không đúng cách

Array Comparison Errors
javascript
// ❌ LỖI: So sánh array bằng == hoặc ===
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
const arr3 = arr1;

console.log(arr1 === arr2); // false - Khác reference!
console.log(arr1 === arr3); // true - Cùng reference

// ❌ LỖI: Nghĩ rằng 2 array giống nhau sẽ bằng nhau
if (arr1 === arr2) { // Sẽ không bao giờ true!
  console.log('Arrays bằng nhau');
}

// ✅ ĐÚNG: So sánh độ dài và từng phần tử
function arraysEqual(a, b) {
  if (a.length !== b.length) return false;
  
  for (let i = 0; i < a.length; i++) {
    if (a[i] !== b[i]) return false;
  }
  return true;
}

// ✅ ĐÚNG: Dùng JSON.stringify cho array đơn giản
function simpleArraysEqual(a, b) {
  return JSON.stringify(a) === JSON.stringify(b);
}

// ✅ ĐÚNG: Dùng every() method
function arraysEqualModern(a, b) {
  return a.length === b.length && 
         a.every((val, index) => val === b[index]);
}

📋 Buổi 4: Object - Lỗi thường gặp và cách tránh

⚠️ Những lỗi phổ biến khi làm việc với Object

Object có nhiều "cạm bẫy" mà học sinh thường gặp phải. Hãy tìm hiểu để tránh!

❌ Lỗi 1: Truy cập thuộc tính không tồn tại

Object Property Errors
javascript
const user = {
  name: 'John',
  age: 25
};

// ❌ LỖI: Truy cập thuộc tính không tồn tại
console.log(user.email); // undefined - không có thuộc tính email
console.log(user.profile.avatar); // ERROR! - Cannot read property 'avatar' of undefined

// ❌ LỖI: Viết sai tên thuộc tính
console.log(user.Name); // undefined - phải là 'name' (chữ n thường)
console.log(user.AGE);  // undefined - phải là 'age' (chữ thường)

// ✅ ĐÚNG: Kiểm tra thuộc tính tồn tại
if (user.email) {
  console.log('Email:', user.email);
} else {
  console.log('Không có email');
}

// ✅ ĐÚNG: Dùng optional chaining
console.log(user.profile?.avatar ?? 'Không có avatar');

// ✅ ĐÚNG: Dùng hasOwnProperty
if (user.hasOwnProperty('email')) {
  console.log(user.email);
}

// ✅ ĐÚNG: Dùng in operator
if ('email' in user) {
  console.log(user.email);
}

❌ Lỗi 2: Nhầm lẫn giữa Dot notation và Bracket notation

Property Access Errors
javascript
const scores = {
  'math': 90,
  'english': 85,
  'science-lab': 95,
  '2023-grade': 'A'
};

// ❌ LỖI: Dùng dot notation với tên có ký tự đặc biệt
console.log(scores.science-lab); // ERROR! Hiểu là phép trừ
console.log(scores.2023-grade);  // ERROR! Không thể bắt đầu bằng số

// ❌ LỖI: Dùng bracket notation không đúng
const subject = 'math';
console.log(scores.subject); // undefined - tìm thuộc tính tên 'subject'
console.log(scores[subject]); // 90 - đúng, tìm thuộc tính tên trong biến subject

// ✅ ĐÚNG: Dùng bracket notation cho tên đặc biệt
console.log(scores['science-lab']); // 95
console.log(scores['2023-grade']);  // 'A'

// ✅ ĐÚNG: Dùng biến làm key
const key = 'english';
console.log(scores[key]); // 85

// ✅ ĐÚNG: Dùng dot notation cho tên thường
console.log(scores.math);    // 90
console.log(scores.english); // 85

❌ Lỗi 3: Copy Array và Object không đúng cách (QUAN TRỌNG!)

🔥 Lỗi nguy hiểm nhất: Reference vs Value

Đây là lỗi gây ra nhiều bug nhất trong JavaScript. 90% học sinh mắc phải!

Reference vs Value Errors
javascript
// ❌ LỖI NGUY HIỂM: Copy bằng reference
const originalArray = [1, 2, 3];
const originalObject = { name: 'John', score: 85 };

const copyArray = originalArray;     // KHÔNG phải copy!
const copyObject = originalObject;   // KHÔNG phải copy!

// Thay đổi "bản copy"
copyArray.push(4);
copyObject.score = 95;

// OMG! Bản gốc cũng bị thay đổi!
console.log(originalArray);  // [1, 2, 3, 4] - BỊ THAY ĐỔI!
console.log(originalObject); // { name: 'John', score: 95 } - BỊ THAY ĐỔI!

// ✅ ĐÚNG: Shallow copy với spread operator
const realCopyArray = [...originalArray];
const realCopyObject = { ...originalObject };

realCopyArray.push(5);
realCopyObject.name = 'Jane';

console.log(originalArray);  // [1, 2, 3] - KHÔNG bị thay đổi ✅
console.log(realCopyArray);  // [1, 2, 3, 5] - Chỉ copy thay đổi ✅

// ⚠️ CHÚ Ý: Shallow copy chỉ copy 1 tầng
const nested = {
  user: { name: 'John', age: 25 },
  scores: [85, 90, 88]
};

const shallowCopy = { ...nested };
shallowCopy.user.age = 30;          // Vẫn ảnh hưởng đến object gốc!
console.log(nested.user.age);       // 30 - BỊ THAY ĐỔI!

// ✅ ĐÚNG: Deep copy cho nested object
const deepCopy = JSON.parse(JSON.stringify(nested));
// Hoặc dùng structuredClone() (modern browsers)
const modernDeepCopy = structuredClone(nested);

❌ Lỗi 4: Nhầm lẫn this trong Object methods

This Context Errors
javascript
// ❌ LỖI: Mất context của this
const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
    return this;
  },
  getValue: function() {
    return this.value;
  }
};

// Lưu method vào biến
const add = calculator.add;
add(5); // ERROR! this không còn trỏ đến calculator

// ❌ LỖI: Dùng arrow function làm method
const brokenCalc = {
  value: 0,
  add: (num) => {
    this.value += num; // ERROR! Arrow function không có this
  }
};

// ✅ ĐÚNG: Dùng bind để giữ context
const boundAdd = calculator.add.bind(calculator);
boundAdd(5); // OK

// ✅ ĐÚNG: Gọi method trực tiếp từ object
calculator.add(10).add(5); // Method chaining

// ✅ ĐÚNG: Dùng call/apply
calculator.add.call(calculator, 3);
calculator.add.apply(calculator, [7]);

💻 Bài tập thực hành Buổi 4 - Tìm và sửa lỗi Object

Trung bình

🎯 Bài 1: Debug - Tìm lỗi trong Object code

Đoạn code sau có nhiều lỗi nguy hiểm. Hãy tìm và sửa chúng:

Bài tập 1 - Debug Object Code
javascript
// 🐛 BUGGY CODE - Tìm và sửa các lỗi sau:

const user = {
  name: 'John',
  'favorite-color': 'blue',
  '2023-score': 95
};

// Lỗi 1: Truy cập thuộc tính không tồn tại
console.log(user.email.address); // ❌ Crash! Tại sao?

// Lỗi 2: Sai cách truy cập thuộc tính có dấu gạch ngang
console.log(user.favorite-color); // ❌ Lỗi syntax! Sửa thế nào?

// Lỗi 3: Truy cập thuộc tính bắt đầu bằng số
console.log(user.2023-score); // ❌ Lỗi syntax! Sửa thế nào?

// Lỗi 4: Copy object sai cách (nguy hiểm!)
const admin = user;
admin.name = 'Admin';
console.log(user.name); // ❌ Kết quả: 'Admin' - Tại sao user bị thay đổi?

// Lỗi 5: Nested object copy sai
const profile = {
  info: { name: 'Jane', age: 25 },
  settings: { theme: 'dark' }
};

const newProfile = { ...profile };
newProfile.info.age = 30;
console.log(profile.info.age); // ❌ Kết quả: 30 - Vẫn bị ảnh hưởng!

// Lỗi 6: This context bị mất
const calculator = {
  value: 10,
  add: function(x) { this.value += x; return this.value; }
};

const addFunc = calculator.add;
console.log(addFunc(5)); // ❌ Error hoặc kết quả không đúng

// TODO: Viết lại code đúng ở đây
// 1. Kiểm tra thuộc tính tồn tại trước khi truy cập
// 2. Dùng bracket notation cho thuộc tính đặc biệt
// 3. Copy object đúng cách (shallow và deep)
// 4. Giữ nguyên this context
Nâng cao

🎯 Bài 2: Viết utility functions an toàn cho Object

Viết các function xử lý object một cách an toàn:

Bài tập 2 - Safe Object Utilities
javascript
// TODO: Viết các utility function xử lý object an toàn

// 1. Function lấy giá trị an toàn (không crash khi thuộc tính không tồn tại)
function safeGet(obj, path, defaultValue = null) {
  // TODO: Lấy giá trị từ path như 'user.profile.name'
  // Trả về defaultValue nếu không tồn tại
  // Ví dụ: safeGet({user: {name: 'John'}}, 'user.name') => 'John'
  //        safeGet({user: {}}, 'user.profile.name', 'Unknown') => 'Unknown'
}

// 2. Function deep copy object
function deepCopy(obj) {
  // TODO: Copy object hoàn toàn (bao gồm cả nested objects và arrays)
  // Không được dùng JSON.parse/stringify
}

// 3. Function merge objects an toàn
function safeMerge(target, source) {
  // TODO: Gộp source vào target mà không làm thay đổi target gốc
  // Trả về object mới
}

// 4. Function kiểm tra object rỗng
function isEmpty(obj) {
  // TODO: Trả về true nếu object không có thuộc tính nào
  // Xử lý cả null, undefined, array
}

// 5. Function so sánh deep equality
function deepEqual(obj1, obj2) {
  // TODO: So sánh 2 object có giống nhau hoàn toàn không
  // Bao gồm cả nested objects và arrays
}

// Test cases
const testObj = {
  user: { name: 'John', age: 25 },
  scores: [85, 90]
};

console.log(safeGet(testObj, 'user.name'));        // Should: 'John'
console.log(safeGet(testObj, 'user.email', 'N/A')); // Should: 'N/A'
console.log(isEmpty({}));                          // Should: true
console.log(isEmpty({a: 1}));                      // Should: false

const copied = deepCopy(testObj);
copied.user.age = 30;
console.log(testObj.user.age);                     // Should: 25 (không đổi)

📝 Tóm tắt buổi học

🎯 Những điều quan trọng đã học:

📋 Buổi 1: Biến và Đặt tên

  • ✅ Dùng const cho giá trị không đổi
  • ✅ Dùng let cho giá trị thay đổi
  • ✅ Đặt tên biến rõ ràng, dễ hiểu
  • ✅ camelCase: userName, phoneNumber

⚡ Buổi 2: Function (Hàm)

  • ✅ Function giúp tái sử dụng code
  • function tên(thamSố) { return kếtQuả; }
  • ✅ Gọi function: tên(giáTrị)
  • ✅ Đặt tên function bằng động từ

📚 Buổi 3: Array - Lỗi thường gặp

  • ⚠️ Tránh truy cập index không tồn tại
  • ⚠️ Không thay đổi array trong vòng lặp
  • ⚠️ So sánh array đúng cách
  • ✅ Viết function xử lý array an toàn

🏷️ Buổi 4: Object - Lỗi thường gặp

  • ⚠️ Reference vs Value (lỗi nguy hiểm nhất!)
  • ⚠️ Truy cập thuộc tính an toàn
  • ⚠️ Dot vs Bracket notation
  • ✅ Copy deep/shallow đúng cách

🚀 Bước tiếp theo:

Thực hành nhiều hơn! Hãy tạo các project nhỏ để áp dụng kiến thức đã học:

  • Todo List: Sử dụng Array để lưu danh sách việc cần làm
  • Student Manager: Dùng Object để quản lý thông tin học sinh
  • Simple Calculator: Tạo function tính toán cơ bản
  • Grade Book: Kết hợp Array và Object để quản lý điểm