Tổng hợp kiểu dữ liệu và cấu trúc dữ liệu trong JavaScript
Trần Thị Vân
- 112
- 25/07/2026
Tổng hợp các kiểu dữ liệu và cấu trúc dữ liệu trong JavaScript, từ String, Number, Boolean, Object, Array đến Set, Map, Stack, Queue, Tree và Graph, kèm ví dụ dễ hiểu, chi tiết như nào hãy cùng chúng tôi phân tích:
Trong quá trình học JavaScript, kiểu dữ liệu và cấu trúc dữ liệu là hai nền tảng quan trọng nhưng thường bị hiểu lẫn với nhau. Kiểu dữ liệu giúp JavaScript biết một giá trị đang thuộc dạng nào, chẳng hạn như chuỗi ký tự, số, giá trị đúng sai hay một đối tượng. Trong khi đó, cấu trúc dữ liệu tập trung vào cách tổ chức, lưu trữ và quản lý nhiều giá trị để chương trình có thể xử lý chúng hiệu quả.
Nếu chỉ biết cú pháp mà chưa hiểu bản chất của dữ liệu, bạn sẽ rất dễ gặp khó khăn khi làm việc với mảng, object, Set, Map hoặc khi xử lý dữ liệu nhận từ API. Ngược lại, khi nắm được cách JavaScript biểu diễn và thao tác với dữ liệu, việc xây dựng giao diện web, xử lý biểu mẫu, quản lý trạng thái hay viết các ứng dụng phức tạp sẽ trở nên dễ dàng hơn rất nhiều.
Bài viết này của Web Mới sẽ tổng hợp từ những kiểu dữ liệu cơ bản nhất đến các cấu trúc dữ liệu thường gặp trong JavaScript. Nội dung được trình bày theo hướng thực tế, giúp người mới hiểu được dữ liệu là gì, nên dùng loại nào trong từng trường hợp và những điểm dễ nhầm cần đặc biệt lưu ý.

Kiểu dữ liệu trong JavaScript là gì?
Kiểu dữ liệu có thể hiểu đơn giản là cách JavaScript phân loại một giá trị. Khi bạn tạo một biến, giá trị được lưu trong biến đó sẽ thuộc một kiểu dữ liệu nhất định.
Ví dụ, tên của một người thường được biểu diễn bằng chuỗi, tuổi có thể là một số, trạng thái đăng nhập có thể là giá trị đúng hoặc sai. Mỗi loại dữ liệu có cách sử dụng và tập hợp thao tác riêng.
JavaScript có hai nhóm kiểu dữ liệu chính gồm kiểu nguyên thủy và kiểu tham chiếu. Đây là cách phân chia rất quan trọng vì nó liên quan trực tiếp đến cách giá trị được xử lý khi gán biến, truyền tham số hoặc so sánh.
Hai nhóm dữ liệu chính cần phân biệt
Kiểu dữ liệu nguyên thủy
Kiểu nguyên thủy đại diện cho một giá trị đơn lẻ. Trong JavaScript có các kiểu nguyên thủy gồm String, Number, BigInt, Boolean, Undefined, Null và Symbol.
Một đặc điểm quan trọng của nhóm này là giá trị nguyên thủy có tính bất biến. Khi bạn thực hiện thao tác tạo ra một giá trị mới, giá trị ban đầu không bị thay đổi theo cách mà các object hoặc array có thể bị thay đổi.
Kiểu dữ liệu tham chiếu
Trong cách phân loại phổ biến, Object được xem là nhóm dữ liệu tham chiếu. Array, Function, Date, RegExp, Map và Set đều là những dạng đối tượng trong JavaScript.
Điểm cần chú ý là biến chứa object không nên được hiểu đơn giản là chứa toàn bộ dữ liệu của object theo cùng cách với một giá trị nguyên thủy. Khi gán hoặc truyền object, nhiều biến có thể cùng tham chiếu đến một đối tượng. Vì vậy, thay đổi dữ liệu thông qua một biến có thể ảnh hưởng đến dữ liệu mà biến khác đang tham chiếu.
const userA = {
name: "An"
};
const userB = userA;
userB.name = "Bình";
console.log(userA.name);
Trong ví dụ trên, userA và userB cùng tham chiếu đến một object. Khi thuộc tính name được thay đổi thông qua userB, kết quả khi truy cập userA.name cũng thay đổi.
String: dữ liệu dạng văn bản
String được sử dụng để biểu diễn dữ liệu dạng văn bản. Đây là kiểu dữ liệu xuất hiện rất thường xuyên trong các ứng dụng JavaScript, từ tên người dùng, tiêu đề bài viết đến URL, nội dung biểu mẫu và dữ liệu trả về từ máy chủ.
Chuỗi có thể được tạo bằng dấu nháy đơn, dấu nháy kép hoặc template literal. Trong các dự án hiện đại, template literal đặc biệt hữu ích khi cần kết hợp biến vào nội dung văn bản.
const name = "Minh";
const age = 25;
const message = `Xin chào ${name}, bạn ${age} tuổi.`;
console.log(message);
String có nhiều phương thức xử lý hữu ích như toUpperCase(), toLowerCase(), trim(), includes(), startsWith(), endsWith(), slice() và replace().
Một lưu ý quan trọng là chuỗi trong JavaScript không bị thay đổi trực tiếp. Các phương thức xử lý chuỗi thường trả về một chuỗi mới thay vì chỉnh sửa chuỗi ban đầu.
Number: dữ liệu số
Number dùng để biểu diễn số trong JavaScript, bao gồm số nguyên và số thực. Không giống một số ngôn ngữ lập trình có nhiều kiểu số riêng biệt, JavaScript sử dụng Number cho phần lớn các phép tính số thông thường.
const quantity = 10;
const price = 250000;
const discount = 0.1;
const total = quantity * price;
const finalPrice = total * (1 - discount);
console.log(finalPrice);
Number có thể dùng cho phép cộng, trừ, nhân, chia và nhiều phép tính khác. Tuy nhiên, khi làm việc với số thực, bạn cần lưu ý đến đặc điểm biểu diễn số của máy tính.
console.log(0.1 + 0.2);
Kết quả có thể không đúng tuyệt đối bằng 0.3 do cách số thực được biểu diễn ở cấp độ máy tính. Với các bài toán tài chính yêu cầu độ chính xác cao, không nên tùy tiện dựa vào phép tính Number mà không cân nhắc cách xử lý số thập phân.
Các giá trị đặc biệt liên quan đến Number
JavaScript có một số giá trị đặc biệt như NaN, Infinity và -Infinity.
console.log(10 / 0);
console.log("abc" * 2);
console.log(Number.isNaN(NaN));
NaN có nghĩa là kết quả không phải một số hợp lệ theo cách biểu diễn của JavaScript. Điều đáng chú ý là NaN vẫn thuộc kiểu Number.
BigInt: xử lý số nguyên rất lớn
BigInt được thiết kế để biểu diễn số nguyên có kích thước vượt quá giới hạn an toàn của Number. Kiểu này phù hợp với những trường hợp cần làm việc với số nguyên cực lớn và yêu cầu giữ độ chính xác.
const bigNumber = 123456789012345678901234567890n;
console.log(bigNumber);
BigInt có hậu tố n ở cuối số. Khi thực hiện phép toán, bạn cần chú ý không trộn trực tiếp BigInt với Number trong cùng một phép tính nếu không có bước chuyển đổi phù hợp.
Boolean: dữ liệu đúng hoặc sai
Boolean chỉ có hai giá trị là true và false. Kiểu dữ liệu này đóng vai trò quan trọng trong các câu lệnh điều kiện, kiểm tra trạng thái và điều khiển luồng chương trình.
const isLoggedIn = true;
if (isLoggedIn) {
console.log("Người dùng đã đăng nhập");
}
Boolean thường xuất hiện trong các tình huống như kiểm tra người dùng đã đăng nhập hay chưa, sản phẩm còn hàng hay không, biểu mẫu đã hợp lệ chưa hoặc một tính năng có được bật hay không.
Undefined: biến chưa có giá trị
Undefined thường xuất hiện khi một biến đã được khai báo nhưng chưa được gán giá trị cụ thể.
let username;
console.log(username);
Ngoài ra, khi truy cập một thuộc tính không tồn tại trong object, kết quả thường là undefined.
const user = {
name: "Lan"
};
console.log(user.email);
Undefined không nên bị nhầm với chuỗi rỗng hoặc số 0. Đây là một giá trị đặc biệt thể hiện tình trạng không có giá trị được xác định.
Null: biểu diễn sự vắng mặt có chủ đích
Null thường được sử dụng khi lập trình viên muốn biểu thị rằng một biến hoặc thuộc tính hiện không có dữ liệu.
const selectedUser = null;
console.log(selectedUser);
Trong thực tế, null thường có ý nghĩa rõ ràng hơn undefined trong một số mô hình dữ liệu. Chẳng hạn, một hồ sơ người dùng có thể có thuộc tính avatar bằng null để biểu thị rằng người dùng chưa thiết lập ảnh đại diện.
Một điểm gây nhầm lẫn nổi tiếng là kết quả của typeof null là "object". Đây là một đặc điểm lịch sử của JavaScript và không nên dùng kết quả này để kết luận rằng null là một object thông thường.
Symbol: tạo giá trị định danh duy nhất
Symbol là một kiểu dữ liệu nguyên thủy được dùng để tạo ra các giá trị định danh duy nhất.
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2);
Dù cùng sử dụng chuỗi mô tả "id", hai Symbol được tạo ra vẫn không giống nhau. Symbol có thể hữu ích khi muốn tạo khóa thuộc tính đặc biệt mà hạn chế nguy cơ xung đột với các tên thuộc tính khác.
Object: mô hình hóa dữ liệu theo thuộc tính
Object là một trong những cấu trúc quan trọng nhất của JavaScript. Một object thường tổ chức dữ liệu theo dạng cặp khóa và giá trị.
const product = {
name: "Bàn phím",
price: 500000,
inStock: true
};
Trong ví dụ này, name, price và inStock là các thuộc tính. Giá trị tương ứng có thể là String, Number, Boolean hoặc thậm chí tiếp tục là một object hay array.
Object đặc biệt phù hợp khi dữ liệu có nhiều thuộc tính mô tả một thực thể. Ví dụ, một sản phẩm có thể có tên, giá, hình ảnh và trạng thái tồn kho. Một người dùng có thể có tên, email, tuổi và danh sách quyền truy cập.
Truy cập và thay đổi thuộc tính
Có hai cách phổ biến để truy cập thuộc tính object là dùng dấu chấm hoặc dấu ngoặc vuông.
const user = {
name: "Huy",
age: 28
};
console.log(user.name);
console.log(user["age"]);
user.age = 29;
Dấu ngoặc vuông đặc biệt hữu ích khi tên thuộc tính nằm trong một biến hoặc không thể truy cập thuận tiện bằng cú pháp dấu chấm.
const key = "name";
const user = {
name: "Huy"
};
console.log(user[key]);
Array: danh sách dữ liệu theo thứ tự
Array là cấu trúc dữ liệu dùng để lưu nhiều giá trị trong một danh sách có thứ tự. Mỗi phần tử có vị trí được xác định bằng chỉ số, bắt đầu từ 0.
const fruits = ["Táo", "Cam", "Xoài"];
console.log(fruits[0]);
console.log(fruits[2]);
Array có thể chứa nhiều kiểu dữ liệu khác nhau, mặc dù trong thực tế nên tổ chức dữ liệu nhất quán để chương trình dễ bảo trì.
const data = [
"JavaScript",
100,
true,
{
level: "basic"
}
];
Các phương thức quan trọng của Array gồm push(), pop(), shift(), unshift(), slice(), splice(), map(), filter(), find(), some(), every() và reduce().
Nhóm phương thức xử lý danh sách hiện đại
Trong các ứng dụng thực tế, map và filter được sử dụng rất thường xuyên vì chúng giúp xử lý danh sách theo hướng rõ ràng.
const products = [
{ name: "Chuột", price: 200000 },
{ name: "Bàn phím", price: 500000 },
{ name: "Màn hình", price: 3000000 }
];
const expensiveProducts = products.filter(product => {
return product.price > 300000;
});
const productNames = products.map(product => {
return product.name;
});
console.log(expensiveProducts);
console.log(productNames);
filter() tạo ra danh sách mới gồm những phần tử đáp ứng điều kiện. Trong khi đó, map() tạo ra một danh sách mới bằng cách biến đổi từng phần tử.
So sánh Object và Array
Object và Array đều có thể chứa nhiều dữ liệu nhưng phục vụ những mục đích khác nhau.
| Tiêu chí | Object | Array |
|---|---|---|
| Cách tổ chức | Theo khóa và giá trị | Theo vị trí của phần tử |
| Phù hợp với | Một thực thể có nhiều thuộc tính | Một danh sách nhiều phần tử |
| Cách truy cập | Thông qua tên khóa | Thông qua chỉ số |
| Ví dụ | Một sản phẩm | Danh sách sản phẩm |
Ví dụ, một sản phẩm có thể được biểu diễn bằng object, còn nhiều sản phẩm có thể được đặt trong array.
const product = {
name: "Laptop",
price: 15000000
};
const products = [
{
name: "Laptop",
price: 15000000
},
{
name: "Điện thoại",
price: 10000000
}
];
Trong các ứng dụng thực tế, hai cấu trúc này thường được kết hợp với nhau thay vì sử dụng riêng biệt.
Nested Object và Array lồng nhau
Dữ liệu thực tế thường có nhiều tầng. Một object có thể chứa object khác, hoặc một array có thể chứa nhiều object.
const user = {
name: "Mai",
address: {
city: "Hà Nội",
country: "Việt Nam"
}
};
console.log(user.address.city);
Đây là dạng dữ liệu rất phổ biến khi làm việc với JSON hoặc dữ liệu nhận từ API.
const users = [
{
name: "Mai",
skills: ["HTML", "CSS", "JavaScript"]
},
{
name: "Nam",
skills: ["JavaScript", "Node.js"]
}
];
Khi xử lý dữ liệu lồng nhau, cần xác định rõ tầng dữ liệu trước khi truy cập. Nếu một thuộc tính trung gian không tồn tại, chương trình có thể phát sinh lỗi khi cố truy cập thuộc tính tiếp theo.
Set: tập hợp các giá trị không trùng lặp
Set là cấu trúc dữ liệu dùng để lưu các giá trị duy nhất. Nếu thêm cùng một giá trị nhiều lần, Set vẫn chỉ giữ lại một giá trị.
const numbers = new Set();
numbers.add(10);
numbers.add(20);
numbers.add(10);
console.log(numbers);
Set rất hữu ích khi cần loại bỏ phần tử trùng lặp khỏi một array.
const numbers = [1, 2, 2, 3, 3, 4];
const uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers);
Set cũng cung cấp các phương thức như add(), has(), delete() và clear().
Map: lưu dữ liệu theo cặp khóa và giá trị
Map cũng tổ chức dữ liệu theo cặp khóa và giá trị nhưng được thiết kế riêng cho việc quản lý tập hợp các cặp dữ liệu này.
const users = new Map();
users.set("user1", "An");
users.set("user2", "Bình");
console.log(users.get("user1"));
console.log(users.has("user2"));
Điểm đáng chú ý của Map là khóa không nhất thiết phải là String. Khóa có thể là Number, Object hoặc nhiều kiểu giá trị khác.
const user = {
id: 1,
name: "An"
};
const userRoles = new Map();
userRoles.set(user, "admin");
console.log(userRoles.get(user));
Map thường phù hợp khi bạn cần một tập hợp khóa và giá trị có tính chất động, đặc biệt khi số lượng phần tử lớn hoặc khi khóa không chỉ là chuỗi.
WeakMap và WeakSet
WeakMap và WeakSet là các cấu trúc dữ liệu chuyên biệt hơn. Chúng thường xuất hiện trong những bài toán liên quan đến object và quản lý bộ nhớ.
WeakMap lưu các cặp khóa và giá trị, trong đó khóa phải là object hoặc một kiểu dữ liệu phù hợp theo quy tắc của JavaScript. WeakSet lưu các object duy nhất.
Hai cấu trúc này không phải lựa chọn mặc định cho người mới. Chúng thường được sử dụng trong các trường hợp cần gắn dữ liệu phụ vào object mà không muốn giữ object đó tồn tại chỉ vì cấu trúc dữ liệu đang tham chiếu đến nó.
Stack: cấu trúc dữ liệu vào sau ra trước
Stack là mô hình dữ liệu hoạt động theo nguyên tắc LIFO, viết tắt của Last In, First Out. Phần tử được thêm vào sau cùng sẽ được lấy ra trước.
Bạn có thể hình dung Stack giống như một chồng đĩa. Muốn lấy một chiếc đĩa, thông thường bạn sẽ lấy chiếc nằm trên cùng, tức chiếc được đặt vào sau cùng.
const stack = [];
stack.push("A");
stack.push("B");
stack.push("C");
const lastItem = stack.pop();
console.log(lastItem);
Trong JavaScript, Array có thể được sử dụng để mô phỏng Stack bằng cách kết hợp push() và pop().
Stack có thể xuất hiện trong lịch sử thao tác, cơ chế hoàn tác, duyệt cây, thuật toán đệ quy và nhiều bài toán xử lý dữ liệu khác.
Queue: cấu trúc dữ liệu vào trước ra trước
Queue hoạt động theo nguyên tắc FIFO, viết tắt của First In, First Out. Phần tử được thêm vào trước sẽ được xử lý trước.
Một hàng người chờ mua vé là ví dụ dễ hình dung. Người đến trước thường được phục vụ trước người đến sau.
const queue = [];
queue.push("A");
queue.push("B");
queue.push("C");
const firstItem = queue.shift();
console.log(firstItem);
Trong ví dụ này, phần tử A được thêm đầu tiên nên được lấy ra trước.
Khi xây dựng ứng dụng thực tế, nếu phải xử lý một Queue rất lớn, việc liên tục dùng shift() trên Array có thể không phải lựa chọn tối ưu. Tùy trường hợp, bạn có thể quản lý vị trí đầu và cuối bằng chỉ số để giảm thao tác dịch chuyển phần tử.
Linked List: danh sách liên kết
Linked List là cấu trúc dữ liệu gồm nhiều node liên kết với nhau. Mỗi node thường chứa dữ liệu và một liên kết đến node tiếp theo.
JavaScript không cung cấp sẵn Linked List như một kiểu dữ liệu tích hợp. Nếu cần sử dụng, bạn có thể tự xây dựng bằng object hoặc class.
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
const first = new Node("A");
const second = new Node("B");
first.next = second;
console.log(first.value);
console.log(first.next.value);
Linked List phù hợp với những bài toán cần thao tác liên kết giữa các node. Tuy nhiên, trong ứng dụng JavaScript thông thường, Array thường được sử dụng nhiều hơn do tính tiện dụng và hệ sinh thái phương thức phong phú.
Tree: dữ liệu có cấu trúc phân cấp
Tree là cấu trúc dữ liệu phân cấp gồm các node. Một node có thể chứa nhiều node con, tạo thành các tầng dữ liệu.
Trong phát triển web, mô hình Tree xuất hiện ở nhiều nơi như cấu trúc thư mục, menu nhiều cấp, DOM của trang web và các hệ thống phân cấp danh mục.
const category = {
name: "Công nghệ",
children: [
{
name: "Lập trình",
children: [
{
name: "JavaScript"
}
]
}
]
};
Tree đặc biệt hữu ích khi dữ liệu có quan hệ cha con. Thay vì lưu tất cả dữ liệu trên một mặt phẳng, cấu trúc này phản ánh trực tiếp mối quan hệ phân cấp.
Graph: mô hình hóa các mối quan hệ
Graph được sử dụng để biểu diễn các thực thể và mối quan hệ giữa chúng. Một graph gồm các node và các cạnh kết nối.
Khác với Tree, một node trong Graph có thể kết nối với nhiều node khác theo nhiều hướng. Mô hình này phù hợp với mạng xã hội, hệ thống giao thông, bản đồ, mạng lưới liên kết hoặc quan hệ giữa các thực thể.
const graph = {
A: ["B", "C"],
B: ["A", "D"],
C: ["A"],
D: ["B"]
};
console.log(graph.A);
Đây là cách biểu diễn Graph bằng một object chứa danh sách kề. Với các bài toán phức tạp hơn, có thể sử dụng Map hoặc các cấu trúc chuyên biệt để quản lý node và cạnh.
JSON và dữ liệu trao đổi giữa các hệ thống
JSON không phải là một kiểu dữ liệu nguyên thủy của JavaScript. Đây là một định dạng biểu diễn dữ liệu rất phổ biến, đặc biệt khi trao đổi dữ liệu giữa trình duyệt và máy chủ.
Dữ liệu JSON thường có cấu trúc gần giống object và array của JavaScript.
const user = {
name: "An",
age: 25
};
const jsonString = JSON.stringify(user);
console.log(jsonString);
Khi nhận một chuỗi JSON và muốn chuyển thành dữ liệu JavaScript, bạn có thể sử dụng JSON.parse().
const jsonString = '{"name":"An","age":25}';
const user = JSON.parse(jsonString);
console.log(user.name);
Cần phân biệt rõ giữa object JavaScript và chuỗi JSON. Object là dữ liệu mà JavaScript có thể trực tiếp thao tác bằng thuộc tính, còn JSON thường tồn tại dưới dạng văn bản khi được truyền qua mạng hoặc lưu trữ.
Truthy và Falsy trong JavaScript
Trong JavaScript, không phải mọi giá trị đều là Boolean nhưng nhiều giá trị vẫn có thể được đánh giá trong ngữ cảnh điều kiện.
Các giá trị thường được xem là falsy gồm false, 0, -0, 0n, "", null, undefined và NaN.
Phần lớn các giá trị khác được đánh giá là truthy, bao gồm cả array rỗng và object rỗng.
const items = [];
if (items) {
console.log("Điều kiện này vẫn được thực thi");
}
Đây là một điểm người mới thường nhầm. Array rỗng không phải là falsy. Nếu muốn kiểm tra một array có phần tử hay không, bạn nên kiểm tra thuộc tính length.
const items = [];
if (items.length > 0) {
console.log("Danh sách có dữ liệu");
}
Phân biệt == và ===
Hai toán tử so sánh này có thể cho kết quả khác nhau vì cách JavaScript xử lý kiểu dữ liệu.
== có thể thực hiện chuyển đổi kiểu trước khi so sánh, trong khi === yêu cầu giá trị và kiểu dữ liệu phải phù hợp.
console.log(5 == "5");
console.log(5 === "5");
Trong phần lớn trường hợp khi viết ứng dụng, sử dụng === giúp việc kiểm tra dữ liệu rõ ràng và dễ dự đoán hơn.
Kiểm tra kiểu dữ liệu bằng typeof
Toán tử typeof thường được sử dụng để kiểm tra kiểu của một giá trị.
console.log(typeof "JavaScript");
console.log(typeof 100);
console.log(typeof true);
console.log(typeof undefined);
console.log(typeof null);
Với các kiểu phức tạp hơn, typeof không phải lúc nào cũng đủ để xác định chính xác loại dữ liệu. Ví dụ, Array cũng trả về kết quả là object.
const items = [];
console.log(typeof items);
console.log(Array.isArray(items));
Vì vậy, khi cần xác định một giá trị có phải Array hay không, Array.isArray() là lựa chọn phù hợp hơn.
Shallow Copy và Deep Copy
Khi làm việc với object và array, việc sao chép dữ liệu là vấn đề rất quan trọng. Một phép gán đơn giản không tạo ra một object hoàn toàn độc lập.
const original = {
name: "An"
};
const copy = original;
copy.name = "Bình";
console.log(original.name);
Nếu muốn tạo một object mới ở cấp đầu tiên, bạn có thể sử dụng spread syntax.
const original = {
name: "An",
age: 25
};
const copy = {
...original
};
copy.name = "Bình";
console.log(original.name);
console.log(copy.name);
Tuy nhiên, spread chỉ tạo shallow copy. Nếu object chứa các object hoặc array lồng nhau, dữ liệu bên trong vẫn có thể tiếp tục dùng chung tham chiếu.
const original = {
profile: {
name: "An"
}
};
const copy = {
...original
};
copy.profile.name = "Bình";
console.log(original.profile.name);
Với dữ liệu có cấu trúc phức tạp, cần cân nhắc phương pháp sao chép phù hợp thay vì mặc định sử dụng spread cho mọi trường hợp.
Cách lựa chọn cấu trúc dữ liệu phù hợp
Không có một cấu trúc dữ liệu duy nhất phù hợp cho mọi bài toán. Việc lựa chọn phụ thuộc vào dạng dữ liệu, cách truy cập và thao tác mà chương trình cần thực hiện.
| Nhu cầu | Cấu trúc nên cân nhắc |
|---|---|
| Lưu một thực thể có nhiều thuộc tính | Object |
| Lưu danh sách có thứ tự | Array |
| Loại bỏ dữ liệu trùng lặp | Set |
| Quản lý cặp khóa và giá trị linh hoạt | Map |
| Xử lý dữ liệu theo nguyên tắc vào sau ra trước | Stack |
| Xử lý dữ liệu theo nguyên tắc vào trước ra trước | Queue |
| Dữ liệu có quan hệ cha con | Tree |
| Dữ liệu có nhiều mối quan hệ kết nối | Graph |
Điều quan trọng không phải là ghi nhớ thật nhiều tên cấu trúc dữ liệu mà là hiểu đặc điểm của từng loại. Khi gặp một bài toán, hãy bắt đầu bằng việc xác định dữ liệu cần lưu là gì, cách truy cập phổ biến nhất là gì và thao tác nào sẽ được thực hiện nhiều nhất.
Những lỗi thường gặp khi làm việc với dữ liệu
Nhầm giữa null và undefined
Hai giá trị này đều có thể liên quan đến việc thiếu dữ liệu nhưng ý nghĩa trong chương trình có thể khác nhau. Undefined thường xuất hiện khi giá trị chưa được xác định, còn null thường được sử dụng để biểu thị trạng thái không có dữ liệu một cách chủ động.
Nhầm Array với Object
Array cũng thuộc nhóm object khi xét theo bản chất của JavaScript, nhưng không nên vì thế mà sử dụng chúng thay thế cho nhau. Array phù hợp với danh sách có thứ tự, còn object phù hợp với dữ liệu được mô tả bằng các thuộc tính.
Quên rằng index của Array bắt đầu từ 0
Phần tử đầu tiên của array có index bằng 0. Đây là một lỗi cơ bản nhưng rất dễ dẫn đến việc truy cập sai phần tử hoặc lỗi trong vòng lặp.
Gán object mà tưởng rằng đã tạo bản sao
Việc gán một object sang biến khác chỉ tạo thêm một tham chiếu đến cùng dữ liệu. Nếu cần một bản sao độc lập, bạn phải chọn cách sao chép phù hợp với độ sâu của cấu trúc dữ liệu.
Dùng sai cấu trúc cho nhu cầu thực tế
Ví dụ, nếu chỉ cần danh sách các giá trị duy nhất, việc dùng Array rồi liên tục kiểm tra trùng lặp có thể phức tạp hơn so với Set. Nếu cần quản lý các cặp khóa và giá trị linh hoạt, Map có thể là lựa chọn phù hợp hơn trong nhiều tình huống.
Kiểu dữ liệu và cấu trúc dữ liệu liên quan với nhau như thế nào?
Kiểu dữ liệu và cấu trúc dữ liệu không phải hai khái niệm tách biệt hoàn toàn. Chúng thường kết hợp với nhau để tạo thành những mô hình dữ liệu thực tế.
Một array có thể chứa nhiều object. Một object có thể chứa array. Một object có thể chứa nhiều object con. Một Map có thể dùng object làm khóa. Một Tree có thể được xây dựng bằng các node object có liên kết đến các node con.
const courses = [
{
title: "JavaScript cơ bản",
lessons: [
"Biến",
"Kiểu dữ liệu",
"Hàm"
]
},
{
title: "JavaScript nâng cao",
lessons: [
"Promise",
"Async",
"API"
]
}
];
Trong ví dụ này, Array được dùng để lưu danh sách khóa học, mỗi khóa học là một Object, còn thuộc tính lessons lại chứa một Array khác. Đây chính là cách dữ liệu thường được tổ chức trong các ứng dụng web thực tế.
Gợi ý lộ trình học dữ liệu trong JavaScript
Nếu bạn mới bắt đầu, không nên cố học tất cả cấu trúc dữ liệu cùng một lúc. Một lộ trình hợp lý là bắt đầu với String, Number, Boolean, Undefined và Null để hiểu nền tảng.
Sau đó, hãy tập trung vào Object và Array vì đây là hai cấu trúc xuất hiện rất thường xuyên trong quá trình phát triển web. Tiếp theo, học cách sử dụng các phương thức xử lý Array như map, filter, find và reduce.
Khi đã quen với Array và Object, bạn có thể tiếp tục tìm hiểu Set và Map. Sau đó mới mở rộng sang Stack, Queue, Linked List, Tree và Graph để hiểu sâu hơn về cấu trúc dữ liệu và thuật toán.
Trong quá trình học, hãy ưu tiên xây dựng các bài tập nhỏ. Chẳng hạn, bạn có thể tạo danh sách sản phẩm, lọc sản phẩm theo giá, loại bỏ sản phẩm trùng mã, nhóm dữ liệu theo danh mục hoặc xây dựng hệ thống menu nhiều cấp. Những bài tập này giúp bạn hiểu cách lựa chọn cấu trúc dữ liệu tốt hơn nhiều so với việc chỉ học thuộc lý thuyết.
Kết luận
Kiểu dữ liệu là nền móng để JavaScript hiểu và xử lý các giá trị, còn cấu trúc dữ liệu giúp tổ chức nhiều giá trị thành những mô hình phù hợp với từng bài toán. Từ String, Number, Boolean đến Object, Array, Set và Map, mỗi loại đều có vai trò riêng trong quá trình xây dựng ứng dụng.
Ở mức cơ bản, bạn nên nắm thật chắc sự khác biệt giữa kiểu nguyên thủy và dữ liệu tham chiếu, hiểu cách Object và Array hoạt động, biết khi nào nên dùng Set hoặc Map và tránh những lỗi phổ biến liên quan đến null, undefined, sao chép dữ liệu và so sánh giá trị.
Khi tiến xa hơn, việc tìm hiểu Stack, Queue, Linked List, Tree và Graph sẽ giúp bạn có tư duy tốt hơn về cách dữ liệu được tổ chức và xử lý. Đây cũng là nền tảng quan trọng nếu bạn muốn học sâu về thuật toán, tối ưu hiệu suất hoặc phát triển các ứng dụng JavaScript có quy mô lớn.
Hiểu dữ liệu không chỉ giúp bạn viết JavaScript đúng cú pháp mà còn giúp bạn đưa ra quyết định tốt hơn khi thiết kế chương trình. Khi biết dữ liệu cần được lưu như thế nào và thao tác nào được thực hiện thường xuyên, bạn sẽ dễ dàng lựa chọn được cấu trúc phù hợp, viết code rõ ràng hơn và xây dựng ứng dụng dễ mở rộng hơn.
- 0 Bình luận
Email, Điện thoại của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *