Giải thích về reduce() trong JavaScript

Ngày đăng: 22/01/2021   -    Cập nhật: 12/03/2021
Chào bạn, reduce() trong JavaScript là một phương thức có thể khó hiểu đối với những người mới bắt đầu, đặc biệt là khi các giải thích trên mạng cũng rất mơ hồ.


Do đó, trong bài viết này, mình sẽ giúp bạn tìm hiểu về căn bản của phương thức reduce() trong JavaScript qua các ví dụ từ đơn giản đến phức tạp.



reduce() trong JavaScript


Hiểu được cách sử dụng reduce() có rất nhiều lợi ích sau này bởi khi học Front end (chuyên sâu), bạn sẽ sử dụng reduce() thường xuyên để quản lý state (hãy nghĩ đến Redux).


Cú pháp đơn giản của phương thức reduce() trong JavaScript là:




arr.reduce(reducerinitialValue);
 


> Lưu ý #1: initialValue (giá trị khởi tạo) là tùy chọn. Nếu bạn truyền vào đối số khởi tạo, phương thức reducer() sử dụng nó ở lần gọi đầu tiên.


Phương thức reduce() là gì?



Phương thức reduce() là:


  • Phương thức giảm mảng xuống thành một giá trị duy nhất.
  • Phương thức reduce() thực thi một hàm được cung cấp cho mỗi giá trị của mảng (từ trái sang phải).
  • Giá trị trả về của hàm được lưu trữ trong bộ tích lũy (kết quả / tổng).


> Lưu ý #2: reduce() không thực thi hàm đối với các phần tử mảng không có giá trị.

> Lưu ý #3: Phương thức này không thay đổi mảng ban đầu.



Reduce đi kèm với một số thuật ngữ như reducer và accumulator. Trong đó:


  • accumulator là giá trị mà chúng ta kết thúc
  • reducer là hành động mà chúng ta sẽ thực hiện để đạt được một giá trị.


Bạn phải nhớ rằng một reduce() sẽ chỉ trả về một giá trị duy nhất do đó nó tên là reduce.


Hàm call back truyền vào trong reduce()



Hàm call back (reducer) này có bốn đối số:



function reducer(accumulatorcurrentValuecurrentIndexarray) {}
 


Trong đó:


  • accumulator:  Bắt buộc. Giá trị được trả về từ lần gọi trước. Nếu bạn truyền giá trị khởi tạo cho phương thức reduce(), khi hàm call back này được thực thi lần đầu tiên, accumulator bằng giá trị khởi tạo.
  • currentValue: Bắt buộc. Giá trị của phần tử mảng trong lần lặp hiện tại.
  • currentIndex: Tùy chọn. Chỉ số của phần tử mảng trong lần lặp hiện tại.
  • arr: Tùy chọn. Mảng mà phương thức reduce() gọi và áp dụng hàm call back trên từng phần tử của nó.


Hàm reducer này thực thi trên mỗi phần tử và trả về một giá trị. Giá trị trả về này được gán cho đối số tích lũy (accumulator) trong mỗi lần lặp.


Ở lần lặp cuối cùng, giá trị của accumulator trở thành giá trị kết quả duy nhất.


Lấy ví dụ cổ điển sau:




let tong = 0;

const mangSo = [51015];

for (let i = 0i < mangSo.lengthi++) {
    tong += mangSo[i];
}
console.log(tong);
 


Kết quả:



30
 


Chương trình trên hoạt động tốt và tong có kết quả 30.


Nhưng chúng ta cũng có thể làm điều này với phương thức reduce() mà không làm thay đổi giá trị khởi tạo (Biến mà chúng ta gọi là initialValue (giá trị khởi tạo) trong cú pháp)




// Đây là giá trị khởi tạo của chúng ta
const giaTriKhoiTao = 0;

// Mảng số
const mangSo = [51015];

// Tạo hàm tính tổng. Hành động này lát nữa sẽ
// áp dụng lên trên mảng (hàm này sẽ được gọi lại)
const tinhTong = (boTichLuyphanTuHienTai=> {
    return boTichLuy + phanTuHienTai;
};

// Sử dụng reduce()
const tong = mangSo.reduce(tinhTonggiaTriKhoiTao);
console.log(tong);
 


Kết quả:



30
 


Chương trình trên nhìn có vẻ khó hiểu, nhưng chúng ta thêm console vào trong hàm tinhTong như sau:



// Đây là giá trị khởi tạo của chúng ta
const giaTriKhoiTao = 0;

/* Mảng số */
const mangSo = [51015];

// Tạo hàm tính tổng. Hành động này lát nữa sẽ
// áp dụng lên trên mảng (hàm này sẽ được gọi lại)
const tinhTong = (boTichLuyphanTuHienTai=> {
    console.log("Bộ tích lũy: " + boTichLuy);
    console.log("Phần hiện tại: " + phanTuHienTai);
    console.log("---");
    return boTichLuy + phanTuHienTai;
};

// Sử dụng reduce()
const tong = mangSo.reduce(tinhTonggiaTriKhoiTao);
console.log(tong);
 


Kết quả:



Bộ tích lũy: 0
Phần hiện tại: 5
---
Bộ tích lũy: 5
Phần hiện tại: 10
---
Bộ tích lũy: 15
Phần hiện tại: 15
---
30
 


Như vậy ta thấy, phương thức của chúng ta được gọi 3 lần vì mảng có 3 phần tử.


boTichLuy bắt đầu từ 0, đó là giá trị khởi tạo mà chúng ta đã truyền vào reduce().


Trên mỗi lần gọi hàm các phần tử hiện tại sẽ được cộng vào bộ tích lũy (là accumulator đó).


Cuối cùng, chúng ta có kết quả 30.


> Lưu ý #4: Hãy nhớ là hàm reduce() chỉ trả về giá trị duy nhất


Một ví dụ khác khá phổ biến trong lập trình web, giả sử chúng ta có giỏ hàng như sau:




// Giỏ hàng
let gioHang = [{
        sanPham: "iPhone 12",
        soLuong: 1,
        giaBan: 999
    },
    {
        sanPham: "RAM",
        soLuong: 1,
        giaBan: 50
    },
    {
        sanPham: "AirPods",
        soLuong: 2,
        giaBan: 250
    }
];
 


Bây giờ, nhiệm vụ của chúng ta là tính tổng giá trị của giỏ hàng ngày bằng cách lấy số lượng * giá bán.


Chúng ta sử dụng phương thức reduce() như sau:




// Tính tổng tiền phải trả bằng reduce()
let tongTien = gioHang.reduce(function(tongsp) {
    return tong + sp.soLuong * sp.giaBan;
}, 0);

// In ra tổng tiền của giỏ hàng
console.log(tongTien);
 


Kết quả ta được:



1549
 


> Lưu ý #5: Nếu bạn không truyền giá trị khởi tạo, lần lặp đầu tiên, nó sẽ lấy phần tử đầu tiên (1 đối tượng) để tính cộng => sẽ tính toán sai.


> Nếu bạn muốn học lập trình web nhanh hơn thì có thể tham gia KHÓA HỌC JAVA WEB hoặc HỌC LÀM WEB PHP (Dành cho sinh viên CNTT, người đi làm) trong 4.5 tháng.

> Hoặc KHÓA HỌC LẬP TRÌNH WEB (Full stack) dành cho dân ngoại đạo trong 12 tháng


Trên đây là một vài ví dụ đơn giản về phương thức reduce(), bây giờ chúng ta sẽ thử với ví dụ phức tạp hơn.



Làm phẳng một mảng bằng cách sử dụng reduce()



Giả sử chúng ta có mảng sau:



const mangSo = [12, [310, [1112]], [12, [34]], 56];
 


Và giả sử vì một số lý do điên rồ, JavaScript đã loại bỏ phương thức .flat, thế nên chúng ta phải tự làm phẳng mảng này.


Chúng ta sẽ viết một hàm để làm phẳng bất kỳ mảng nào bất kể các mảng được lồng sâu như thế nào:




function lamPhangMang(mang) {
    // Giá trị khởi tạo của chúng ta
    // trong trường hợp này là 1 mảng trống
    const giaTriKhoiTao = [];

    // Gọi reduce() trên mảng của chúng ta
    return mang.reduce((ketQuagiaTri=> {
        // Nếu giá trị là 1 mảng thì gọi đệ quy reduce
        // Nếu giá trị không phải 1 mảng thì cần nối
        // các giá trị lại với nhau
        return ketQua.concat(Array.isArray(giaTri) ? lamPhangMang(giaTri) : giaTri);
    }, giaTriKhoiTao);
}

const mangSo = [12, [310, [1112]], [12, [34]], 56];

// Làm phẳng mảng lồng sâu
console.log(lamPhangMang(mangSo));
 


Kết quả:



[1, 2, 3, 10, 11, 12, 12, 3, 4, 5, 6]
 


Việc làm phẳng mảng khá phổ biến đó, với reduce thì việc này cũng đã đơn giản đi hơn rất nhiều.


Thay đổi cấu trúc đối tượng với reduce()



Giả sử, máy chủ gửi cho chúng ta một đối tượng như thế này:



const duLieu = [
    { name: "Apple"country: "Mỹ" },
    { name: "Samsung"country: "Hàn Quốc" },
    { name: "Google"country: "Mỹ" }
];
 


Và chúng ta muốn chuyển đối tượng này thành như thế này:



const duLieuDaThayDoi = {
    Apple: { country: "Mỹ" },
    Samsung: { country: "Hàn Quốc" },
    Google: { country: "Mỹ" }
};
 


Để có được kết quả mong muốn, chúng ta thực hiện như sau:



const thayDoiCauTruc = data =>
    data.reduce((accitem=> {
        // Thêm key cho đối tượng
        acc[item.name] = { country: item.country };
        return acc;
    }, {});

console.log(thayDoiCauTruc(duLieu));
 


Tổng kết về reduce()



Như vậy, trong bài hướng dẫn này, mình đã giúp bạn tìm hiểu sơ bộ về cách hoạt động của phương thức reduce() trong JavaScript. Hi vọng nó giúp ích cho bạn.


Chúc bạn học tốt!


Tham khảo thêm:



---
HỌC VIỆN ĐÀO TẠO CNTT NIIT - ICT HÀ NỘI
Học Lập trình chất lượng cao (Since 2002). Học thực tế + Tuyển dụng ngay!
Đc: Tầng 3, 25T2, N05, Nguyễn Thị Thập, Cầu Giấy, Hà Nội
SĐT: 02435574074 - 0383.180086
Email: hello@niithanoi.edu.vn
Fanpage: https://facebook.com/NIIT.ICT/
 
#niit #niithanoi #niiticthanoi #hoclaptrinh #khoahoclaptrinh #hoclaptrinhjava #hoclaptrinhphp #java #php #python
Bình luận Facebook
Khóa học liên quan đến bài viết

KHÓA HỌC LẬP TRÌNH FRONT END VỚI REACT.JS

56 giờ
Học Lập trình Front end hiện đại với ReactJS. Học làm chủ HTML, CSS, JS và thư viện JavaScript phổ biến nhất hiện nay. Sẵn sàng đi thực tập / đi làm ngay sau khóa học.

Khóa học PHP Full stack [2023] cho người mới bắt đầu

96 giờ
Khóa học Lập trình PHP Full stack, phiên bản cập nhật lần thứ 8. Dạy Lập trình PHP bài bản từ Front end đến Back end + Laravel. Hướng dẫn làm 2 Dự Án Web lớn

KHÓA HỌC PYTHON HƯỚNG ĐỐI TƯỢNG

50 giờ
Khóa học giúp học viên sử dụng thành thạo ngôn ngữ Lập trình Python (3x). Hiểu và phát triển được Ứng dụng Web với Django Framework. Học thực hành với Giảng viên cao cấp.

Khóa học Java Full stack (IJFD)

104 giờ
Học lập trình Java Fullstack với khóa học được xây dựng theo lộ trình bài bản, từ JAVA CƠ BẢN đến JAVA WEB và nâng cao về JAVA FRAMEWORK như: Spring Boot, Hibernate
Mục lục
Đăng ký tư vấn
Nhân viên gọi điện tư vấn miễn phí sau khi đăng ký
Được cập nhật các ưu đãi sớm nhất
Hotline: 0383180086
Tên không được để trống
Số điện thoại không được để trống
Email không được để trống
Hãy đăng ký để nhận những thông tin mới nhất về học bổng mới nhất tại NIIT - ICT Hà Nội
top
Đóng lại Đăng ký học tại NIIT - ICT Hà Nội
6260+ học viên đã theo học tại NIIT - ICT Hà Nội và có việc làm tốt trong ngành lập trình. Nắm lấy cơ hội ngay hôm nay!
Chọn khóa học
  • KHÓA HỌC LẬP TRÌNH FRONT END VỚI REACT.JS
  • KHÓA HỌC LẬP TRÌNH PHP WEB
  • Khóa học PHP Full stack [2023] cho người mới bắt đầu
  • Khóa học BIG DATA với Hadoop và Spark
  • Khóa học Lập trình Android tại Hà Nội
  • [Tuyển sinh 2023] Lập trình viên Quốc tế DigiNxt
  • Khóa học Tiền lương & Phúc lợi (C&B Excel) tại Hà Nội
  • LẬP TRÌNH GAME
    • Khóa học Lập trình Game Unity
  • LẬP TRÌNH WEB FRONT END
    • KHÓA HỌC PYTHON HƯỚNG ĐỐI TƯỢNG
    • KHÓA HỌC ANGULAR & TYPESCRIPT (FRONT END)
  • LẬP TRÌNH WEB BACK END
    • LẬP TRÌNH JAVA WEB VỚI FRAME WORK
    • Lập trình Web với Django
    • Lập trình PHP với Laravel Framework
  • CHƯƠNG TRÌNH ĐÀO TẠO ỨNG DỤNG CÔNG NGHỆ
    • Khóa học Tiền lương & Phúc lợi (C&B Excel) tại TP HCM
  • LẬP TRÌNH WEB FULL STACK
    • Khóa học Java Full stack (IJFD)
  • LẬP TRÌNH MOBILE
    • FRONT-END VỚI REACTJS VÀ REACT NATIVE
    • Lập trình Android Nâng cao
  • ĐÀO TẠO CHO DOANH NGHIỆP
    • KHÓA HỌC BUSINESS ANALYSIC TỪ CƠ BẢN ĐẾN NÂNG CAO 2023
    • Khóa học Magento: Làm chủ CMS TMĐT lớn nhất
    • Khóa học IOT: Xây dựng Sản phẩm IOT với Raspberry Pi
    • Khóa học Automation Testing Chuyên nghiệp
  • KHÓA HỌC DỰ ÁN
    • Học sử dụng bộ Office: Word, Excel, Power Point, Mail chuyên nghiệp
  • KHÓA HỌC KHÁC
    • VBA Excel Toàn Tập (Cơ Bản - Nâng Cao)
    • VBA Excel Nâng cao
    • Khóa học JMeter: Performance Testing
    • Khóa học Tester đạt chuẩn Quốc tế ISTQB Foundation Level
    • Khoá Học Tester đạt chuẩn quốc tế ISTQB Advanced Level
Bạn chưa chọn khóa học cần đăng ký
Tên không được để trống
Số điện thoại không được để trống
Email không được để trống
Đăng ký học thành công!
Cảm ơn bạn đã đăng ký học tại NIIT - ICT HÀ NỘI!