5 Khái niệm Javascript thiết yếu cho mọi lập trình viên web
Từ newbie đến pro Javascript chỉ với 5 khái niệm cốt lõi. Bài viết này tổng hợp 5 khái niệm Javascript hàng đầu dành cho lập trình viên web, phù hợp với mọi trình độ, từ người mới bắt đầu đến những lập trình viên giàu kinh nghiệm.
1. Call Stack
Call Stack là một cấu trúc dữ liệu theo dõi vị trí hiện tại của chương trình trong hành trình thực thi của nó. Mỗi khi một hàm được gọi, một mục (được gọi là 'stack frame') được thêm vào call stack. Khi hàm hoàn thành việc thực thi, stack frame tương ứng của nó bị xóa (hoặc 'bật ra') khỏi call stack và quyền điều khiển quay trở lại hàm trước đó trong stack.
Các điểm chính: LIFO (Vào sau, ra trước): Call stack hoạt động theo nguyên tắc này, trong đó hàm được đẩy vào cuối cùng là hàm được bật ra đầu tiên. Mọi lệnh gọi hàm đang hoạt động đều nằm ở đây, duy trì thứ tự thực thi. Nếu quá nhiều lệnh gọi hàm được thêm vào mà không bị xóa (ví dụ: đệ quy vô hạn), stack sẽ hết bộ nhớ, gây ra lỗi tràn stack. Theo dõi call stack: Các công cụ gỡ lỗi sử dụng stack để hiển thị thứ tự các lệnh gọi hàm dẫn đến lỗi.
2. Execution Context
Execution Context hay Bối cảnh thực thi xác định môi trường mà mã JavaScript được thực thi. Nó bao gồm mọi thứ cần thiết để thực thi mã, chẳng hạn như định nghĩa biến, từ khóa 'this' và tham chiếu hàm.
Có ba loại bối cảnh thực thi chính trong JavaScript:
- Bối cảnh thực thi toàn cục: Được tạo theo mặc định khi tập lệnh bắt đầu. Nó chứa các biến và hàm toàn cục.
- Bối cảnh thực thi hàm: Được tạo bất cứ khi nào một hàm được gọi. Mỗi lệnh gọi hàm đều có bối cảnh riêng.
- Bối cảnh thực thi Eval: Được tạo khi mã được thực thi bên trong hàm eval().
Call stack và bối cảnh thực thi hoạt động cùng nhau. Call stack quản lý thứ tự thực thi, trong khi bối cảnh thực thi quản lý các chi tiết của việc thực thi. Khi một hàm được gọi, một bối cảnh thực thi mới được tạo và đẩy lên stack. Mã chạy trong bối cảnh thực thi hiện tại. Khi hàm kết thúc, bối cảnh của nó bị xóa khỏi stack.
3. typeof, toán tử so sánh lỏng lẻo == và toán tử so sánh nghiêm ngặt ===
Mặc dù hầu hết các lập trình viên đều biết những điều này là gì nhưng các lập trình viên chuyên nghiệp, ngoài việc biết những điều cơ bản, còn biết những hạn chế và khi nào nên sử dụng cái gì.
Toán tử typeof trả về một chuỗi cho biết kiểu của toán hạng của nó. Đó là cách dễ nhất để biết kiểu dữ liệu của một biến hoặc một biểu thức.
Các điểm chính về typeof:
- Đầu ra luôn là một chuỗi, chẳng hạn như "number", "string", "boolean", "object", "function" hoặc "undefined".
- Mặc dù là một tham chiếu đối tượng, typeof null trả về "object".
- Bạn có thể chuyển bất kỳ giá trị hoặc biểu thức nào đến typeof.
VD:
typeof 42; // "number"
typeof "Hello"; // "string"
typeof {}; // "object"
Toán tử == kiểm tra xem hai giá trị có lỏng lẻo bằng nhau hay không, nghĩa là nó so sánh các giá trị của chúng sau khi thực hiện ép kiểu (chuyển đổi cả hai toán hạng thành cùng một kiểu).
Các điểm chính về ==
- Chuyển đổi một hoặc cả hai toán hạng thành cùng một kiểu trước khi so sánh.
- Việc chuyển đổi kiểu ngầm định có thể dẫn đến kết quả không mong muốn.
- Sử dụng === thay thế để đảm bảo tính rõ ràng và độ tin cậy.
VD:
42 == "42"; // true (string is coerced to a number)
null == undefined; // true (special case of loose equality)
0 == false; // true (type coercion happens)
Toán tử === kiểm tra xem hai giá trị có nghiêm ngặt bằng nhau hay không, nghĩa là nó đánh giá cả giá trị và kiểu mà không thực hiện ép kiểu.
Các điểm chính về ===
- Cả giá trị và kiểu phải khớp chính xác.
- Đảm bảo tính rõ ràng và ngăn chặn hành vi không mong muốn.
- Xử lý mọi thứ, từ số và chuỗi đến mảng và đối tượng, và do đó đáng tin cậy hơn.
VD:
42 === "42"; // false (different types)
null === undefined; // false (different values and types)
0 === false; // false (different types)
Khi nào nên sử dụng từng toán tử?
- Sử dụng typeof khi kiểm tra hoặc gỡ lỗi các kiểu biến.
- Sử dụng === để so sánh nhằm đảm bảo cả giá trị và kiểu đều khớp.
- Tránh == trừ khi bạn tự tin rằng ép kiểu sẽ dẫn đến kết quả mong muốn (ví dụ: khi so sánh null và undefined).
4. Hàm thuần khiết (Pure functions) và hàm không thuần khiết (Impure functions)
Một hàm thuần khiết là một hàm không có tác dụng phụ và luôn trả về cùng một đầu ra cho một đầu vào nhất định (tức là nó có đầu ra xác định).
// pure function
function add(a, b) {
return a + b; // Only depends on input arguments
}
// impure function
let counter = 0;
function increment() {
counter++; // Modifies external state (impure)
}
Lợi ích của hàm thuần khiết:
- Dễ dàng kiểm tra: Vì đầu ra chỉ phụ thuộc vào đầu vào, bạn không cần phải mô phỏng các phụ thuộc bên ngoài. Ví dụ: Kiểm tra add(2, 3) luôn dẫn đến 5.
- Khả năng dự đoán: Không có hậu quả ngoài ý muốn từ trạng thái ẩn hoặc tác dụng phụ.
- Cải thiện khả năng gỡ lỗi: Các hàm thuần khiết được phân tách, giúp dễ dàng theo dõi các vấn đề.
- Khả năng tái sử dụng: Các hàm thuần khiết khép kín và có thể được tái sử dụng một cách tự tin trong các ngữ cảnh khác nhau.
- Tạo điều kiện cho lập trình hàm: Khuyến khích tính bất biến và các mô hình lập trình khai báo.
5. Lan truyền sự kiện (Event propagation)
Lan truyền sự kiện đề cập đến cách các sự kiện được xử lý trong một chương trình. Trong JavaScript, các sự kiện có thể nổi lên thông qua DOM (Mô hình đối tượng tài liệu) hoặc chúng có thể được nắm bắt và xử lý ở mỗi cấp.
- Hiệu quả xử lý sự kiện: Sử dụng uỷ quyền sự kiện để quản lý các sự kiện trên nhiều phần tử con với một trình lắng nghe cha duy nhất.
- Gỡ lỗi các vấn đề lan truyền: Hiểu về lan truyền giúp giải quyết các vấn đề khi các phần tử không mong muốn phản hồi lại các sự kiện.
- Kiểm soát tốt: Chọn giai đoạn nắm bắt hoặc nổi bọt để xử lý các sự kiện tại các điểm cụ thể trong hệ thống phân cấp DOM.
- event.stopPropagation(): Dừng lan truyền thêm trong cả giai đoạn nắm bắt và nổi bọt.
- event.stopImmediatePropagation(): Dừng lan truyền và ngăn các trình lắng nghe khác trên cùng một phần tử được gọi.
Cảm ơn các bạn đã theo dõi!
All rights reserved