Cập nhật mảng bất biến bằng Array.prototype.with

Gần đây, các trình duyệt đã có được một phương thức mới có khả năng tương tác mà bạn có thể gọi trên Arrays: Array.prototype.with().

Hỗ trợ trình duyệt

  • 110
  • 110
  • 115
  • 16

Nguồn

Bài viết này tìm hiểu cách hoạt động và cách sử dụng phương thức này để cập nhật một mảng mà không làm thay đổi mảng gốc.

Giới thiệu về Array.prototype.with(index, value)

Phương thức Array.prototype.with(index, value) trả về một bản sao của mảng được gọi trong đó index được đặt thành value mới mà bạn cung cấp.

Ví dụ sau đây cho thấy một mảng độ tuổi. Bạn muốn tạo một bản sao mới của mảng trong khi thay đổi độ tuổi thứ hai từ 15 thành 16:

const ages = [10, 15, 20, 25];

const newAges = ages.with(1, 16);
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] (unchanged)

Chia nhỏ mã:: ages.with(...) trả về bản sao của biến ages mà không sửa đổi mảng gốc. ages.with(1, …) thay thế mục thứ hai (index = 1). ages.with(1, 16) gán mục thứ hai cho 16.

Đây là cách bạn có thể tạo bản sao mới của mảng có nội dung sửa đổi.

Điều này khá hữu ích khi bạn muốn đảm bảo rằng mảng ban đầu không bị thay đổi. Bài viết này đề cập đến một số trường hợp sử dụng cho việc này. Nhưng bây giờ, hãy xem điều gì đã xảy ra nếu bạn sử dụng ký hiệu dấu ngoặc:

const ages = [10, 15, 20, 25];

const newAges = ages;
newAges[1] = 16;
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 16, 20, 25] (Also changed 🙁)

Như bạn có thể thấy, biến ages cũng đã được sửa đổi trong ví dụ này. Lý do là khi bạn chỉ định ages = newAges, JavaScript sẽ không sao chép mảng mà thay vào đó sẽ tạo một tham chiếu đến mảng khác. Vì vậy, bất kỳ thay đổi nào trong một thay đổi cũng sẽ ảnh hưởng đến quảng cáo còn lại khi cả hai đều trỏ đến cùng một mảng.

Array.prototype.with() và tính bất biến

Tính bất biến là yếu tố cốt lõi của nhiều thư viện và khung giao diện người dùng, chẳng hạn như: React (và Redux) và Vue

Ngoài ra, các thư viện và khung khác không nhất thiết yêu cầu tính bất biến, nhưng chúng tôi khuyến khích việc này mang lại hiệu suất tốt hơn: Angular và Lit

Vì vậy, nhà phát triển thường phải sử dụng các phương thức khác trả về bản sao của các mảng làm giảm khả năng đọc của mã:

const ages = [10, 15, 20, 25];

const newAges = ages.map((age, index) => {
    if (index === 1) {
         return 16;
    }
    return age;
});

console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] (Remains unchanged)

Dưới đây là một Codepen mẫu về cách sử dụng .with() trong React kết hợp với useState để cập nhật một mảng mục bất biến:

Vì phương thức .with() trả về bản sao của mảng, nên bạn có thể liên kết nhiều lệnh gọi .with() hoặc thậm chí là các phương thức mảng khác. Ví dụ sau minh hoạ việc gia tăng độ tuổi thứ hai và thứ ba từ mảng:

const ages = [10, 15, 20, 25];

const newAges = ages.with(1, ages[1] + 1).with(2, ages[2] + 1)

console.log(newAges); // [10, 16, 21, 25]
console.log(ages); // [10, 15, 20, 25] (unchanged)

Các phương thức mới không thể thay đổi

Gần đây, 3 phương thức khác có khả năng tương tác:

Theo MDN, ba phương thức này là phiên bản sao chép của các phương thức tương ứng. Bạn cũng có thể sử dụng các phương thức này khi dự kiến hoặc ưu tiên tính bất biến.

Tóm lại, bạn có thể dễ dàng cập nhật bất biến bất biến trong JavaScript bằng một trong 4 phương thức được trình bày trong bài viết này. Cụ thể, phương thức .with() giúp bạn dễ dàng cập nhật một phần tử duy nhất của mảng mà không cần thay đổi mảng gốc.