Thứ năm, 09/04/2020 | 00:00 GMT+7

Cách triển khai các phương thức mảng JavaScript từ Scratch

JavaScript bao gồm một số hàm để làm việc với các mảng vượt ra ngoài vòng lặp for . Bạn có thể đã sử dụng các chức năng này trong các dự án của riêng mình và tự hỏi chúng hoạt động như thế nào và tại sao bạn lại sử dụng chúng thay thế nhau.

Một cách tốt để hiểu cách hoạt động của một thứ là xây dựng version của bạn từ đầu. Trong bài viết này, bạn sẽ làm điều đó bằng cách tạo các version bản map , filter , sort và thu reduce của bạn từ đầu. Khi hoàn thành, bạn sẽ hiểu rõ hơn về các chức năng này và công dụng của chúng.

Bằng cách kết hợp các Hàm mũi tên ES6 với các hàm Mảng JavaScript, bạn có thể viết mã cực kỳ mạnh mẽ và sạch sẽ.

Cách hoạt động của các phương thức mảng JavaScript

Hãy bắt đầu với một ví dụ. Giả sử bạn muốn lặp qua một mảng số, tăng từng phần tử một và trả về mảng mới. Trước đây, bạn cần phải làm một số điều để thực hiện điều này:

  • Khởi tạo một mảng trống mới.
  • Lặp lại từng phần tử trong mảng ban đầu.
  • Thay đổi phần tử đó và đặt giá trị đã thay đổi vào mảng mới.

Mã sẽ như thế này:

const arr = [1, 2, 3]; const newArray = [];  for (let i = 0; i < arr.length; i++) {     newArray[i] = arr[i] + 1; }  return newArray; 

Nhưng với chức năng map tích hợp, bạn có thể thực hiện điều này trong một dòng mã:

return arr.map(element => ++element); 

Các phương thức Mảng JavaScript tận dụng rất nhiều Hàm mũi tên ES6 .

Mỗi hàm Array ta sẽ đề cập đến việc chấp nhận một hàm như một tham số. Họ sẽ lặp qua từng phần tử của mảng và gọi hàm đó để xác định những việc cần làm với từng phần tử. Sau khi lặp qua từng phần tử và gọi hàm gọi lại, một mảng hoặc mục mới sẽ được trả về.

Yêu cầu

Để làm theo hướng dẫn này local , bạn cần một trình soạn thảo (chẳng hạn như Visual Studio Code ) và một tiện ích mở rộng môi trường sandbox (chẳng hạn như Quokka.js ).

Để làm theo hướng dẫn trực tuyến, bạn có thể sử dụng CodePen hoặc CodeSandbox .

Bước 1 - Triển khai Bản đồ

map lặp qua từng phần tử, biến đổi nó theo một cách nào đó, thêm nó vào một mảng mới và trả về mảng mới.

Cảnh báo : Trong bài viết này, bạn sẽ mở rộng các đối tượng global JavaScript với các hàm tùy chỉnh. Điều này chỉ dành cho mục đích giáo dục, vì thực hành này có khả năng gây ra các tác dụng phụ trong quy trình production .

Ví dụ, các hàm mảng trong JavaScript là một phần của nguyên mẫu Array, tương tự như các hàm trên một lớp trong Java. Để overrides chúng, bạn có thể gán một hàm mới cho Array.prototype .

Hãy tạo một hàm mới và gán nó cho Array.prototype.mapFromScratch :

const myCustomMapFunction = function(callback) {     console.log('My Custom Map Function!'); } Array.prototype.mapFromScratch = myCustomMapFunction;  const arr = [1, 2, 3];  arr.mapFromScratch(); 

Nếu bạn chạy mã này, bạn sẽ thấy thông báo log trong console :

Output
My Custom Map Function!

Bây giờ, thêm vòng lặp for và in ra từng phần tử. Do chính mảng gọi phương thức, bạn có quyền truy cập vào mảng đó bằng cách tham chiếu this :

const myCustomMapFunction = function(callback) {     console.log('My Custom Map Function!');      // 'this' refers to the array     for (let i = 0; i < this.length; i++) {         console.log(this[i]);     }  } 

Bây giờ, thực hiện bất kỳ chuyển đổi cần thiết nào bằng cách gọi hàm gọi lại. Khi bạn làm như vậy, bạn sẽ chuyển cho nó phần tử hiện tại và index hiện tại:

const myCustomMapFunction = function(callback) {     console.log('My Custom Map Function!');      // 'this' refers to the array     for (let i = 0; i < this.length; i++) {         const transformedElement = callback([this[i], i);     }  } 

Cuối cùng, thêm các phần tử đã biến đổi vào một mảng mới và trả về mảng đó.

const myCustomMapFunction = function(callback) {     console.log('My Custom Map Function!');      const newArray = [];      // 'this' refers to the array     for (let i = 0; i < this.length; i++) {         newArray[i] = callback(this[i], i);     }      return newArray; } 

Hãy xem chức năng được viết lại của bạn đang hoạt động bằng cách thử nghiệm nó với một hàm sẽ tăng từng giá trị trong mảng:

// arr = [1, 2, 3] // expected = [2, 3, 4]  console.log(arr.mapFromScratch((element) => ++element)); 

Bạn sẽ nhận được kết quả sau:

Output
My Custom Map Function! [2, 3, 4]

Trong bước này, bạn đã triển khai một chức năng map tùy chỉnh. Tiếp theo, ta hãy khám phá việc triển khai một chức năng filter .

Bước 2 - Triển khai bộ lọc

Hàm filter trả về một mảng phần tử mới được lọc từ mảng ban đầu.

Hãy tạo một hàm mới và gán nó cho Array.prototype.filterFromScratch :

const myCustomFilterFunction = function(callback) {     console.log('My Custom Filter Function!'); } Array.prototype.filterFromScratch = myCustomFilterFunction;  const arr = [1, 2, 3];  arr.filterFromScratch(); 

Bây giờ, hãy cài đặt vòng lặp for để lặp qua từng phần tử:

const myCustomFilterFunction = function(callback) {     console.log('My Custom Filter Function!');      const newArray = [];      for (let i = 0; i < this.length; i++) {         console.log(this[i]);     } } 

Bên trong vòng lặp for , bạn cần quyết định có thêm từng phần tử vào mảng mới hay không. Đây là mục đích của hàm gọi lại, vì vậy bạn sử dụng nó để thêm từng phần tử một cách có điều kiện. Nếu giá trị trả về là true , hãy đẩy phần tử vào mảng trả về:

const myCustomFilterFunction = function(callback) {     console.log('My Custom Filter Function!');      const newArray = [];      for (let i = 0; i < this.length; i++) {         if (callback(this[i])) {             newArray.push(this[i]);         }     }      return newArray; } 

Hãy xem chức năng được viết lại của bạn đang hoạt động bằng cách thử nghiệm nó với một hàm sẽ hiển thị các giá trị lớn hơn 1 :

// arr = [1, 2, 3] // expected = [2, 3]  console.log(arr.filterFromScratch((element) =>  element > 1)); 

Bạn sẽ nhận được kết quả sau:

Output
My Custom Filter Function! [2, 3]

Như vậy, bạn đã triển khai một chức năng filter tùy chỉnh. Tiếp theo bạn sẽ làm việc với chức năng sort .

Bước 3 - Thực hiện Sắp xếp

Hàm sort trả về một mảng được sắp xếp từ mảng ban đầu.

Hãy tạo một hàm mới và gán nó cho Array.prototype.sortFromScratch :

const myCustomSortFunction = function(callback) {     console.log('My Custom Sort Function!'); } Array.prototype.sortFromScratch = myCustomSortFunction;  const arr = [3, 2, 1];  arr.sortFromScratch(); 

Ta sẽ sử dụng Sắp xếp bong bóng để triển khai sắp xếp này. Đây là cách tiếp cận ta sẽ thực hiện:

  • Lặp lại nhiều lần qua các mục trong mảng.
  • So sánh các mục liền kề và swap nếu chúng không theo thứ tự.
  • Sau khi lặp qua mảng đủ số lần để thực hiện mỗi lần so sánh, mảng sẽ được sắp xếp.

Với Bubble Sort, bạn phải lặp lại toàn bộ mảng một lần cho mỗi phần tử trong mảng. Điều này yêu cầu một vòng lặp for lồng nhau for vòng lặp bên trong lặp lại thông qua việc dừng một đoạn ngắn của phần tử cuối cùng, vì vậy hãy thêm nó ngay bây giờ.

Lưu ý : Điều này nhằm mục đích giáo dục và không phải là một phương pháp hiệu quả để phân loại.

const myCustomSortFunction = function(callback) {     console.log('My Custom Sort Function!');      const newArray = [];      for (let i = 0; i < newArray.length; i++) {         for (let j = 0; j < newArray.length - 1; j++) {          }     } } 

Bạn cũng không muốn thay đổi mảng ban đầu. Để tránh điều này, bạn có thể sao chép mảng ban đầu vào mảng mới bằngToán tử Spread .

const myCustomSortFunction = function(callback) {     console.log('My Custom Sort Function!');      const newArray = [...this];      for (let i = 0; i < newArray.length; i++) {         for (let j = 0; j < newArray.length - 1; j++) {          }     } } 

Hàm gọi lại nhận hai tham số, phần tử hiện tại và phần tử tiếp theo, và sẽ trả về cho dù chúng có theo thứ tự hay không. Trong trường hợp của ta , nếu hàm gọi lại trả về một số lớn hơn 0 , ta muốn swap hai phần tử.

const myCustomSortFunction = function(callback) {     console.log('My Custom Sort Function!');      const newArray = [...this];      for (let i = 0; i < newArray.length; i++) {         for (let j = 0; j < newArray.length - 1; j++) {             if (callback(newArray[j], newArray[j + 1]) > 0) {                 // swap the elements             }         }     } } 

Để swap các phần tử, bạn tạo một bản sao của một phần tử, thay thế phần tử đầu tiên, sau đó thay thế phần tử thứ hai bằng bản sao. Khi hoàn tất, nó trả về mảng mới được sắp xếp.

const myCustomSortFunction = function(callback) {     console.log('My Custom Sort Function!');      const newArray = [...this];       for (let i = 0; i < newArray.length; i++){         for (let j = 0; j < newArray.length - 1; j++) {             if (callback(newArray[j], newArray[j + 1]) > 0) {                 const temp = newArray[j + 1];                 newArray[j + 1] = newArray[j];                 newArray[j] = temp;             }        }     }      // array is sorted     return newArray; } 

Hãy xem chức năng được viết lại của bạn đang hoạt động bằng cách thử nghiệm nó với một chức năng sắp xếp nhanh từ thấp đến cao:

// arr = [3, 2, 1] // expected = [1, 2, 3]  console.log(arr.sortFromScratch((current, next) => current - next)); 

Bạn sẽ nhận được kết quả sau:

Output
My Custom Sort Function! [1, 2, 3]

Đến đây bạn đã tạo một chức năng sort tùy chỉnh, bạn đã sẵn sàng chuyển sang triển khai chức năng reduce .

Bước 4 - Thực hiện Giảm

Hàm reduce lặp qua từng phần tử và trả về một giá trị duy nhất.

reduce không trả về một mảng mới giống như các hàm khác. Nó thực sự "giảm" các phần tử trong một mảng xuống một giá trị cuối cùng: một số, một chuỗi hoặc một đối tượng. Một trong những lý do phổ biến nhất để sử dụng reduce là khi bạn muốn tính tổng tất cả các phần tử trong một mảng số.

Hãy tạo một hàm mới và gán nó cho Array.prototype.reduceFromScratch :

const myCustomReduceFunction = function(callback) {     console.log('My Custom Reduce Function!'); } Array.prototype.reduceFromScratch = myCustomReduceFunction;  const arr = [1, 2, 3];  arr.reduceFromScratch(); 

Để reduce để trả về một giá trị cuối cùng, nó cần một giá trị bắt đầu để làm việc. Hàm gọi lại mà user chuyển qua sẽ xác định cách cập nhật bộ tích lũy này dựa trên từng phần tử của mảng và trả về ở cuối. Hàm gọi lại phải trả về bộ tích lũy được cập nhật.

Thêm vòng lặp for của bạn ngay bây giờ và thực hiện cuộc gọi đến chức năng gọi lại. Giá trị trả về trở thành bộ tích lũy mới. Sau khi vòng lặp kết thúc, bạn trả lại bộ tích lũy.

const myCustomReduceFunction = function(callback, accumulator) {     console.log('My Custom Reduce Function!');     for (let i = 0; i < this.length; i++) {         accumulator = callback(accumulator, this[i]);     }     return accumulator; } 

Hãy xem chức năng được viết lại của bạn đang hoạt động bằng cách thử nghiệm nó với một hàm tính tổng nội dung của một mảng:

// arr = [1, 2, 3] // expected = 6  console.log(arr.reduceFromScratch((accumulator, element) => accumulator + element, 0)); 
Output
My Custom Reduce Function! 6

Kết luận

Các hàm mảng của JavaScript cực kỳ hữu ích. Trong hướng dẫn này, bạn đã hoàn thành lại các hàm mảng để hiểu rõ hơn về cách chúng hoạt động để có thể sử dụng chúng hiệu quả hơn.


Tags:

Các tin liên quan

Các đống nhị phân và hàng đợi ưu tiên qua JavaScript
2020-04-05
JavaScript bất biến có thể thay đổi
2020-04-02
Hiểu các tham số mặc định trong JavaScript
2020-03-31
Cookie là gì và cách làm việc với chúng bằng JavaScript
2020-03-19
Tham quan nhanh về date-fns, Thư viện ngày JavaScript đơn giản
2020-03-18
Phương thức getOwnPropertyDescriptors trong JavaScript
2020-03-12
Cây tìm kiếm nhị phân thông qua JavaScript
2020-03-03
Tree Traversal qua JavaScript
2020-03-02
Hiểu về Trình tạo trong JavaScript
2020-02-28
Triển khai Thành phần Tab từ Scratch trong Vanilla JavaScript
2020-02-24