可以使用ES6取代的10个Lodash特性

Lodash常常需要依赖于npm包,但如果使用ES6,你可能不再需要依赖于npm包。在这篇文章中,收集和整理了一些方法和ES6的新特性,这些示例都是来自一些经典的用例中。

Map, Filter, Reduce

收集的这些方法可以用来转换数据,而且它们普遍都得到了支持,我们使用箭头函数特性能让这些写得更为简单。

_.map([1, 2, 3], function(n) { return n * 3; });
// [3, 6, 9]
_.reduce([1, 2, 3], function(total, n) { return total + n; }, 0);
// 6
_.filter([1, 2, 3], function(n) { return n <= 2; });
// [1, 2]

// 可以换成这样

[1, 2, 3].map(n => n * 3);
[1, 2, 3].reduce((total, n) => total + n);
[1, 2, 3].filter(n => n <= 2);

支持的不仅仅这些,如果使用ES6的Polyfill,还可以使用findsomeeveryreduceRight

Head 和 Tail

Destructuring语法让我们可以在不实用的函数使用headtail处理列表。

_.head([1, 2, 3]);
// 1
_.tail([1, 2, 3]);
// [2, 3]

// 换成

const [head, ...tail] = [1, 2, 3];

也可以使用类似的方式获取初始的元素和最后一个元素。

_.initial([1, 2, 3]);
// -> [1, 2]
_.last([1, 2, 3]);
// 3

// 换成

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

如果你觉得reverse让数组反转排列烦人,那么可以在调用reverse之前使用[]来克隆数组。

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

Rest 和 Spread

restspread函数允许我们定义和调用的函数接受可变的数字参数。这两个功能在ES6中引入了专门的语法。

var say = _.rest(function(what, names) {
  var last = _.last(names);
  var initial = _.initial(names);
  var finalSeparator = (_.size(names) > 1 ? ', & ' : '');
  return what + ' ' + initial.join(', ') +
    finalSeparator + _.last(names);
});

say('hello', 'fred', 'barney', 'pebbles');
// "hello fred, barney, & pebbles"

// 换成

const say = (what, ...names) => {
  const [last, ...initial] = names.reverse();
  const finalSeparator = (names.length > 1 ? ', &' : '');
  return `${what} ${initial.join(', ')} ${finalSeparator} ${last}`;
};

say('hello', 'fred', 'barney', 'pebbles');
// "hello fred, barney, & pebbles"

Curry

没有像TypeScriptFlow更高级的语言,我们给函数使用Curring变得非常困难。当使用Curried函数很难知道有多少参数已经提供了,而且在下一步也需要提供。箭头函数可以让curried函数功能更明确,而且让其他程序员更易理解。

function add(a, b) {
  return a + b;
}
var curriedAdd = _.curry(add);
var add2 = curriedAdd(2);
add2(1);// 3

// 换成

const add = a => b => a + b;
const add2 = add(2);
add2(1);// 3

这些箭头的curried函数功能对于调试bug也非常重要。

var lodashAdd = _.curry(function(a, b) {
  return a + b;
});
var add3 = lodashAdd(3);
console.log(add3.length); // 0
console.log(add3);
//function wrapper() {
//  var length = arguments.length,
//  args = Array(length),
//  index = length;
//
//  while (index--) {
//    args[index] = arguments[index];
//  }…

// 换成

const es6Add = a => b => a + b;
const add3 = es6Add(3);
console.log(add3.length);// 1
console.log(add3);// function b => a + b

如果使用像loadsh/fp或者ramda这样的函数库,这里我们使用箭头函数删除时需要使用auto-curry样式。

_.map(_.prop('name'))(people);

// 换成

people.map(person => person.name);

Partial

像使用Currying一样,可以在Partial上使用箭头函数,会变得更简单,功能更明确。

var greet = function(greeting, name) {
  return greeting + ' ' + name;
};

var sayHelloTo = _.partial(greet, 'hello');
sayHelloTo('fred');// "hello fred"

// 换成

const sayHelloTo = name => greet('hello', name);
sayHelloTo('fred');// "hello fred"

也可以这样使用

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

Operators

Lodash附带了一些数字函数,重新实现了运算符函数的功能。这里收集了一些这方面的方法。

在大多数情况下,箭头函数使其变得简单,而且书写短。

_.eq(3, 3); // true
_.add(10, 1); // 11
_.map([1, 2, 3], function(n) {
  return _.multiply(n, 10);
});// [10, 20, 30]
_.reduce([1, 2, 3], _.add);// 6

// 换成

3 === 3
10 + 1
[1, 2, 3].map(n => n * 10);
[1, 2, 3].reduce((total, n) => total + n);

Paths

Lodash很多功能用来处理字符串和数组的paths。我们可以使用箭头函数来创建更多的可复用的paths。

var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };

_.at(object, ['a[0].b.c', 'a[1]']);// [3, 4]
_.at(['a', 'b', 'c'], 0, 2);// ['a', 'c']

// 换成

[
  obj => obj.a[0].b.c,
  obj => obj.a[1]
].map(path => path(object));

[
  arr => arr[0],
  arr => arr[2]
].map(path => path(['a', 'b', 'c']));

因为这些paths是功能,所以也可以将它们组合在一起。

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

甚至可以让高阶paths(Higher order paths)接受参数。

const getFirstNPeople = n => people => people.slice(0, n);

const getFirst5People = getFirstNPeople(5);
const getFirst5PostCodes = people => getFirst5People(people).map(getPostCode);

Pick

Pick可以让我们从一个目标对象中选择想要的属性。使用Destructuring和简单的对象遍历可以达到相同的结果。

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

return _.pick(object, ['a', 'c']);  // { a: 1, c: 3 }

// 换成

const { a, c } = { a: 1, b: 2, c: 3 };

return { a, c };

Constant, Identity, Noop

Lodash提供了一些实用的程序来创建简单的函数和特定的行为。

_.constant({ 'a': 1 })();   // { a: 1 }
_.identity({ user: 'fred' });   // { user: 'fred' }
_.noop();   // undefined

也可以使用箭头函数定义下面这些函数

const constant = x => () => x;
const identity = x => x;
const noop = () => undefined;

也可以像下面这样重写上面的示例

(() => ({ a: 1 }))();   // { a: 1 }
(x => x)({ user: 'fred' }); // { user: 'fred' }
(() => undefined)();    // undefined

Chaining 和 Flow

Lodash帮助我们编写链接语句(Chained Statements)提供了一些函数功能。在很多情况之下,内置的一些方法可以返回一个数组实例替换链接语句。

然而,可以定义相同的箭头功能转换为一个数组。

.tap(function(array) {
   // Mutate input array.
   array.pop();
})
.reverse()
.value();// [2, 1]

// 换成

const pipeline = [
  array => { array.pop(); return array; },
  array => array.reverse()
];

pipeline.reduce((xs, f) => f(xs), [1, 2, 3]);

这种方式,甚至不需要考虑tapthru之间的区别。

const pipe = functions => data => {
  return functions.reduce(
    (value, func) => func(value),
    data
  );
};

const pipeline = pipe([
  x => x * 2,
  x => x / 3,
  x => x > 5,
  b => !b
]);

pipeline(5);    // true
pipeline(20);   // false

总结

Lodash仍然是一个强大的库,这篇文章只是从一个全新的角度去看如何使用JavaScript将其进化,并且解决一些以前需要依赖工具模块才能解决的问题。

本文根据@Dan Prince的《10 Lodash Features You Can Replace with ES6》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://www.sitepoint.com/lodash-features-replace-es6/

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:http://www.w3cplus.com/javascript/lodash-features-replace-es6.html

返回顶部