JavaScript Course Content

Scope & Hoisting

Hiểu về phạm vi biến và cơ chế hoisting trong JavaScript

Lesson 2/8Chapter 1: Variables

Mục tiêu học tập

Hiểu khái niệm Scope (phạm vi biến) trong JavaScript
Phân biệt Global Scope, Function Scope và Block Scope
Nắm vững cơ chế Hoisting của JavaScript
Hiểu Temporal Dead Zone (TDZ) và cách tránh lỗi
Phân biệt hoisting behavior giữa var, let, const và function
Áp dụng lexical scoping và closure basics
Tránh được các lỗi thường gặp về scope và hoisting

Các loại Scope

Global Scope

Biến khai báo ngoài function/block, truy cập được từ mọi nơi

var global = "everywhere"; // có thể dùng ở mọi nơi

Function Scope

Biến khai báo trong function, chỉ truy cập được trong function đó

function test() { var local = "only here"; }

Block Scope

let/const trong {...} chỉ truy cập được trong block đó

if (true) { let block = "in block only"; }

Lexical Scope

Scope được xác định bởi vị trí khai báo trong code

function outer() { function inner() { /* có thể dùng biến outer */ } }

Scope Chain

JavaScript tìm biến từ scope hiện tại lên scope cha

local scope → function scope → global scope

Hành vi Hoisting

Khai báoHoistedKhởi tạoTDZVí dụ
varundefinedKhôngconsole.log(x); var x = 5; // undefined, không lỗi
letKhông khởi tạoconsole.log(x); let x = 5; // ReferenceError
constKhông khởi tạoconsole.log(x); const x = 5; // ReferenceError
functionToàn bộ functionKhôngfunc(); function func() {} // Hoạt động bình thường
function expressionTheo biến chứaundefined (var) hoặc TDZ (let/const)Phụ thuộc biến chứafunc(); var func = function() {}; // TypeError

Lỗi thường gặp

Sử dụng var trong loops với closures

Dùng let thay vì var hoặc tạo IIFE

// Sai
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100); // In ra 3, 3, 3
}

// Đúng
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100); // In ra 0, 1, 2
}

Truy cập biến trong Temporal Dead Zone

Khai báo biến trước khi sử dụng

// Sai
console.log(x); // ReferenceError
let x = 5;

// Đúng
let x = 5;
console.log(x); // 5

Nhầm lẫn giữa function scope và block scope

Hiểu rõ scope của từng loại khai báo

// Chú ý
if (true) {
  var x = 1; // function scoped
  let y = 2; // block scoped
}
console.log(x); // 1 (OK)
console.log(y); // ReferenceError

Không hiểu closure giữ lại scope

Nhớ closure "đóng gói" scope của function cha

function outer() {
  let count = 0;
  return function() { return ++count; };
}
const counter = outer();
// count vẫn tồn tại trong closure

Global scope pollution

Sử dụng modules, IIFE hoặc namespaces

// Sai
var data = "global";

// Đúng
(function() {
  var data = "encapsulated";
})();

Best Practices

Khai báo biến ở đầu scope

Luôn khai báo biến ở đầu scope để tránh confusion về hoisting

// Tốt
function example() {
  var x, y, z;
  // logic code...
  x = 1;
  y = 2;
  z = x + y;
}

Ưu tiên let/const thay vì var

Sử dụng let/const để có block scope rõ ràng và tránh hoisting issues

// Tốt
const PI = 3.14159;
let radius = 5;
let area = PI * radius * radius;

Sử dụng strict mode

Strict mode giúp phát hiện lỗi scope sớm hơn

'use strict';
// Sẽ báo lỗi nếu dùng biến chưa khai báo

Tạo scope riêng với IIFE khi cần

Sử dụng IIFE để tạo scope riêng biệt và tránh global pollution

(function() {
  // Code trong scope riêng
  var private = "not global";
})();

Hiểu rõ closure performance

Closure giữ lại toàn bộ scope, có thể gây memory leak nếu không cẩn thận

// Cẩn thận với closures trong loops
for (let i = 0; i < 1000; i++) {
  // Tạo closure cẩn thận
}

Mục lục

Không có mục lục