iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
Modern Web

致 JavaScript 開發者的 Functional Programming 新手指南系列 第 27

Day 27 :第三方函式庫(2):從 Lodash.js 深入了解 JavaScript

  • 分享至 

  • xImage
  •  

Lodash 這個函式庫中,提供了高達上百種的方法,有些方法可以說是原生 JavaScript 的加強版,或是將原有的原型方法包裝成純函式。

除了在實務開發時,可以透過 Lodash 解決一些需要複雜運算才可以解決的問題,同時也可以透過 Lodash 所提供的方法,了解 JavaScript 的特性與進階用法,可以說是一個非常值得效仿學習的函式庫。

在這個章節中,我們要來聊聊,Lodash 提供哪些好用的 API ,讓我們可以簡化前端的複雜任務。

以下範例會主要會以 CDN 的方式進行程式碼的示範,若是想了解如何使用 UMD 的方式引入 Lodash,可以參考前面的章節,那就讓我們來看看 Lodash 中有哪些好用的方法吧!

Lodash 好用方法分享

filter 方法搭配進行條件篩選:

試想一個狀況,我們想要針對一個後台表單的內容進行複雜篩選,例如:後台管理者可以透過關鍵字搜尋,查找出指定的那一筆資料,如果我們要透過 JavaScript 來做到這件事,光是想就相當複雜,但如果是透過 Lodash 提供的 filter 方法,可以很快速的做到篩選的功能!

Lodash 所提供的 filter 方法其實與原生 JavaScript 的 filter 方法差異不大,原生的 filter 是使用串接的方式:

const ary = [1, 2, 3, 4, 5];
const filterAry = ary.filter(i => i> 2);
console.log(filterAry);
// [3, 4, 5]

而 Lodash 所提供的 filter() 方法,是基於 FP 設計模式,所以是使用帶入參數的方式使用,第一個參數帶入要進行篩選的陣列,第二個參數則是帶入進行條件篩選的 callback 函式:

const ary = [1, 2, 3, 4, 5];
const filterAry = _.filter(ary, i => i> 2);
console.log(filterAry);
// [3, 4, 5]

除了可以照原生的方式來使用 filter() 方法,Lodash 還為這個函式延伸出更多強大的功能,透過在第二個參數傳入物件、陣列或是字串來進行陣列的篩選,讓我們來看看以下範例:

const list = [
	{
		name: '王小明',
	},
	{
		name: '張小美',
	}
];
const filterByObj = _.filter(list, {name: '王小明'});
console.log(filterByObj);
const filterByAry = _.filter(list, ['name','王小明']);
console.log(filterByAry);
const filterByStr = _.filter(list, 'name');
console.log(filterByStr);
/* 
output 1 & 2:
 [{
		name: '王小明',
	},
	] 
   
 output 3:

[
	{
		name: '王小明',
	},
	{
		name: '張小美',
	}
];
*/

當在 Lodash filter() 方法第二個參數傳入:

  1. 物件:此物件會用來比對迭代中的物件是否有相同的屬性值,若有相同即將該迭代中的物件回傳至新陣列中。
  2. 陣列:此陣列會用來比對迭代中的物件是否有相同的屬性值(屬性值的排列順序要與物件經JSON.Stringify() 字串化之排列順序一致 ),若有相同即將該迭代中的物件回傳至新陣列中。
  3. 字串:檢查物件中是否有該屬性,若有相同即將該迭代中的物件回傳至新陣列中。

如果想要找到符合第一筆就停止資料的查找,我們還可以透過 Lodash 所提供的 find 方法來提升資料查找的效能,其使用方法與上述 filter 方法相同。

在以往的 FP 中,我們可以透過 filter 方法篩選我們所要的資料,來做到刪除特定資料的目的,但在 Lodash 中我們可以直接使用 reject 這個方法來達到相同的目標。

sorted 系列方法加快排序演算

在建置一些後台服務時,為了避免頻繁的呼叫 API 佔到自家後端的效能,有時我們可能會將排序的邏輯寫在前端頁面上,如此一來前端進行篩選或是排序的程式碼效能就會變得相當重要。

Lodash 提供一系列以 sorted 開頭的方法,讓我們可以透過二分搜尋法(binary search,請見註一)的方式優化排序的時間複雜度(註二),舉例來說,我們可以透過 sortedUniq 方法篩選陣列中的不重複純值。

const ary = ['王小明', '王小明', '張小花', '林小白'];
 
const sorted = _.sortedUniq(ary);
console.log(sorted);
// ["王小明","張小花","林小白"]

partition 方法條件式分類陣列

在 Lodash 中有提供許多將陣列進行展開、分類的方法,我們可以透過 partition 方法將陣列進行條件式的切割分類,使用的方式與 fitler 方法幾乎一樣,我們會在第二個參數中帶入篩選條件,這個條件可以是 callback function、物件、陣列或是字串。

這個方法會將符合條件的內容,封裝進陣列中,並作為另一個新陣列中的第一筆資料,不符合條件的則會封裝進另一個陣列,作為另一個新陣列中的第二筆資料:

const members = [
	{
		name: '王小明',
		verify: false,
	},
	{
		name: '張小花',
		verify: false,
	},
	{
		name: '林小白',
		verify: true,
	},
];

const groupedByCallback = _.partition(members, ({verify}) => !verify);
console.log(groupedByCallback);
/*
[
	[
		{
		name: '王小明',
		verify: false,
		},
		{
		name: '張小花',
		verify: false,
		},
	],
	[
		{
		name: '林小白',
		verify: true,
		},
	],
]
*/

個人認為 partition 方法非常好用,當需要進行同一資料的重複分類時,我們可以同時取到屬於、不屬於指定條件的資料,然後分別進行更進階的篩選,這樣就不用針對對一資料重複跑迴圈了。

flat 系列方法攤平資料結構

在先前的章節中,我們曾透過 JavaScript 中的 reduce() 陣列方法來攤平,或是依照自己的開發需求重整資料結構,但如果不想要這麼麻煩自己重寫一個,可以透過 Lodash 協助我們做到這件事:

const flattenAry = _.flatten([1, [2, [3, [4]], 5]]);
console.log(flattenAry);
// => [1, 2, [3, [4]], 5]

在上方的範例中,我們在 flatten() 函式中,傳入了多層級的的陣列,經過處理後,內部的階層被拆掉了一層,Lodash 函式庫提供了許多類似的方法,讓開發者可針對不同的資料結構進行淺層、深層的攤平。

is 系列方法檢查資料型別

在 JavaScript 中,「自動轉型」大概是最煩人的問題之一,如果我們想要檢查指定資料的型別,光靠 typeof() 運算子是沒有辦法獲得所有精準的型別,但我們可以透過 Lodash 做到許多型別的檢查:

//  在 JavaScript 中使用 typeof() 檢查 Date 型別的話,會印出 'object' 字串
typeof(new Date);
// => 'object'

const isDate1 = _.isDate(new Date);
console.log(isDate1);
// => true
 
const isDate2 = _.isDate('Mon April 23 2012');
console.log(isDate2);
// => false

舉例來說,我們可以透過 isDate() 方法檢查指定的資料是否為 Date 型別。

或是我們可以透過 isBoolean() 檢查某資料的型別是否為布林值:

const isBool1 = _.isBoolean(false);
console.log(isBool1);
// => true
 
const isBool2 = _.isBoolean(null);
console.log(isBool2);
// => false

Lodash 函式庫中提供了許多方便且能快速上手的工具方法,但如果你是一個柯里愛好者的話,另外一個函式庫也許會更對你的胃,在下一個章節中,我們要來介紹另外一個同樣知名的 FP 函式庫,那我們就下一個章節見啦!

註解:

  1. 二分搜尋法(binary search)指的是將資料折半,再把折半的資料繼續折半進行關鍵資料查找的一種演算法,這種演算法在資料處在複雜、最糟的排列,仍能保有 O(log n) 次的查找數。
  2. 時間複雜度指的是演算法到要完成目的所要執行的次數,通常會使用英文大寫 O 標記法來代表某演算法的執行次數的上限,常見的時間複雜度有 O(1)O(n)O(n^2)O(log n)。以前端常用的迴圈來說:
// *O(1):用 notation 一次找到我們所需要的值

const target1 = ary[0];
const target2 = obj.key;
const target3 = obj[key]*

// *O(n):透過迴圈進行遍歷查找

let  target4Index;
ary.forEach((item, index) => { 
	if(item === '小明') target4Index = index;
});

// O(n^2):迴圈中再包裹迴圈遍歷查找
let  target5Index;
ary.forEach( innerAry => { 
	innerAry.forEach((item, index) => { 
		if(item === '小明') target5Index = index;
});
// O(log n) 可快速透過 Lodash 函式庫做到
const target6Index = _.sortedIndexOf([4, 5, 5, 5, 6], 5);
console.log(target6Index)
// 1*

參考資料:

  1. Lodash.js
  2. wikipedia - binary search
  3. wikipedia - time complexity

上一篇
Day 26 :第三方函式庫(1):初識Lodash.js
下一篇
Day 28 :第三方函式庫 (3):從 Ramda.js 深入了解 JavaScript
系列文
致 JavaScript 開發者的 Functional Programming 新手指南30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言