HomeLập trìnhJavaScriptPhương thức reduce...

Phương thức reduce và reduceRight của JavaScript hoạt động như thế nào


reducereduceRight là hai phương thức mảng JavaScript tích hợp có một chút đường cong học tập dốc.

Nhưng bản chất của các phương pháp này cũng đơn giản như các phép tính số học sau đây.

Giả sử chúng ta có một dãy số:

[1, 2, 3, 4]

Và chúng tôi muốn lấy tổng của chúng.

Các reduce cách để có được tổng tương tự như:

((((1) + 2) + 3) + 4)

Trong khi reduceRight cách để có được tổng tương tự như:

((((4) + 3) + 2) + 1)

Với reducereduceRight, bạn có thể xác định dấu + của riêng mình. Các phần tử của mảng cũng có thể là bất kỳ thứ gì. Nghe có vẻ thú vị, phải không?

nghĩ về reducereduceRight không là gì ngoài sự tổng quát hóa của các mẫu số học ở trên. Trong bài viết này, chúng tôi sẽ đề cập đến tất cả các chi tiết quan trọng.

Bài viết này sử dụng cách tiếp cận thuật toán dễ hiểu để cho bạn thấy cách giảm hoạt động trong JavaScript.

Tôi cũng đã tạo một video để cho bạn thấy các phương pháp này hoạt động như thế nào. Hãy xem nếu muốn tìm hiểu các khái niệm từ một góc độ trực quan hơn:

Mục lục


1Cái gì được rút gọn thành cái gì? §

Bạn có thể tự hỏi, “Loại giảm nào xảy ra khi sử dụng reduce hoặc reduceRight?”

Ở đây, phép rút gọn phản ánh một cách chuyển đổi cụ thể (mà chúng ta sẽ thấy chi tiết) các phần tử trong một mảng thành một giá trị duy nhất tương tự như các phép tính số học mà chúng ta đã thấy ở trên.

Nhưng lưu ý rằng giá trị đầu ra có thể là bất cứ thứ gì. Vì vậy, nó có thể là một giá trị trông lớn hơn mảng ban đầu mà phương thức được gọi.

Trong lập trình chức năng ngôn ngữ, ý tưởng giảm có nhiều tên khác như gập lại, tích trữ, tổng hợp, nén và ngay cả tiêm.

2thông số của reduce/reduceRight
§

Cả hai phương pháp này đều có cùng quy tắc để gọi chúng. Vì vậy, thật dễ dàng để tìm hiểu chúng cùng nhau. Hãy xem làm thế nào họ có thể được gọi là:

let myArray      = [/* an array */];
let callbackfn   = /* A function value */ ;
let initialvalue = /* any value */ ;

myArray.reduce(callbackfn)
myArray.reduce(callbackfn, initialValue)

myArray.reduceRight(callbackfn)
myArray.reduceRight(callbackfn, initialValue)

Ở đây việc sử dụng các tham số của reduce/reduceRight được giải thích thông qua callbackfninitialValue biến:

Đọc thêm  Hai cách để xác nhận kết thúc của Chuỗi trong JavaScript

callbackfn: Nó phải là một chức năng. Trong khi lặp lại mảng, đối với mỗi phần tử, reduce/reduceRight cuộc gọi callbackfn với 4 đối số. Giả sử các biến previousValue, currentElement, indexarray giữ các giá trị của các đối số đó, tương ứng. Vì vậy, cuộc gọi nội bộ đến callbackfn trông như thế này:

callbackfn(previousValue, currentElement, index, array)

Bây giờ hãy xem ý nghĩa của các giá trị đó:

  1. previousValue: Đây còn được gọi là bộ tích điện. Tóm lại, giá trị này đại diện cho “công việc đang tiến hành” của giá trị trả về của phương thức. Giá trị này bao gồm những gì sẽ trở nên hoàn toàn rõ ràng khi bạn nghiên cứu thuật toán được trình bày ở phần sau của bài viết này.
  2. currentElement: Phần tử hiện tại.
  3. index: Chỉ số của phần tử hiện tại.
  4. array: myArray.

Giá trị trả về của callbackfn: Đối với cuộc gọi cuối cùng đến callbackfngiá trị trả về của nó trở thành giá trị trả về của reduce/reduceRight. Nếu không, giá trị trả về của nó sẽ được đưa ra là previousValue cho cuộc gọi tiếp theo tới callbackfn.

Và cuối cùng, initialValue: Đây là giá trị ban đầu tùy chọn cho previousValue (bộ tích lũy). Nếu nó được đưa ra, và myArray có một số yếu tố trong đó, cuộc gọi đầu tiên đến callbackfn sẽ nhận giá trị này như previousValue.

Ghi chú: Các callbackfn thường được gọi là một chức năng giảm tốc(hoặc chỉ bộ giảm tốc gọi tắt).

3hiểu biết reduce/reduceRight với sơ đồ §

Sự khác biệt duy nhất giữa reducereduceRight là hướng của vòng lặp. reduce lặp qua các phần tử mảng từ trái sang phải. Và reduceRight lặp qua các phần tử từ phải sang trái.

Hãy xem cách bạn có thể sử dụng reduce/reduceRight để tham gia một mảng các chuỗi. Lưu ý cách đạt được đầu ra cuối cùng bằng cách nối các phần tử mảng từng bước theo cả hai hướng:

rút gọn sơ đồ1-1
Biểu đồ thể hiện sự khác biệt giữa reducereduceRight

Ở đây lưu ý rằng:

  • acc được sử dụng để truy cập previousValue .
  • curVal được sử dụng để truy cập currentElement.
  • Đầu vào hình tròn để r đại diện curVal.
  • Đầu vào hình chữ nhật để r đại diện acc hoặc bộ tích lũy.
  • Các giá trị ban đầu có dạng hình chữ nhật, bởi vì chúng được nhận bởi r như accS.

4thuật toán của reduce/reduceRight
§

Thuật toán 29 dòng dưới đây thoạt nhìn có vẻ đáng sợ. Nhưng bạn có thể sẽ thấy nó dễ hiểu hơn nhiều so với việc tiêu hóa hàng đống câu dài giải thích các chi tiết phức tạp của các phương pháp này.

Đọc thêm  find() so với filter() trong JavaScript – Sự khác biệt được giải thích bằng các ví dụ

Ghi chú: Thuật toán được mô tả ở đây có ngữ cảnh của phần “Tham số của reduce/reduceRight”. (Tức là các biến myArray, callbackfninitialValue đến từ phần đó.)

Vì vậy, hãy thư giãn, tận hưởng các bước và đừng quên thử nghiệm trong bảng điều khiển:

  • 1

    Nếu initialValue là quà tặng,

    • 2

      Nếu myArray không có phần tử,

    • 4

      Khác

      • 5

        Để cho accumulator thì là ở initialValue.

      • 6

        Nếu phương pháp là reduce,

        • 7

          Để cho startIndex là chỉ số của phần tử ngoài cùng bên trái của myArray.

      • số 8

        Nếu phương pháp là reduceRight,

        • 9

          Để cho startIndex là chỉ số của phần tử ngoài cùng bên phải của myArray.

  • 10

    Khác

    • 11

      Nếu myArray không có phần tử,

    • 13

      khác nếu myArray chỉ có một phần tử duy nhất,

    • 15

      Khác

      • 16

        Nếu phương pháp là reduce,

        • 17

          Để cho accumulator là phần tử ngoài cùng bên trái của myArray.

        • 18

          Để cho startIndex là chỉ số của phần tử đứng ngay sau phần tử ngoài cùng bên trái của myArray.

      • 19

        Nếu phương pháp là reduceRight,

        • 20

          Để cho accumulator là phần tử ngoài cùng bên phải của myArray.

        • 21

          Để cho startIndex là chỉ số của phần tử đứng ngay trước phần tử ngoài cùng bên phải của myArray.

  • 22

  • 23

    Nếu phương pháp là reduce,

    • 24

      Theo thứ tự từ trái sang phải, với mỗi phần tử của myArray sao cho nó là chỉ số istartingIndex,

      • 25

        Bộ accumulator đến callbackfn(accumulator, myArray[i], i, myArray).

  • 26

    Nếu phương pháp là reduceRight,

    • 27

      Theo thứ tự từ phải sang trái, với mỗi phần tử của myArray sao cho nó là chỉ mục istartingIndex,

      • 28

        Bộ accumulator đến callbackfn(accumulator, myArray[i], i, myArray).

  • 29

    Trở lại accumulator.

Ghi chú: Một mảng có thể có độ dài lớn hơn nhưng không có phần tử. Những chỗ trống như vậy trong mảng thường được gọi là hố trong mảng. Ví dụ:

let arr = [,,,,];
console.log(arr.length);
// 4

// note that trailing comma doesn't increase the length.
// This feature enables us to add a new element quickly.

Các phương thức này chỉ gọi callbackfn cho các yếu tố của myArray mà thực sự tồn tại. Ví dụ: nếu bạn có một mảng như [1,,3,,5]họ sẽ không xem xét các yếu tố không tồn tại tại các chỉ số 13. Hãy thử đoán những gì sẽ được ghi lại sau khi chạy như sau:

[,,,3,,,4].reduce((_, cv, i) => {
  console.log(i);
});

Nếu bạn nói 6bạn đúng rồi!

⚠️ Cảnh báo: Không nên sửa đổi myArray bên trong của callbackfn vì nó làm phức tạp logic mã của bạn và do đó làm tăng khả năng xảy ra lỗi.

Nếu bạn đã đọc và hiểu đến đây, xin chúc mừng! Bây giờ bạn nên có một sự hiểu biết vững chắc về cách reduce/reduceRight làm.

Đây là thời điểm tuyệt vời để giải quyết một số vấn đề để làm quen reduce/reduceRight. Trước khi xem các giải pháp, hãy tự giải quyết chúng hoặc ít nhất là dành thời gian suy nghĩ về nó.

5Bài tập §

5.1Mảng lồng phẳng §

Viết một chức năng flatten có thể làm phẳng một mảng lồng nhau.

let arr = [1, [2, [3], [[4], 5], 6]];
console.log(flatten(arr));
// [1, 2, 3, 4, 5, 6]

Dung dịch
    
const flatten = (arr) => 
  arr.reduce((acc, curVal) =>
    acc.concat(Array.isArray(curVal) ? flatten(curVal) : curVal), []);
    
  

5.2Loại bỏ các mục trùng lặp khỏi một mảng §

Viết một chức năng rmDuplicates loại bỏ các mục trùng lặp như bên dưới:

console.log(rmDuplicates([1, 2, 2, 3, 4, 4, 4]));
// [1, 2, 3, 4]

Dung dịch
    
const rmDuplicates = arr => 
  arr.reduce((p, c) => p.includes(c) ? p : p.concat(c), []);
    
  

5.3Đảo ngược một mảng mà không thay đổi nó §

Có một tích hợp reverse phương pháp mảng để đảo ngược mảng. Nhưng nó làm thay đổi mảng ban đầu. Sử dụng reduceRight để đảo ngược một mảng mà không làm biến đổi nó.

Dung dịch
    
let arr = [1, 2, 3];

let reversedArr = arr.reduceRight((acc, curVal) => [...acc, curVal], []);

console.log(arr);
// [1, 2, 3]

console.log(reversedArr);
// [3, 2, 1]
    
  

Lưu ý rằng bằng cách đảo ngược mảng theo cách này, bạn sẽ mất tất cả các lỗ trong mảng.

6Phần kết luận §

Khi nào reduce/reduceRight cuộc gọi callbackfn trong nội bộ, chúng ta có thể gọi những kiểu gọi đó là “hành vi bình thường” và chúng ta có thể coi các tình huống khác là trường hợp cạnh. Những điều này có thể được tóm tắt trong bảng dưới đây:

Giá trị ban đầu Số phần tử đầu ra
Hiện nay trường hợp cạnh: Giá trị ban đầu
Hiện nay Lớn hơn 0 hành vi bình thường
Không có mặt trường hợp cạnh: LoạiLỗi
Không có mặt 1 trường hợp cạnh: Yếu tố đó
Không có mặt Lớn hơn 1 hành vi bình thường

Học hỏi reduce/reduceRight liên quan nhiều hơn một chút so với các phương thức mảng bậc cao khác. Nhưng nó đáng để bạn dành thời gian để học nó thật tốt.

Cảm ơn bạn đã đọc! Tôi hy vọng bài viết này là hữu ích. Nếu bạn muốn, bạn có thể kiểm tra trang web của tôi và theo dõi tôi trên Twitter và LinkedIn.

Mừng giảm 😃





Zik.vn – Biên dịch & Biên soạn Lại

spot_img

Create a website from scratch

Just drag and drop elements in a page to get started with Newspaper Theme.

Buy Now ⟶

Bài viết liên quang

DMCA.com Protection Status