JavaScript - Function Hoisting: A Beginner's Guide

Xin chào các bạn tương lai của các pháp sư JavaScript! Hôm nay, chúng ta sẽ cùng nhau khám phá một khía cạnh thú vị của JavaScript mà thường làm mới手的 người mới bối rối: Function Hoisting. Đừng lo lắng nếu điều này听起来 có vẻ bí ẩn - đến cuối bài học này, bạn sẽ có thể "hoisting" các hàm như một chuyên gia!

JavaScript - Function Hoisting

什么是 Function Hoisting?

Trước khi chúng ta đi vào chi tiết, hãy bắt đầu với một định nghĩa đơn giản:

Function hoisting là một hành vi trong JavaScript nơi các khai báo hàm được di chuyển lên đỉnh của phạm vi của chúng trước khi mã được thực thi.

Bây giờ, tôi biết bạn đang nghĩ gì: "Nhưng thầy, điều đó có nghĩa là gì?" Hãy phá vỡ điều này với một số ví dụ, nhé?

Ví dụ 1: Hàm xuất hiện kỳ diệu

sayHello(); // Điều này hoạt động!

function sayHello() {
console.log("Hello, world!");
}

Nếu bạn là người mới bắt đầu lập trình, bạn có thể đang gãi đầu bối rối. "Làm thế nào chúng ta có thể gọi một hàm trước khi nó được định nghĩa?" bạn hỏi. Well, những người học yêu quí của tôi, đó là phép màu của function hoisting!

Trong ví dụ này, JavaScript "hoisting" toàn bộ hàm sayHello lên đỉnh của phạm vi của nó. Vậy, phía sau hậu trường, mã như thể được viết như này:

function sayHello() {
console.log("Hello, world!");
}

sayHello(); // Bây giờ có lẽ dễ hiểu hơn phải không?

Ví dụ 2: Câu chuyện về hai hàm

Hãy làm cho mọi thứ thú vị hơn một chút với một ví dụ khác:

greeting("John"); // Output: "Hello, John!"
farewell("John"); // Lỗi: farewell is not a function

function greeting(name) {
console.log("Hello, " + name + "!");
}

var farewell = function(name) {
console.log("Goodbye, " + name + "!");
};

Trong câu chuyện về hai hàm này, chúng ta thấy các hành vi khác nhau. Hàm greeting hoạt động tốt khi được gọi trước khi khai báo, nhờ vào hoisting. Nhưng đáng thương farewell lại gây ra lỗi. Tại sao? Bởi vì chỉ có khai báo biến var farewell được hoisting, không phải là việc gán hàm.

Các quy tắc của Function Hoisting

Bây giờ chúng ta đã thấy function hoisting trong hành động, hãy lập ra một số quy tắc cơ bản:

  1. Các khai báo hàm được hoisting hoàn toàn.
  2. Các khai báo biến được hoisting, nhưng không phải là việc gán chúng.
  3. Các biểu thức hàm (khi bạn gán một hàm vào một biến) không được hoisting.

Hãy cùng khám phá các quy tắc này với thêm một số ví dụ!

Ví dụ 3: Khai báo so với biểu thức

// Điều này hoạt động
hello();

function hello() {
console.log("Hello from a function declaration!");
}

// Điều này không hoạt động
goodbye(); // Lỗi: goodbye is not a function

var goodbye = function() {
console.log("Goodbye from a function expression!");
};

Ở đây, hello là một khai báo hàm, vì vậy nó được hoisting hoàn toàn. Nhưng goodbye là một biểu thức hàm, vì vậy chỉ phần var goodbye được hoisting, không phải là hàm itself.

JavaScript Variable Hoisting

Bây giờ chúng ta đã覆盖 function hoisting, hãy nhanh chóng xem qua biến hoisting. Đây là một khái niệm liên quan mà rất quan trọng để hiểu.

Ví dụ 4: Vô định bí ẩn

console.log(x); // Output: undefined
var x = 5;
console.log(x); // Output: 5

Trong ví dụ này, khai báo của x được hoisting, nhưng không phải là việc gán nó. Vì vậy, console.log đầu tiên xuất ra undefined, trong khi cái thứ hai hiển thị giá trị được gán.

Ví dụ 5: Let và Const - Những người mới đến

console.log(a); // Lỗi: Cannot access 'a' before initialization
let a = 10;

console.log(b); // Lỗi: Cannot access 'b' before initialization
const b = 20;

Với sự ra đời của letconst trong ES6, chúng ta có một hành vi mới. Các khai báo này được hoisting, nhưng chúng không được khởi tạo. Điều này tạo ra một "vùng chết thời gian" nơi bạn không thể truy cập vào biến trước khi khai báo của nó.

Practical Implications and Best Practices

Bây giờ chúng ta đã hiểu cách hoisting hoạt động, điều này có ý nghĩa gì đối với chúng ta như những nhà phát triển?

  1. Always declare your variables at the top of their scope. Điều này làm cho mã của bạn rõ ràng hơn và ngăn chặn các hành vi không mong muốn.

  2. Use function declarations for functions you want to use throughout your code. Hành vi hoisting của chúng có thể rất hữu ích.

  3. Be cautious with function expressions. Nhớ rằng, chúng không được hoisting như các khai báo hàm.

  4. When in doubt, declare and initialize together. Điều này loại bỏ mọi sự không rõ ràng về giá trị của biến.

  5. Consider using let and const instead of var. Chúng cung cấp hành vi giam giới rõ ràng hơn.

Dưới đây là bảng tóm tắt hành vi hoisting của các loại khai báo khác nhau:

Loại khai báo Được hoisting? Được khởi tạo?
Function Declaration
var Undefined
let Không (TDZ)
const Không (TDZ)
Function Expression Không Không

Kết luận

Và thế là bạn đã có nó, những nhà lập trình non trẻ của tôi! Chúng ta đã giải mã bí ẩn của function hoisting trong JavaScript. Nhớ rằng, việc hiểu các khái niệm này không chỉ là biết các quy tắc - nó còn về việc viết mã sạch sẽ và dễ dự đoán hơn.

Trong hành trình JavaScript của bạn, bạn sẽ gặp rất nhiều tính năng thú vị (và đôi khi là khó hiểu). Nhưng đừng nản chí! Mỗi khi bạn học được một điều mới, bạn lại gần hơn một bước đến việc trở thành một ninja JavaScript.

Tiếp tục thực hành, tiếp tục lập mã, và quan trọng nhất, tiếp tục hỏi câu hỏi. Cuối cùng, câu hỏi duy nhất ngốc nghếch là câu hỏi bạn không hỏi!

Đến gặp lại lần sau, chúc các bạn lập mã vui vẻ!

Credits: Image by storyset