用ES6替換lodash的10大特徵

Lodash是目前最火的npm安裝包,但是如果你正在使用ES6,可能就不需要上lodash了。更多IT技術乾貨請鎖定

"朗妹兒"公眾號,每天都有更新。在本文中,我們將利用ES6的箭頭函數和其他新特徵覆蓋最常見的應用場景。

1. Map, Filter, Reduce

這些集合方法很優雅的處理數據,廣受支持,我們將使用剪頭函數來替代Lodash提供的這些功能。

1. _.map([1, 2, 3], function(n) { return n * 3; });
2. // [3, 6, 9]
3. _.reduce([1, 2, 3], function(total, n) { return total + n; }, 0);
4. // 6
5. _.filter([1, 2, 3], function(n) { return n <= 2; });
6. // [1, 2]
7.
8. // 使用ES6之後
9.
10. [1, 2, 3].map(n => n * 3);
11. [1, 2, 3].reduce((total, n) => total + n);
12. [1, 2, 3].filter(n => n <= 2);
lsl

這個示例只演示了部分功能,如果你用ES6,還可以使用find, some, every 以及 reduceRight 等方法。

2. Head & Tail

ES6的解構語法可以讓我們很輕鬆的訪問列表的頭尾。

1. _.head([1, 2, 3]);
2. // 1
3. _.tail([1, 2, 3]);
4. // [2, 3]
5.
6. // 使用ES6之後
7.
8. const [head, ...tail] = [1, 2, 3];

9. `

同樣可以很輕鬆訪問前後段結構。

1. _.initial([1, 2, 3]);
2. // -> [1, 2]
3. _.last([1, 2, 3]);
4. // 3
5.
6. // 使用ES6之後
7.
8. const [last, ...initial] = [1, 2, 3].reverse();

如果你覺得reverse方法改變了原有數據的值,你可以使用展開操作符(...target)複製數據然後再調用reverse方法

1. const xs = [1, 2, 3];
2. const [last, ...initial] = [...xs].reverse();

3. Rest & Spread

使用rest參數和spread展開操作符可以實現定義和調用動態變參函數。ES6引入這個語法真是大殺器。

1. var say = _.rest(function(what, names) {
2. var last = _.last(names);
3. var initial = _.initial(names);
4. var finalSeparator = (_.size(names) > 1 ? ', & ' : '');
5. return what + ' ' + initial.join(', ') +
6. finalSeparator + _.last(names);
7. });
8.
9. say('hello', 'fred', 'barney', 'pebbles');
10. // "hello fred, barney, & pebbles"
11.
12. // 使用ES6之後
13.
14. const say = (what, ...names) => {
15. const [last, ...initial] = names.reverse();
16. const finalSeparator = (names.length > 1 ? ', &' : '');

17. return `${what} ${initial.join(', ')} ${finalSeparator} ${last}`;
18. };
19.
20. say('hello', 'fred', 'barney', 'pebbles');
21. // "hello fred, barney, & pebbles"
javascript

4. Curry

沒有TypeScript或者Flow這樣高級語言,要實現函數簽名curry是非常困難的。當我們接受一個curry函數的時候內心是崩潰的,想要知道到底支持多少個參數?調用鏈的下一個參數是什麼?完全一頭懵逼。箭頭函數顯式的定義方式提高了可讀性,拯救了curry函數。

1. function add(a, b) {
2. return a + b;
3. }
4. var curriedAdd = _.curry(add);
5. var add2 = curriedAdd(2);
6. add2(1);
7. // 3
8.
9. // 使用ES6之後
10.
11. const add = a => b => a + b;
12. const add2 = add(2);
13. add2(1);
14. // 3

這種顯式的curry剪頭函數也方便了調試。

1. var lodashAdd = _.curry(function(a, b) {
2. return a + b;
3. });
4. var add3 = lodashAdd(3);
5. console.log(add3.length)
6. // 0
7. console.log(add3);
8. //function wrapper() {

9. // var length = arguments.length,
10. // args = Array(length),
11. // index = length;
12. //
13. // while (index--) {
14. // args[index] = arguments[index];
15. // }…
16.
17. // 使用ES6之後
18.
19. const es6Add = a => b => a + b;
20. const add3 = es6Add(3);
21. console.log(add3.length);
22. // 1
23. console.log(add3);
24. // function b => a + b

如果我們還在使用lodash/fp或者ramda這樣的函數式庫,我們也可以使用箭頭移除對lodash風格的依賴。

1. _.map(_.prop('name'))(people);
2.
3. // 使用ES6之後
4.
5. people.map(person => person.name);
less

5. Partial

就像curry特徵,使用剪頭函數同樣也可以使partial簡單易懂。

1. var greet = function(greeting, name) {
2. return greeting + ' ' + name;
3. };
4.
5. var sayHelloTo = _.partial(greet, 'hello');
6. sayHelloTo('fred');
7. // "hello fred"
8.
9. // 使用ES6之後
10.
11. const sayHelloTo = name => greet('hello', name);

12. sayHelloTo('fred');
13. // "hello fred"

也可以使用rest參數和spread操作符

1. const sayHelloTo = (name, ...args) => greet('hello', name, ...args);
2. sayHelloTo('fred', 1, 2, 3);
3. // "hello fred"

6. Operators

Lodash重新實現了運算符函數,並提供了一整套函數,這樣運算符函數就可以傳遞到其他集合類方法中。

其實在大多數情況下,使用箭頭函數就足夠簡單了,我們完全可以直接改為使用剪頭函數。

1. _.eq(3, 3);
2. // true
3. _.add(10, 1);
4. // 11
5. _.map([1, 2, 3], function(n) {
6. return _.multiply(n, 10);
7. });
8. // [10, 20, 30]
9. _.reduce([1, 2, 3], _.add);
10. // 6
11.
12. // 使用ES6之後
13.
14. 3 === 3
15. 10 + 1
16. [1, 2, 3].map(n => n * 10);
17. [1, 2, 3].reduce((total, n) => total + n);
18. `

7. Paths

很多lodash函數用字符串或者數組來處理路徑問題。我們完全可以使用剪頭函數來代替這種處理方式。

1. var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
2.
3. _.at(object, ['a[0].b.c', 'a[1]']);
4. // [3, 4]
5. _.at(['a', 'b', 'c'], 0, 2);
6. // ['a', 'c']
7.
8. // 使用ES6之後
9.
10. [
11. obj => obj.a[0].b.c,
12. obj => obj.a[1]
13. ].map(path => path(object));
14.
15. [
16. arr => arr[0],
17. arr => arr[2]
18. ].map(path => path(['a', 'b', 'c']));

因為這些路徑是純函數,我們可以對其進行自由組合。

1. const getFirstPerson = people => people[0];
2. const getPostCode = person => person.address.postcode;
3. const getFirstPostCode = people => getPostCode(getFirstPerson(people));

甚至可以定義接受變參的高階路徑。

1. const getFirstNPeople = n => people => people.slice(0, n);
2.
3. const getFirst5People = getFirstNPeople(5);
4. const getFirst5PostCodes = people => getFirst5People(people).map(getPostCode);

8. Pick

在lodash中可以通過pick從一個目標對象中選擇想要的屬性。 在ES6中通過解構和簡單的對象遍歷可以達到相同的結果。

1. var object = { 'a': 1, 'b': '2', 'c': 3 }; 

2.
3. return _.pick(object, ['a', 'c']);
4. // { a: 1, c: 3 }
5.
6. // 使用ES6之後
7.
8. const { a, c } = { a: 1, b: 2, c: 3 };
9.
10. return { a, c };

9. Constant, Identity, Noop

Lodash提供了一些工具來處理一些特殊場景。

1. _.constant({ 'a': 1 })();
2. // { a: 1 }
3. _.identity({ user: 'fred' });
4. // { user: 'fred' }
5. _.noop();
6. // undefined

在ES6裡面完全可以用剪頭函數來實現。

1. const constant = x => () => x;
2. const identity = x => x;
3. const noop = () => undefined;

或者換一個方式

1. (() => ({ a: 1 }))();
2. // { a: 1 }
3. (x => x)({ user: 'fred' });
4. // { user: 'fred' }
5. (() => undefined)();
6. // undefined

10. Chaining & Flow

Lodash提供了編寫鏈接語句(Chained Statements)的函數功能。在大部分場景下,lodash內置的這些集合方法實現了鏈式調用,但是有些情況下,這些方法會修改集合的內部結構,這是不能接受的。

還好,我們可以用ES6的剪頭函數數組實現同樣的功能。

1. _([1, 2, 3])
2. .tap(function(array) {
3. // Mutate input array.
4. array.pop();
5. })
6. .reverse()
7. .value();
8. // [2, 1]
9.
10. // 使用ES6之後
11.
12. const pipeline = [
13. array => { array.pop(); return array; },
14. array => array.reverse()
15. ];
16.
17. pipeline.reduce((xs, f) => f(xs), [1, 2, 3]);

在這種方式下,我們根本不需要去考慮tap和thru的區別,而是將其封裝在一個函數里面,成為一個更通用的工具。

1. const pipe = functions => data => {
2. return functions.reduce(
3. (value, func) => func(value),
4. data
5. );
6. };
7.
8. const pipeline = pipe([
9. x => x * 2,
10. x => x / 3,
11. x => x > 5,
12. b => !b
13. ]);
14.
15. pipeline(5);
16. // true
17. pipeline(20);
18. // false
19. Conclusion

dart

Lodash依然是一個偉大的函數庫,這篇文章不是要推翻lodash,而是想給大家一個全新的視角去看待問題,去看看新版JavaScript提供的解決問題的新能力,而在此之前,我們不得不依賴第三方庫才能實現。

記得下一次你要發明輪子的時候,想想是不是有更簡單的方式來處理。


分享到:


相關文章: