Collections là gì?
Collections là một kiểu dữ liệu mà chúng ta hay thường sử dụng để lưu trữ dữ liệu có dạng một danh sách các giá trị, gọi dưới cái tên cụ thể là arrays, sets và maps.
Tại sao tôi cần quan tâm đến nó?
Trong Javascript, chúng ta thường xuyên phải làm việc với collection, đơn giản như việc trỏ lần lượt đến từng phần tử, lọc ra những thứ cần thiết, tìm một phần tử hoặc thậm chí giảm mảng ban đầu bằng nhiều cách khác nhau.
Có 3 phương thức chính để thao tác với collection là .map()
, .filter()
, và .reduce()
.
Nắm vững trong tay 3 phương thức này là một bước quan trọng để viết ra một đoạn code sạch
, rõ ràng và dễ hiểu.
Hãy bắt đầu mới một mảng chứa thông tin của các developer
sau:
1 2 3 4 5 6 7 8 | <span class="token keyword">let</span> developers <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'Bjarne Stroustrup'</span><span class="token punctuation">,</span> born<span class="token punctuation">:</span> <span class="token number">1950</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'James Gosling'</span><span class="token punctuation">,</span> born<span class="token punctuation">:</span> <span class="token number">1955</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'Linus Torvalds'</span><span class="token punctuation">,</span> born<span class="token punctuation">:</span> <span class="token number">1969</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">4</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'Guido van Rossum'</span><span class="token punctuation">,</span> born<span class="token punctuation">:</span> <span class="token number">1956</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'Ken Thompson'</span><span class="token punctuation">,</span> born<span class="token punctuation">:</span> <span class="token number">1943</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> |
Map pattern
Map sẽ áp dụng một function đến từng phân tử trong mảng và trả về một mảng mới với giá trị là kết quả khi chạy function đó.
Rườn ra thế là đủ rồi. Hiểu đơn giản như bây giờ chúng ta có một mảng object, nếu bạn muốn sửa đổi dữ liệu của từng phần tử, hoặc đơn giản chỉ là lấy ra những thuộc tính cần thiết thì hãy sử dụng .map()
.
Ví dụ như chúng ta chỉ cần lấy ra ngày sinh của từng developer thôi thì làm như thế nào nhỉ.
Input: Một mảng dữ liệu developers
Output: Một mảng dữ liệu chỉ chứa tên của các developer
Khi không dùng map():
Sử dụng for()
:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">var</span> <span class="token function-variable function">listNameEmployeesUsingFor</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>developers<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> listNames <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> developers<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> listNames<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>developers<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> listNames <span class="token punctuation">}</span> |
Sử dụng .forEach()
:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">var</span> <span class="token function-variable function">listNameEmployeesUsingForEach</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>developers<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> listNames <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> developers<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span>developer<span class="token punctuation">)</span> <span class="token punctuation">{</span> listNames<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>developer<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> listNames <span class="token punctuation">}</span> |
Và khi dùng map()
Sử dụng .map()
:
1 2 3 4 5 6 | <span class="token keyword">var</span> <span class="token function-variable function">listNameEmployeesUsingMap</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>developers<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> developers<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>developer <span class="token operator">=></span> developer<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// ["Bjarne Stroustrup", "James Gosling", "Linus Torvalds", "Guido van Rossum", "Ken Thompson"]</span> |
Chuyện gì vừa xảy ra vậy? Sao chỉ có 1 dòng mà đã ra được những cái kia. Hãy để tôi giải thích những gì đã xảy ra khi dùng map ở ví dụ trên nhé:
- Tạo 1 mảng mapArr
- Lặp qua các phần tử của mảng developers
- Gọi hàm mapFunc với phần tử hiện tại làm đối số
- Đẩy kết quả của mapFunc vào mảng mapArr
- Trả về mảng mapArr sau khi đã duyệt qua tất cả các phần tử
Khá là giống với việc sử dụng .for()
và .forEach
đúng không.
Ngoài ra bạn có thể xử lý dữ liệu (thêm, sửa đổi) thông qua map()
Giúp tôi lấy ra số tuổi của developer nào:
1 2 3 4 | developers<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>developer <span class="token operator">=></span> <span class="token number">2020</span> <span class="token operator">-</span> developer<span class="token punctuation">.</span>born<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [70, 65, 51, 64, 77]</span> |
Cách tạo ra hàm map()
Hàm .map()
có thể được thực hiện thông qua đệ quy.
1 2 3 4 5 6 7 | <span class="token keyword">const</span> <span class="token function-variable function">customMap</span> <span class="token operator">=</span> <span class="token punctuation">(</span>fn<span class="token punctuation">,</span> arr<span class="token punctuation">,</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span> result<span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=></span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length <span class="token operator">?</span> <span class="token function">customMap</span><span class="token punctuation">(</span>fn<span class="token punctuation">,</span> arr<span class="token punctuation">,</span> i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token operator">...</span>result<span class="token punctuation">,</span> <span class="token function">fn</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> result console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">customMap</span><span class="token punctuation">(</span>developer <span class="token operator">=></span> developer<span class="token punctuation">.</span>name<span class="token punctuation">,</span> developers<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// ["Bjarne Stroustrup", "James Gosling", "Linus Torvalds", "Guido van Rossum", "Ken Thompson"]</span> |
Filter Pattern
Filter sẽ áp dụng một function kiểm tra điều kiện duyệt qua từng phần tử một, sang đó trả về một mảng mới với dữ liệu chứa các phần tử đã pass điều kiện đó(trả về true).
Cái tên nói lên tất cả, bất kể khi nào bạn muốn lọc dữ liệu từ một mảng hãy sử dụng filter nhé.
Hãy bắt đầu với việc lấy ra những developer sinh sau năm 1950.
Input: Một mảng dữ liệu developers
Output: Một mảng dữ liệu chỉ chứa những developer sinh sau năm 1950
Cách tốt nhất
1 2 3 4 | <span class="token keyword">var</span> <span class="token function-variable function">listDevelopersOlder25UsingFilter</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>developers<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> developers<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>developer <span class="token operator">=></span> developer<span class="token punctuation">.</span>born <span class="token operator"><=</span> <span class="token number">1950</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Hãy đi từng bước để biết hàm .filter()
hoạt động như thế nào nha:
- Tạo một mảng trống filterArr.
- Lặp qua các phần tử mảng.
- Gọi đến hàm filterFunc với phần tử hiện tại làm đối số.
- Nếu kết quả là đúng, đẩy phần tử vào mảng filterArr.
- Trả về mảng filterArr sau khi đi qua tất cả các phần tử.
Khi không dùng filter
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">var</span> <span class="token function-variable function">listDevelopersOlder1950UsingForEach</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>developers<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> listOfAges <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> developers<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span>developer<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>developer<span class="token punctuation">.</span>born <span class="token operator"><</span> <span class="token number">1950</span><span class="token punctuation">)</span> listOfAges<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>developer<span class="token punctuation">.</span>born<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> listOfAges <span class="token punctuation">}</span> |
Và đây là kết quả trả về:
1 2 3 4 5 | <span class="token punctuation">[</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'Bjarne Stroustrup'</span><span class="token punctuation">,</span> born<span class="token punctuation">:</span> <span class="token number">1950</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'Ken Thompson'</span><span class="token punctuation">,</span> born<span class="token punctuation">:</span> <span class="token number">1943</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> |
Cách tạo ra hàm filter()
Chúng ta có thể tạo ra hàm filter() bằng cách sử dụng hàm đệ quy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">const</span> <span class="token function-variable function">customFilter</span> <span class="token operator">=</span> <span class="token punctuation">(</span>predicate<span class="token punctuation">,</span> arr<span class="token punctuation">,</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> res <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">predicate</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token function">customFilter</span><span class="token punctuation">(</span>predicate<span class="token punctuation">,</span> arr<span class="token punctuation">,</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token operator">...</span>res<span class="token punctuation">,</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token function">customFilter</span><span class="token punctuation">(</span>predicate<span class="token punctuation">,</span> arr<span class="token punctuation">,</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> res<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">customFilter</span><span class="token punctuation">(</span>developer <span class="token operator">=></span> developer<span class="token punctuation">.</span>born <span class="token operator"><=</span> <span class="token number">1950</span><span class="token punctuation">,</span> developers<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">/*[ { id: 1, name: 'Bjarne Stroustrup', born: 1950 }, { id: 5, name: 'Ken Thompson', born: 1943 } ]*/</span> |
Reduce Pattern
Reduce sẽ chuyển đổi mảng thành một giá trị bằng cách kết hợp từng phần tử lại với nhau.
Ví dụ như bạn có một mảng dữ liệu các bảng điểm các môn học, giờ bạn muốn biết điểm phẩy của mình thì reduce sẽ dẽ dàng giúp bạn tính toán và trả về điểm phẩy cho bạn.
Giờ chúng ta muốn biết năm sinh trung bình của các developer thì như thế nào nhỉ:
Input: Một mảng dữ liệu developers
Output: Năm sinh trung bình của các developer
Cách tốt nhất
Sử dụng .reduce()
, thật sự rất đơn giản:
1 2 3 | <span class="token keyword">var</span> averageYear <span class="token operator">=</span> developers<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span>acc<span class="token punctuation">,</span> developer<span class="token punctuation">)</span> <span class="token operator">=></span> acc <span class="token operator">+</span> developer<span class="token punctuation">.</span>born<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">/</span><span class="token punctuation">(</span>developers<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token number">1954.6</span> |
Khi không dùng reduce
1 2 3 4 5 6 7 8 | <span class="token keyword">var</span> sumOfYears <span class="token operator">=</span> <span class="token number">0</span> developers<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>developer <span class="token operator">=></span> <span class="token punctuation">{</span> sumOfYears <span class="token operator">+=</span> developer<span class="token punctuation">.</span>born <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> averageYear <span class="token operator">=</span> sumOfYears<span class="token operator">/</span><span class="token punctuation">(</span>developers<span class="token punctuation">.</span>length<span class="token punctuation">)</span> |
Bonus
Cách sử dụng join()
Nếu bạn muốn có được thông tin đây đủ của developer thì làm như thế nào?
1 2 3 4 | <span class="token keyword">const</span> <span class="token function-variable function">toString</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>developer<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> developer<span class="token punctuation">.</span>name <span class="token operator">+</span> <span class="token string">"was born in "</span> <span class="token operator">+</span> developer<span class="token punctuation">.</span>born <span class="token punctuation">}</span> |
Mọi thứ có vẻ ổn đấy, nhưng chúng ta nên viết như sau thì hơn đấy:
1 2 3 4 | <span class="token keyword">const</span> <span class="token function-variable function">toString</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>developer<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span>developer<span class="token punctuation">.</span>name<span class="token punctuation">,</span> <span class="token string">"was born in"</span><span class="token punctuation">,</span> developer<span class="token punctuation">.</span>born<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">" "</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Cách sử dụng .min() hoặc .max()
Việc so sánh 2 giá trị với nhau và sau đó trả về giá trị nhỏ hơn hoặc lớn hơn khá là phố biến đấy:
Cách điển hình để giải quyết vấn đề đó là:
1 2 3 | Math<span class="token punctuation">.</span>min<span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>Math<span class="token punctuation">,</span> <span class="token punctuation">(</span>developers<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>developer <span class="token operator">=></span> developer<span class="token punctuation">.</span>born<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token number">1946</span> |
Tại sao phải như vậy? Hàm Math.min()
sẽ trả về giá trị nhỏ nhất của bất kỳ tập hợp số nào đúng không. Mỗi tham số được truyền vào lần lượt chứ không phải là truyền thẳng vào một mảng. Để dễ hiểu hơn, hay xem ví dụ dưới đây:
1 2 3 4 5 | Math<span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token number">1</span> Math<span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span> <span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token number">NaN</span> |
Trước ES6/ES2015 .apply() function đã được dùng để giải quyết vấn đề đó.
Ngoài ra cũng có thể dùng Spread syntax (…) đối với ES6
1 2 3 4 5 6 7 | Math<span class="token punctuation">.</span>min<span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>Math<span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span> <span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token number">1</span> Math<span class="token punctuation">.</span>min<span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span> <span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token number">1</span> Math<span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token operator">...</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token number">1</span> |
Cách tạo ra hàm sum()
Hàm .sum () trả về tổng của tất cả các giá trị trong một mảng đã cho.
1 2 3 4 | <span class="token keyword">const</span> <span class="token function-variable function">sum</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>arr<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> arr<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span>b<span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Tham khảo
https://levelup.gitconnected.com/use-collections-wisely-in-javascript-c1440f2ff595
https://www.freecodecamp.org/news/how-to-write-your-own-map-filter-and-reduce-functions-in-javascript-ab1e35679d26/