Cách hoạt động của hằng số mảng (Array Const) trong JavaScript

Javascript căn bản | by Học Javascript

Trong JavaScript, từ khóa const được sử dụng để khai báo hằng số, tức là những biến không thể bị gán lại giá trị mới sau khi khởi tạo. Tuy nhiên, khi áp dụng const với mảng, nhiều người dễ nhầm lẫn rằng mảng sẽ trở thành bất biến hoàn toàn. Trên thực tế, const chỉ ngăn chặn việc gán lại mảng mới, nhưng vẫn cho phép thay đổi nội dung bên trong mảng. Điều này có ý nghĩa quan trọng trong việc quản lý dữ liệu và tối ưu hóa code, giúp lập trình viên kiểm soát biến chặt chẽ hơn mà vẫn đảm bảo tính linh hoạt.

Trong bài viết này, mình sẽ tìm hiểu chi tiết cách hoạt động của const với mảng, những thao tác hợp lệ và không hợp lệ, cũng như ứng dụng thực tế trong lập trình JavaScript.

Hằng số mảng (const với mảng) trong JavaScript

Trong JavaScript, const là một từ khóa được sử dụng để khai báo hằng số. Khi một biến được khai báo bằng const, giá trị của nó không thể bị gán lại. Điều này có nghĩa là bạn không thể thay đổi tham chiếu của biến const sau khi đã khởi tạo.

Ví dụ:

const x = 10;
x = 20; // Lỗi: Assignment to constant variable

Tại sao dùng const với mảng?

Mặc dù const ngăn chặn việc gán lại biến, nhưng khi dùng với mảng, nó có một số lợi ích quan trọng:

  • Ngăn chặn thay đổi tham chiếu của mảng: Bạn không thể gán một mảng mới cho biến const, giúp tránh lỗi khi vô tình gán lại giá trị.
  • Dễ đọc và bảo trì code: Khi sử dụng const, lập trình viên hiểu rằng biến này sẽ luôn trỏ đến cùng một mảng trong suốt vòng đời của nó.
  • Hạn chế lỗi do gán lại biến: Nếu sử dụng let hoặc var, một biến có thể bị gán lại vô tình, gây ra lỗi khó tìm.

Ví dụ:

const numbers = [1, 2, 3];
// numbers = [4, 5, 6]; //  Lỗi: Assignment to constant variable

Nhầm lẫn phổ biến: const không làm mảng bất biến hoàn toàn

Một quan niệm sai lầm phổ biến là const làm cho mảng không thể thay đổi. Trên thực tế, const chỉ ngăn chặn việc gán lại mảng mới, nhưng vẫn cho phép thay đổi nội dung bên trong mảng.

Ví dụ:

const numbers = [1, 2, 3];

numbers.push(4);   //  Hợp lệ
numbers[0] = 10;   //  Hợp lệ

console.log(numbers); // Output: [10, 2, 3, 4]

Tuy nhiên, nếu bạn cố gắng gán lại numbers thành một mảng mới, JavaScript sẽ báo lỗi:

numbers = [5, 6, 7]; // Lỗi: Assignment to constant variable

Cách hoạt động của const khi khai báo mảng trong JavaScript

Trong JavaScript, khi khai báo một mảng bằng const, có một số quy tắc quan trọng cần lưu ý:

Không thể gán lại một mảng mới cho biến khai báo bằng const

Khi một mảng được khai báo bằng const, bạn không thể thay đổi tham chiếu của biến đó. Điều này có nghĩa là bạn không thể gán một mảng mới vào biến const.

Ví dụ: Gán lại toàn bộ mảng sẽ gây lỗi

const numbers = [1, 2, 3];

// Cố gắng gán lại một mảng mới
numbers = [4, 5, 6]; //  Lỗi: Assignment to constant variable

Lỗi xảy ra vì const không cho phép thay đổi tham chiếu của biến.

Nếu bạn cần thay đổi toàn bộ mảng, hãy sử dụng let thay vì const:

let numbers = [1, 2, 3];
numbers = [4, 5, 6]; // Hợp lệ vì sử dụng let

Thay đổi nội dung của mảng (push, pop, splice, …)

Mặc dù const ngăn chặn việc gán lại mảng mới, nó vẫn cho phép thay đổi nội dung bên trong mảng. Các phương thức như push(), pop(), splice(), shift(), unshift() vẫn có thể được sử dụng.

Ví dụ: Thay đổi nội dung bên trong mảng

const fruits = ["Apple", "Banana", "Cherry"];

// Thêm phần tử vào mảng
fruits.push("Mango");  
console.log(fruits); // Output: ["Apple", "Banana", "Cherry", "Mango"]

// Xóa phần tử cuối cùng
fruits.pop();  
console.log(fruits); // Output: ["Apple", "Banana", "Cherry"]

// Xóa phần tử đầu tiên
fruits.shift();  
console.log(fruits); // Output: ["Banana", "Cherry"]

// Thêm phần tử vào đầu mảng
fruits.unshift("Grapes");  
console.log(fruits); // Output: ["Grapes", "Banana", "Cherry"]

// Xóa và thay thế phần tử bằng splice
fruits.splice(1, 1, "Orange");  
console.log(fruits); // Output: ["Grapes", "Orange", "Cherry"]

Kết quả:

Không có lỗi xảy ra vì chúng ta chỉ thay đổi nội dung bên trong mảng, không thay đổi tham chiếu của nó.

Các phương thức thao tác trên mảng vẫn hoạt động bình thường

Hầu hết các phương thức thao tác trên mảng vẫn hoạt động với biến const, bao gồm:

map(), filter(), reduce() không gây lỗi vì tạo mảng mới

Các phương thức này trả về một mảng mới, nhưng chúng không thay đổi tham chiếu của biến gốc, vì vậy không gây lỗi.

const numbers = [1, 2, 3, 4, 5];

// map() - Tạo mảng mới với các phần tử được nhân đôi
const doubled = numbers.map(num => num * 2);
console.log(doubled); // Output: [2, 4, 6, 8, 10]

// filter() - Lọc ra các số lớn hơn 2
const greaterThanTwo = numbers.filter(num => num > 2);
console.log(greaterThanTwo); // Output: [3, 4, 5]

// reduce() - Tính tổng các phần tử trong mảng
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // Output: 15

Kết quả

Các phương thức này không thay đổi numbers, mà chỉ tạo mảng mới, do đó không vi phạm quy tắc const.

Không gây lỗi vì const chỉ bảo vệ tham chiếu, không phải dữ liệu bên trong

  • const chỉ đảm bảo rằng biến mảng luôn tham chiếu đến cùng một vùng nhớ.
  • Nội dung bên trong mảng vẫn có thể thay đổi, miễn là không gán lại toàn bộ mảng.

Ví dụ: Thêm phần tử vào mảng không vi phạm const

const arr = [1, 2, 3];

arr.push(4); // Hợp lệ
arr[0] = 100; //  Hợp lệ

console.log(arr); // Output: [100, 2, 3, 4]
Không có lỗi xảy ra vì chúng ta chỉ thay đổi nội dung bên trong mảng.

Các thao tác hợp lệ và không hợp lệ với mảng const trong JavaScript

Trong JavaScript, khi khai báo một mảng bằng const, bạn có thể thực hiện một số thao tác mà không vi phạm quy tắc const, nhưng cũng có một số thao tác sẽ gây lỗi. Dưới đây là danh sách chi tiết các thao tác hợp lệ và không hợp lệ.

Hợp lệ (Có thể thực hiện được)

Mặc dù const ngăn không cho gán lại toàn bộ mảng, nhưng vẫn cho phép thay đổi nội dung bên trong. Các thao tác hợp lệ bao gồm:

Thêm phần tử vào mảng (push(), unshift())

Bạn có thể thêm phần tử vào cuối hoặc đầu mảng bằng push()unshift().

const numbers = [1, 2, 3];

// Thêm phần tử vào cuối mảng
numbers.push(4);
console.log(numbers); // Output: [1, 2, 3, 4]

// Thêm phần tử vào đầu mảng
numbers.unshift(0);
console.log(numbers); // Output: [0, 1, 2, 3, 4]

Không gây lỗi vì push() và unshift() chỉ thay đổi nội dung bên trong mảng.

Xóa phần tử khỏi mảng (pop(), shift(), splice())

Bạn có thể xóa phần tử bằng các phương thức pop(), shift(), và splice().

const fruits = ["Apple", "Banana", "Cherry", "Mango"];

// Xóa phần tử cuối cùng
fruits.pop();
console.log(fruits); // Output: ["Apple", "Banana", "Cherry"]

// Xóa phần tử đầu tiên
fruits.shift();
console.log(fruits); // Output: ["Banana", "Cherry"]

// Xóa phần tử ở vị trí bất kỳ
fruits.splice(1, 1);  // Xóa phần tử tại index 1
console.log(fruits); // Output: ["Banana"]

Không gây lỗi vì các phương thức này chỉ thay đổi nội dung bên trong mảng.

Thay đổi giá trị phần tử (array[index] = value)

Bạn có thể thay đổi giá trị của từng phần tử bằng cách gán giá trị mới cho một chỉ mục cụ thể.

const scores = [10, 20, 30];

// Thay đổi giá trị của phần tử tại index 1
scores[1] = 50;
console.log(scores); // Output: [10, 50, 30]

// Thay đổi giá trị của phần tử đầu tiên
scores[0] = 100;
console.log(scores); // Output: [100, 50, 30]

Không gây lỗi vì chúng ta chỉ cập nhật giá trị của phần tử trong mảng, không thay đổi tham chiếu của biến scores.

Không hợp lệ (Sẽ gây lỗi)

Các thao tác dưới đây sẽ vi phạm quy tắc của const và gây lỗi vì chúng cố gắng thay đổi tham chiếu của biến const.

Gán lại mảng mới (array = [new values])

Không thể gán lại toàn bộ mảng mới cho biến đã khai báo bằng const.

const numbers = [1, 2, 3];

// Cố gắng gán một mảng mới sẽ gây lỗi
numbers = [4, 5, 6]; //  Lỗi: Assignment to constant variable

Lỗi xảy ra vì const không cho phép thay đổi tham chiếu của biến numbers.

Xóa toàn bộ mảng bằng array = []

Bạn không thể xóa toàn bộ mảng bằng cách gán nó thành một mảng rỗng.

const animals = ["Cat", "Dog", "Rabbit"];

// Cố gắng xóa toàn bộ mảng
animals = []; //  Lỗi: Assignment to constant variable

Lỗi xảy ra vì const không cho phép thay đổi tham chiếu của biến animals.

Cách thay thế nếu cần gán lại mảng

Nếu bạn muốn thay đổi toàn bộ mảng, hãy sử dụng let thay vì const:

let numbers = [1, 2, 3];
numbers = [4, 5, 6]; //  Hợp lệ vì sử dụng let
console.log(numbers); // Output: [4, 5, 6]

Cách thay thế nếu cần xóa toàn bộ mảng

Bạn không thể gán array = [], nhưng bạn có thể xoá toàn bộ phần tử trong mảng mà không thay đổi tham chiếu bằng cách sử dụng splice() hoặc length = 0:

Cách 1: Dùng splice() để xóa toàn bộ phần tử

const animals = ["Cat", "Dog", "Rabbit"];

// Xóa tất cả phần tử nhưng vẫn giữ nguyên tham chiếu
animals.splice(0, animals.length);
console.log(animals); // Output: []

Không gây lỗi vì splice() chỉ thay đổi nội dung bên trong mảng.

Cách 2: Gán length = 0 để xóa tất cả phần tử

const colors = ["Red", "Green", "Blue"];

// Xóa tất cả phần tử
colors.length = 0;
console.log(colors); // Output: []

Không gây lỗi vì length = 0 chỉ thay đổi kích thước của mảng, không thay đổi tham chiếu của biến.

Thao tác Hợp lệ / Không hợp lệ Giải thích
push() / unshift() Hợp lệ Thêm phần tử vào mảng
pop() / shift() / splice() Hợp lệ Xóa phần tử trong mảng
array[index] = value Hợp lệ Thay đổi giá trị phần tử
array = [new values] Không hợp lệ Không thể gán mảng mới
array = [] Không hợp lệ Không thể gán mảng rỗng
splice(0, array.length) Hợp lệ Xóa toàn bộ phần tử
array.length = 0 Hợp lệ Xóa toàn bộ phần tử

So sánh const, let, và var khi khai báo mảng trong JavaScript

Khi khai báo mảng trong JavaScript, có thể sử dụng ba từ khóa: const, let, và var. Mỗi từ khóa có những đặc điểm riêng về khả năng thay đổi nội dung mảng, gán lại giá trị và phạm vi hoạt động. Dưới đây là so sánh chi tiết giữa chúng.

Bảng so sánh const, let, và var khi khai báo mảng

Từ khóa Có thể thay đổi giá trị bên trong mảng? Có thể gán lại mảng mới? Phạm vi hoạt động (Scope)
const Có thể thay đổi nội dung Không thể gán lại Block Scope
let Có thể thay đổi nội dung Có thể gán lại Block Scope
var Có thể thay đổi nội dung Có thể gán lại Function Scope


const – Hằng số, không thể gán lại nhưng có thể thay đổi nội dung

Khi khai báo một mảng bằng const:
Có thể thay đổi nội dung của mảng bằng cách thêm, xóa hoặc sửa phần tử.
Không thể gán lại một mảng mới, tức là không thể thay đổi tham chiếu của biến.

Ví dụ:

const numbers = [1, 2, 3];

//  Có thể thay đổi nội dung của mảng
numbers.push(4);
console.log(numbers); // Output: [1, 2, 3, 4]

numbers[0] = 100;
console.log(numbers); // Output: [100, 2, 3, 4]

//  Không thể gán lại một mảng mới
numbers = [10, 20, 30]; // Lỗi: Assignment to constant variable

Lỗi xảy ra vì const không cho phép thay đổi tham chiếu của biến numbers.

Phạm vi hoạt động (Block Scope)

  • constphạm vi trong khối {}.
  • Không thể khai báo lại cùng một tên biến trong cùng một khối.

Ví dụ:

{
    const colors = ["Red", "Green"];
}
// console.log(colors); //  Lỗi: colors is not defined (biến chỉ tồn tại trong block)

let – Có thể thay đổi nội dung và gán lại mảng mới

Khi khai báo một mảng bằng let:
Có thể thay đổi nội dung của mảng (thêm, xóa, chỉnh sửa phần tử).
Có thể gán lại một mảng mới bằng cách thay đổi tham chiếu của biến.

Ví dụ:

let fruits = ["Apple", "Banana", "Cherry"];

//  Có thể thay đổi nội dung của mảng
fruits.push("Mango");
console.log(fruits); // Output: ["Apple", "Banana", "Cherry", "Mango"]

// Có thể gán lại một mảng mới
fruits = ["Orange", "Grapes"];
console.log(fruits); // Output: ["Orange", "Grapes"]

Phạm vi hoạt động (Block Scope)

  • let cũng có phạm vi trong khối {}, giống như const.
  • Không thể khai báo lại cùng một tên biến trong cùng một khối.

Ví dụ:

{
    let animals = ["Dog", "Cat"];
}
// console.log(animals); //  Lỗi: animals is not defined (biến chỉ tồn tại trong block)

var – Có thể thay đổi nội dung và gán lại mảng mới nhưng có phạm vi rộng hơn

  • Khi khai báo một mảng bằng var:
  • Có thể thay đổi nội dung của mảng.
  • Có thể gán lại một mảng mới.

Phạm vi hoạt động (Function Scope) thay vì Block Scope, nghĩa là biến có thể bị truy cập bên ngoài {} nếu không nằm trong hàm.

Ví dụ:

var cities = ["Hanoi", "Saigon", "Danang"];

//  Có thể thay đổi nội dung của mảng
cities.push("Hue");
console.log(cities); // Output: ["Hanoi", "Saigon", "Danang", "Hue"]

// Có thể gán lại một mảng mới
cities = ["London", "New York"];
console.log(cities); // Output: ["London", "New York"]

Phạm vi hoạt động (Function Scope)

  • var không bị giới hạn trong block {}, mà chỉ bị giới hạn trong function.
  • Có thể khai báo lại cùng một tên biến trong cùng phạm vi.

Ví dụ:

{
    var numbers = [1, 2, 3];
}
console.log(numbers); //  Không lỗi, vẫn truy cập được ["1, 2, 3"]
Nhược điểm của var: Dễ gây lỗi khi biến bị truy cập hoặc thay đổi ngoài ý muốn.

Khi nào nên sử dụng const cho mảng trong JavaScript?

Trong JavaScript, const được sử dụng để khai báo biến mà không thể gán lại giá trị mới. Khi áp dụng với mảng, const giúp bảo vệ tham chiếu của mảng khỏi việc thay đổi, đồng thời vẫn cho phép thao tác với nội dung bên trong mảng. Dưới đây là những trường hợp nên sử dụng const cho mảng để tăng tính bảo mật, ổn định và dễ bảo trì trong lập trình.

Khi không muốn thay đổi tham chiếu của mảng nhưng vẫn cần thay đổi nội dung

Nếu bạn muốn bảo vệ tham chiếu của mảng để tránh việc vô tình gán lại một mảng mới nhưng vẫn cần thao tác thêm, xóa, hoặc cập nhật phần tử bên trong, const là lựa chọn tốt nhất.

const numbers = [1, 2, 3];

//  Có thể thay đổi nội dung mảng
numbers.push(4);
numbers[0] = 100;

console.log(numbers); // Output: [100, 2, 3, 4]

//  Không thể gán lại mảng mới
numbers = [10, 20, 30]; // Lỗi: Assignment to constant variable

Giải thích:

  • numbers.push(4) : Hợp lệ vì chỉ thay đổi nội dung của mảng.
  • numbers[0] = 100 : Hợp lệ vì chỉ thay đổi một phần tử bên trong mảng.
  • numbers = [10, 20, 30] : Lỗi vì const không cho phép gán lại mảng mới.

Kết bài

Sử dụng const để khai báo mảng trong JavaScript mang lại nhiều lợi ích quan trọng trong việc lập trình, giúp tăng tính ổn định, bảo mật dữ liệu và giảm thiểu lỗi do vô tình thay đổi giá trị của biến. Mặc dù const ngăn chặn việc gán lại một mảng mới, nhưng vẫn cho phép thay đổi nội dung bên trong, giúp lập trình viên linh hoạt khi làm việc với dữ liệu.

Bằng cách áp dụng const đúng lúc, đặc biệt trong các tình huống quản lý danh sách dữ liệu quan trọng như danh mục sản phẩm, quyền hạn người dùng hay cấu hình hệ thống, chúng ta có thể viết mã nguồn dễ hiểu, dễ bảo trì và đáng tin cậy hơn.

Bài viết liên quan

  • 2