你的位置:首页 > Java教程

[Java教程]lodash用法系列,函数种种


 

Lodash用来操作对象和集合,比Underscore拥有更多的功能和更好的性能。

官网:https://lodash.com/
引用:<script src="http://www.cnblogs.com///cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
安装:npm install lodash

首先通过npm安装lodash:
npm i --save lodash

在js文件中引用lodash:
var _ = require('lodash');

 

本系列包括:

 

● lodash用法系列(1),数组集合操作
● lodash用法系列(2),处理对象 
● lodash用法系列(3),使用函数 
● lodash用法系列(4),使用Map/Reduce转换  
● lodash用法系列(5),链式 
● lodash用法系列(6),函数种种 

 

 

■ 不同的函数定义方式

 

var collection = [  { name: 'Ronnie', age: 43 },  { name: 'Ben', age: 19 },  { name: 'Sharon', age: 25 },  { name: 'Melissa', age: 29 }];//返回name键值组成的数组function collectionNames(){  //依赖于变量  //name是hardcode  return _.map(collection, 'name');}//coll形参,输入集合//prop形参,输入集合对象的某个字段//map中的参数完全依赖形参,coll, prop泛型function inderectionNames(coll, prop){  return _.map(coll, prop);}//coll形参,输入集合//coll泛型function genericCollNames(coll){  return _.map(coll, 'name');}//prop形参,输入集合对象的某个字段//prop泛型function genericPropNames(prop){  return _.map(collection, prop);}//[ 'Ronnie', 'Ben', 'Sharon', 'Melissa' ]console.log(collectionNames());//[ 'Ronnie', 'Ben', 'Sharon', 'Melissa' ]console.log(inderectionNames(collection, 'name'));//[ 'Ronnie', 'Ben', 'Sharon', 'Melissa' ]console.log(genericCollNames(collection));//[ 'Ronnie', 'Ben', 'Sharon', 'Melissa' ]console.log(genericPropNames('name'));

 


■ 函数的参数都不是静态的、固定的,但可以到arguments中提取

 

function insert(coll, callback){  var toInsert;  //也就是callback这个参数是optional的  if(_.isFunction(callback)){    toInsert= _.slice(arguments,2);//截掉insert参数中coll, callback这2个实参  }else{    toInsert= _.slice(arguments,1)    callback= _.identity;//_.identity是lodash回调函数的默认值  }  _.each(toInsert, function(item){    //把加入的元素放到coll集合中合适的位置    coll.splice(_.sortedIndex(coll, item, callback),0, item);  });  return coll;}var collection=_.range(1,11);var result = insert(collection,8.4);//[ 1, 2, 3, 4, 5, 6, 7, 8, 8.4, 9, 10 ]console.log(result);

 

■ 函数的参数不是静态的、固定的,输入部分实参

以上在调用函数的时候是把所有的实参给了函数,而在lodash中,还可以分步输入实参。

 

//接受两个形参var greet = function (greeting, name) {  return greeting + ' ' + name;}//先输入第一个实参var sayHello = _.partial(greet, 'hello');//再输入第二个实参//hello darrenconsole.log(sayHello('darren'));//输入两个实参,第一个用占位符var greetJack = _.partial(greet, _, 'jack');//hi jackconsole.log(greetJack('hi'));

 

以上,greet函数接受2个形参,但我们在实际使用过程中,先输入一个实参,再输入其它实参。

如果先输入第二个实参,就使用partialRight方法。如果使用partialRight而不输入第二个实参,只输入第一个实参,那第二个实参需要用占位符。

与parital类似的还有一个方法使curry:

 

var add = function (a, b) {  return a + b;}var c1 = _.curry(add);var c2 = c1(5);var result = c2(6);//11console.log(result);

 

partial和curry的共同点都是需要把实参凑齐了才能执行方法。不同点是:parital似乎把2个参数交给了一个人,一个人先后拿到所有的实参;curry似乎是把不同的参数交给了不同的人,拿2个实参为例,拿到第一个实参交给一个人c1,c1说我拿了实参5告诉c2,c2知道后有拿了参数6,2个实参拿齐后,由c2执行方法。


■ 自定义的函数作为回调函数

 

var YEAR_MILLISECONDS = 31560000000;function validItem(item){  return item.age > 21 &&    _.isString(item.first) &&    _.isString(item.last);}var invalidItem = _.negate(validItem);function computed(item) {  return _.extend({    name: _.result(item, 'first', '') + ' ' +    _.result(item, 'last', ''),    yob: new Date(new Date() - (YEAR_MILLISECONDS * item.age))      .getFullYear()  }, item);}var collection = [  { first: 'Roderick', last: 'Campbell', age: 56 },  { first: 'Monica', last: 'Salazar', age: 38 },  { first: 'Ross', last: 'Andrews', age: 45 },  { first: 'Martha', age: 51 }];console.log(_.every(collection, validItem));//false//[ { first: 'Roderick', last: 'Campbell', age: 56 },//  { first: 'Monica', last: 'Salazar', age: 38 },//  { first: 'Ross', last: 'Andrews', age: 45 } ]console.log(_.filter(collection, validItem));//{ first: 'Martha', age: 51 }console.log(_.find(collection, invalidItem));//[ { name: 'Roderick Campbell',//  yob: 1959,//  first: 'Roderick',//  last: 'Campbell',//  age: 56 },...]console.log(_.map(collection, computed));

 


■ 把过滤封装到一个函数中

 

function byName(coll, name, take) {  return _(coll)    .filter({ name: name })    .take(_.isUndefined(take) ? 100 : take)    .value();}var collection = [  { name: 'Theodore', enabled: true },  { name: 'Leslie', enabled: true },  { name: 'Justin', enabled: false },  { name: 'Leslie', enabled: false }];byName(collection, 'Leslie');byName(_.filter(collection, 'enabled'), 'Leslie');byName(_(collection).filter('enabled'), 'Leslie');

 

以上,把过滤封装到了byName方法中,并且在该方法内返回值,即直接调用了方法。


■ 把链式封装到一个函数中

 

function sort(coll, prop, desc){  var wrapper = _(coll).sortBy(prop);  return desc? wrapper.reverse() : wrapper;}var collection = [  { first: 'Bobby', last: 'Pope' },  { first: 'Debbie', last: 'Reid' },  { first: 'Julian', last: 'Garcia' },  { first: 'Jody', last: 'Greer' }];var result = sort(collection,'first').value();//[ { first: 'Bobby', last: 'Pope' },//  { first: 'Debbie', last: 'Reid' },//  { first: 'Jody', last: 'Greer' },//  { first: 'Julian', last: 'Garcia' } ]console.log(result);var result2=sort(collection,'last')  .takeRight(2)  .pluck('last') //获取某个字段的值放在数组中  .value();//[ 'Pope', 'Reid' ]console.log(result2);

 


以上,把链式封装到了sort方法中,但在该方法内没有返回值,该方法可以看做是链式的一个wrapper。

 

■ 补充:indexBy的用法

 

var keyData = [  { 'dir': 'left', 'code': 97 },  { 'dir': 'right', 'code': 100 }];var result1= _.indexBy(keyData,'dir');//把dir字段对应的键值作为键,把集合元素作为键值//{ left: { dir: 'left', code: 97 },//  right: { dir: 'right', code: 100 } }console.log(result1);

 

■ 把几个方法合成起来

 

function enabledIndex(obj){  return _.transform(obj, function(result, value, key){    result[key]= _.result(value, 'enabled',false);  });}var collection = [  { name: 'Claire', enabled: true },  { name: 'Patricia', enabled: false },  { name: 'Mario', enabled: true },  { name: 'Jerome', enabled: false }];//实际上indexByName接受2个形参,一个是集合,一个是字段//indexByName的返回结果是以name属性值为key,集合元素作为value//{ Claire: { name: 'Claire', enabled: true },//  Patricia: { name: 'Patricia', enabled: false },//  Mario: { name: 'Mario', enabled: true },//  Jerome: { name: 'Jerome', enabled: false } }var indexByName=_.partialRight(_.indexBy, 'name'),  //把第一个参数collection传给第一个方法IndexByName  //第一个方法的返回值作为第二个方法的实参  enabled=_.partial(_.flow(indexByName, enabledIndex), collection);//{ Claire: true, Patricia: false, Mario: true, Jerome: false }console.log(enabled());

 

以上,通过flow方法把indexByName和enabledIndex方法合成了起来,并且,第一个方法的返回值作为第二个方法的实参。

■ 合成函数,并作为回调函数

 

var collection = [  { first: 'Andrea', last: 'Stewart', age: 28 },  { first: 'Clarence', last: 'Johnston', age: 31 },  { first: 'Derek', last: 'Lynch', age: 37 },  { first: 'Susan', last: 'Rodgers', age: 41 }];var minimal=_.flow(_.identity, _.partialRight(_.pick, ['last','age']));var result=_.map(collection, minimal);//[ { last: 'Stewart', age: 28 },//  { last: 'Johnston', age: 31 },//  { last: 'Lynch', age: 37 },//  { last: 'Rodgers', age: 41 } ]console.log(result);

 

■ 合成函数,控制链式的过程

 

function sorted(wrapper){  return _(wrapper).sortBy();}function rejectOdd(wrapper){  return _(wrapper).reject(function(item){    return item%2;  });}var sortedEvens=_.flow(sorted, rejectOdd),  evensSorted=_.flow(rejectOdd, sorted, _.partialRight(_.result, 'value')),  collection=_.shuffle(_.range(1,11));var result=sortedEvens(collection)  .reverse()  .value();//[ 10, 8, 6, 4, 2 ]console.log(result);

 

以上,sorted和sortedEvens方法接收的是wrapper,正是因为是wrapper,所以在flow中可以改变这些wrapper的顺序,即控制链式过程。

■ 在函数的方法中显示使用链式

 

function validThru(next, value){  return value && next;}function User(first, last, age){  this.first=first;  this.last=last;  this.age=age;}User.prototype.valid = function(){  return _.chain(this.first) //一旦显式调用chain方法,意味着接下来那些返回值的函数返回wrapper    .isString()    .thru(_.partial(validThru, this.last))//validThru相当于thru的回调函数    .isString()    .thru(_.partial(validThru, this.age))    .isFinite()    .value();}var result = new User('orlando','Olson',25).valid();console.log(result);

 

■ 自定义内置方法average

 

//自定义average方法_.mixin({average:function(coll, callback){  return _(coll)    .map(callback)    .reduce(function(result, item){      return result +item;    }) / _.size(coll);}});var collection = [  { name: 'Frederick', age: 41, enabled: true },  { name: 'Jasmine', age: 29, enabled: true },  { name: 'Virgil', age: 47, enabled: true },  { name: 'Lila', age: 22, enabled: false }];var result = _.average(collection, 'age');//34.75console.log(result);

 

参考资料:lodash essentials

 

本系列结束☺