Lodash用来操作对象和集合,比Underscore拥有更多的功能和更好的性能。
官网:https://lodash.com/
引用:<script src="//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: \'\', age:45} ]; _.pluck(collection, \'age\');
也可以这样写:
_.map(collection, \'age\');
■ 对象的集合,留下想要的字段们
var collection = [ {frist:\'\',last:\'\',age:23}, ... ]; _.map(collection, function(item){ return _.pick(item, [\'first\',\'last\']); })
■ 对象的集合,排除不想要的字段们,不想要的字段作为参数传递
var collection = [ {first:\'\',last:\'\',age:19}, ... ]; _.map(collection, function(item){ return _.omit(item, \'first\'); })
■ 对象的集合,排除不想要的字段们,通过函数
var collection = [ {first:\'\',last:\'\',age:19}, ... ]; //key 字段名称 //value 字段对应的值 function invalidAge(value, key){ return key === \'age\' && value < 40; } _.map(collection, function(item){ reutrn _.omit(item, invalidAge); });
■ 对象的集合,给对象元素添加新的字段,根据现有字段计算而得
var collection = [ { name: \'Valerie\', jqueryYears: 4, cssYears: 3 }, { name: \'Alonzo\', jqueryYears: 1, cssYears: 5 }, { name: \'Claire\', jqueryYears: 3, cssYears: 1 }, { name: \'Duane\', jqueryYears: 2, cssYears: 0 } ]; var result = _.map(collection, function(item){ return _.extend({ experience: item.jqueryYears + item.cssYears, speciality: item.jqueryYears >= item.cssYears ? \'jQuery\' : \'CSS\' }, item); }); //[ { experience: 7,speciality: \'jQuery\',name: \'Valerie\',jqueryYears: 4,cssYears: 3 },...] console.log(result);
■ 使用map方法一个不易发现的错误
var app = {}, collection = [ { name: \'Cameron\', supervisor: false }, { name: \'Lindsey\', supervisor: true }, { name: \'Kenneth\', supervisor: false }, { name: \'Caroline\', supervisor: true } ]; app.supervisor = _.find(collection, {supervisor:true}); //{ supervisor: { name: \'Lindsey\', supervisor: true } } console.log(app); _.map(collection, function(item){ return _.extend(item, {supervisor: false}); }); //{ supervisor: { name: \'Lindsey\', supervisor: false } } console.log(app);
以上,使用map对collection集合操作,重写supervisor字段的值,居然也把app对象的supervisor字段值也重写了。
■ map方法使用内置函数,计算每一个集合元素的大小
var collection=[ [1,2], [1,2,3], {first:1, second:2}, {first:1, second:2,third:3} ]; var result = _.map(collection, _.size); //[ 2, 3, 2, 3 ] console.log(result);
■ map方法使用内置函数,获取每个集合元素中的最小值
var source = _.range(1000), collection=[ //sample从集合中获取一个或n个元素 _.sample(source,50), _.sample(source,100), _.sample(source,150) ]; //[ 12, 44, 0 ] console.log(_.map(collection, _.min));
■ map方法使用内置函数,针对集合元素依次调用多个方法
var collection = [ [ \'Evan\', \'Veronica\', \'Dana\' ], [ \'Lila\', \'Ronald\', \'Dwayne\' ], [ \'Ivan\', \'Alfred\', \'Doug\' ], [ \'Penny\', \'Lynne\', \'Andy\' ] ]; var result = _.map(collection, _.flowRight(_.first, function(item){ return _.sortBy(item); })); //[ \'Dana\', \'Dwayne\', \'Alfred\', \'Andy\' ] console.log(result);
以上,flowRight方法会依次调用其参数方法,先给每个一个元素内的元素排序,然后取出元素中的元素中的第一个。
■ 对集合元素依次使用多个方法
var collection = [ { name: \'Karl\', enabled: true }, { name: \'Sophie\', enabled: true }, { name: \'Jerald\', enabled: false }, { name: \'Angie\', enabled: false } ]; var result = _.flowRight( _.partialRight(_.map, \'name\'), _.partialRight(_.filter, \'enabled\') )(collection); //[ \'Karl\', \'Sophie\' ] console.log(result);
以上,对集合依次使用了filter和map方法。
■ 获取对象的所有键值
var object = { first: \'Ronald\', last: \'Walters\', employer: \'Packt\' }; var result = _.map(_.sortBy(_.keys(object)), function(item){ return object[item]; }) //[ \'Packt\', \'Ronald\', \'Walters\' ] console.log(result);
以上,_.keys(object)获取对象的所有键,_.sortBy(_.keys(object))对所有键排序,然后根据键获取所有元素。
■ 创建唯一的自增编号
var result = _.uniqueId(\'user-\'); var result2 = _.uniqueId(\'user-\'); console.log(result);//user-1 console.log(result2);//user-2
以上,通过_.uniqueId(\'user-\');创建的编号是唯一、自增的。
■ 从两个具有相同键、相同键数量的对象中,取出对应的键、键值合并成一个新的对象,新的对象作为数组元素
ar users = {}, prefereces = {}; _.each(_.range(100), function () { var id = _.uniqueId(\'user-\'); users[id] = {type: \'user\'}; prefereces[id] = {email: !!(_.random())} }); //users:{ \'user-1\': { type: \'user\' },\'user-2\': { type: \'user\' },...} //preference:{ \'user-1\': { email: false }, \'user-2\': { email: true }...} //users和preference的键是一样的,键对应的值都是对象,键的数量也是一样的 var result = _.map(users, function (value, key) { return _.extend({id: key}, prefereces[key]); }); //[ { id: \'user-1\', email: false },{ id: \'user-2\', email: true },...] console.log(result);
■ 对象中键值包含值或函数,取出对象的所有键值对方到一个数组中,键值是函数的执行该函数
var obj = { first: \'a\', last: \'b\', name: function () { return this.first + \' \' + this.last; }, age: 22, retirement: 65, working: function () { return this.retirement - this.age; } }; var result1 = _.map(obj, function (value, key) { var item = {}; item[key] = _.isFunction(value) ? obj[key]() : value; return item; }); //[ { first: \'a\' }, // { last: \'b\' }, // { name: \'a b\' }, // { age: 22 }, // { retirement: 65 }, // { working: 43 } ] console.log(result1); //[ { first: \'a\' }, // { last: \'b\' }, // { name: \'a b\' }, // { age: 22 }, // { retirement: 65 }, // { working: 43 } ] var result2=_.map(obj, function(value, key){ var item={}; item[key]= _.result(obj,key); return item; }); console.log(result2);
以上,一个是通过isFunction来判断键值是否是函数,一个直接调用result来执行键值函数。
■ 根据键取出一个对象中间对应的函数
var object = { \'user\': \'fred\', \'greet\': function(greeting, punctuation) { return greeting + \' \' + this.user + punctuation; } }; var bound = _.bindKey(object, \'greet\',\'hi\'); //hi fred! console.log(bound(\'!\'));
以上,bindKey,根据键greet这个键把它对应的函数取出来。
■ 把对象中的函数取出来放到一个数组中,再invoke它们
var obj={ firstName: \'a\', lastName: \'b\', first: function(){ return this.firstName; }, last: function(){ return this.lastName; } }; var methods =_.map(_.functions(obj),function(item){ return [_.bindKey(obj, item)]; }); console.log(methods); //[ \'a\', \'b\' ] console.log(_.invoke(methods,0));
■ 把一个对象中的所有值取出来
var _ = require(\'lodash\'); var obj = { first: \'a\', last: \'b\', age:50 }; var result = _.map(_.filter(_.values(obj), _.isString), function(item){ return \'<strong>\' + item + \'</strong>\'; }); //[ \'<strong>a</strong>\', \'<strong>b</strong>\' ] console.log(result);
不仅通过values把对象的值取出来,还用filter进行了排序,最后还把值包裹到html元素中。
■ 把对象的键值转换成数组元素,再放到更大的数组中去
//把首字母转换成大写 function capitalize(s){ return s.charAt(0).toUpperCase() + s.slice(1); } //label接受对象的key //value接受对象的键值 function format(label, value) { return \'<label>\' + capitalize(label) + \':</label>\' + \'<strong>\' + value + \'</strong>\'; } var object = { first: \'Julian\', last: \'Ramos\', age: 43 }; var tempParis =_.pairs(object); //[ [ \'first\', \'Julian\' ], [ \'last\', \'Ramos\' ], [ \'age\', 43 ] ] console.log(tempParis); var result = _.map(tempParis, function(pair){ return format.apply(undefined, pair); });
以上,pairs方法把对象的键值作为数组的元素,比如[ \'first\', \'Julian\' ],再把[ \'first\', \'Julian\' ]放到一个更大的数组中:[ [ \'first\', \'Julian\' ], ...]
■ 对象的集合,计算某个字段的和,累加的初始值是数字
var collection = [ { ram: 1024, storage: 2048 }, { ram: 2048, storage: 4096 }, { ram: 1024, storage: 2048 }, { ram: 2048, storage: 4096 } ]; var result1 = _.reduce(collection, function(result, item){ return result+item.ram; },0); //6144 console.log(result1); var result2 = _.reduce(collection, function(result, item){ return result+item.storage; },0); //12288 console.log(result2);
以上,0是累加的初始值。
■ 对象的集合,计算某个字段的和, 累加的初始值是对象,类加后的结果也是对象
var collection = [ {hits: 2, misses: 4}, {hits: 5, misses: 1}, {hits: 3, misses: 8}, {hits: 7, misses: 3} ]; var result = _.reduce(collection, function(result, item) { return { hits: result.hits + item.hits, misses: result.misses + item.misses }; }, { hits: 0, misses: 0 }); //{ hits: 17, misses: 16 } console.log(result);
■ 自定义累加的算法
function add(a,b){ return a+b; } var collection =[ {wins:34, loses:21}, {wins:58, loses:12}, {wins:34, loses:23}, {wins:40, loses:15}, ]; var result1 = _.reduce(_.range(1,6),add);//[ 1, 2, 3, 4, 5 ] console.log(result1);//15 var result2 =_.reduce(_.pluck(collection,\'wins\'),add); console.log(result2);//166
■ 对象的集合,先过滤,然后自定义求和算法
var collection = [ { name: \'Gina\', age: 34, enabled: true }, { name: \'Trevor\', age: 45, enabled: false }, { name: \'Judy\', age: 71, enabled: true }, { name: \'Preston\', age: 19, enabled: false } ]; var result = _.reduce(_.filter(collection, \'enabled\'), function(result, item){ result.names.push(item.name); result.years+= item.age; return result; },{names:[], years:0}); //{ names: [ \'Gina\', \'Judy\' ], years: 105 } console.log(result);
■ 对象的集合,自定义求和算法,并在算法中过滤
var collection = [ { name: \'Melissa\', age: 28, enabled: true }, { name: \'Kristy\', age: 22, enabled: true }, { name: \'Kerry\', age: 31, enabled: false }, { name: \'Damon\', age: 36, enabled: false } ]; var result = _.reduce(collection, function(result, item) { if (item.enabled) { result.names.push(item.name); result.years += item.age; } return result; }, { names: [], years: 0 }); //{ names: [ \'Melissa\', \'Kristy\' ], years: 50 } console.log(result);
■ 对象集合,对象元素中有一个字段是整型数组,这些数组元素相加,把和最小所在的对象打印出来
//对象中的一个字段是数值数组 var collection = [ { name: \'Madeline\', scores: [ 88, 45, 83 ] }, { name: \'Susan\', scores: [ 79, 82, 78 ] }, { name: \'Hugo\', scores: [ 90, 84, 85 ] }, { name: \'Thomas\', scores: [ 74, 69, 78 ] } ]; //对对象item的scores字段所代表的数组数组求和 function score(item) { return _.reduce(item.scores, function(result, score) { return result + score; }); } var result = _.min(collection, score); //{ name: \'Madeline\', scores: [ 88, 45, 83 ] } console.log(result);
如果求最大,那就是:
var result = _.max(collection, score);
■ 对象的集合,对象元素中有个字段是整型号数组,求出每个对象元素整型数组的平均值,放在一个数组中,再求这个数组的平均值
function average(items){ return _.reduce(items, function(result, item){ return result + item; }) / items.length; } var collection = [ { name: \'Anthony\', scores: [ 89, 59, 78 ] }, { name: \'Wendy\', scores: [ 84, 80, 81 ] }, { name: \'Marie\', scores: [ 58, 67, 63 ] }, { name: \'Joshua\', scores: [ 76, 68, 74 ] } ]; //result表示累加之和 //item表示集合中的元素 //index表示集合元素索引 //coll表示集合 var result = _.reduce(collection, function(result, item, index, coll){ var ave = average(item.scores); result.push(ave); //如果当前元素的索引是集合中的最后一个元素 if(index === (coll.length - 1)){ return average(result); } return result; },[]).toFixed(2); //73.08 console.log(result);
■ 删除某个对象中的某些键值对
var object = { first: \'a\', last: \'b\', age: 41 }, allowed = [\'first\',\'last\']; var result = _.reduce(object,function(result, value, key){ if(_.contains(allowed, key)){ result[key] = value; } return result; },{}); //{ first: \'a\', last: \'b\' } console.log(result); var result2 = _.pick(object, allowed); //{ first: \'a\', last: \'b\' } console.log(result2);
以上,分别通过reduce和pick的方式把对象中的不需要的字段剔除了。
■ 剔除对象中不需要的键值对,并对某些键值进行转换
var object = { first: \'<strong>Nicole</strong>\', last: \'<strong>Russel</strong>\', age: 26 }; var result = _.transform(object, function(result, value, key) { if (_.isString(value)) { result[key] = _.unescape(value); } }); //{ first: \'<strong>Nicole</strong>\', // last: \'<strong>Russel</strong>\' } console.log(result);
以上,unescape是把键值转换成html元素。
■ 对对象的键值进行转换,再调用对象的原型方法
function Person(first, last){ this.first = first; this.last = last; } Person.prototype.name = function name(){ return this.first + \' \' + this.last; } var darren = new Person(\'Darren\',\'ji\'); var result = _.transform(darren, function(result, value,key){ if(_.isString(value)){ result[key] = value.toString(); } }).name(); //Darren ji console.log(result);
■ 对象集合,根据对象元素的某个字段进行分组
var collection = [ { id: _.uniqueId(\'id-\'), position: \'absolute\', top: 12 }, { id: _.uniqueId(\'id-\'), position: \'relative\', top: 20 }, { id: _.uniqueId(\'id-\'), position: \'absolute\', top: 12 }, { id: _.uniqueId(\'id-\'), position: \'relative\', top: 20 } ]; var result = _.groupBy(collection, \'position\'); //{ absolute: // [ { id: \'id-1\', position: \'absolute\', top: 12 }, // { id: \'id-3\', position: \'absolute\', top: 12 } ], // relative: // [ { id: \'id-2\', position: \'relative\', top: 20 }, // { id: \'id-4\', position: \'relative\', top: 20 } ] } console.log(result); var result2 = _.indexBy(collection, \'id\'); //{ \'id-1\': { id: \'id-1\', position: \'absolute\', top: 12 }, // \'id-2\': { id: \'id-2\', position: \'relative\', top: 20 }, // \'id-3\': { id: \'id-3\', position: \'absolute\', top: 12 }, // \'id-4\': { id: \'id-4\', position: \'relative\', top: 20 } } console.log(result2);
■ 为map方法绑定上下文
var app = { states: [ \'running\', \'off\', \'paused\' ], machines: [ { id: _.uniqueId(), state: 1 }, { id: _.uniqueId(), state: 0 }, { id: _.uniqueId(), state: 0 }, { id: _.uniqueId(), state: 2 } ] }; var mapStates = _.partialRight(_.map, function(item){ return _.extend({state: this.states[item.state]}, _.pick(item,\'id\')); },app); var result = mapStates(app.machines); //[ { state: \'off\', id: \'1\' }, // { state: \'running\', id: \'2\' }, // { state: \'running\', id: \'3\' }, // { state: \'paused\', id: \'4\' } ] console.log(result);
以上,partialRight方法的第三个参数app是map方法的上下文。
■ 为reduce方法绑定上下文
var collection = [ 12, 34, 53, 43 ], settings = { tax: 1.15 }, applyTax = _.partialRight(_.reduce, function(result, item) { return result + item * this.tax; }, 0, settings); //163.30 console.log(applyTax(collection).toFixed(2));
■ 对象集合,更改对象某个字段的值,类似泛型
//this作为上下文对象有prop和value字段 //this的prop键值决定哪个字段需要实施加法 //item在这里会传入集合元素 function add(item){ var result = _.clone(item); result[this.prop] += this.value; return result; } function upper(item){ var result = _.clone(item); result[this.prop]=result[this.prop].toUpperCase(); return result; } var collection = [ { name: \'Gerard\', balance: 100 }, { name: \'Jean\', balance: 150 }, { name: \'Suzanne\', balance: 200 }, { name: \'Darrell\', balance: 250 } ]; var mapAdd = _.partial(_.map, collection, add), mapUpper = _.partial(_.map, collection, upper); //[ { name: \'Gerard\', balance: 150 }, // { name: \'Jean\', balance: 200 }, // { name: \'Suzanne\', balance: 250 }, // { name: \'Darrell\', balance: 300 } ] console.log(mapAdd({ prop: \'balance\', value: 50 })); //[ { name: \'GERARD\', balance: 100 }, // { name: \'JEAN\', balance: 150 }, // { name: \'SUZANNE\', balance: 200 }, // { name: \'DARRELL\', balance: 250 } ] console.log(mapUpper({ prop: \'name\'}));
■ 对象集合,对某个字段求和,类似泛型
function sum(a,b){ return a+b[this.prop]; } var collection = [ { low: 40, high: 70 }, { low: 43, high: 83 }, { low: 39, high: 79 }, { low: 45, high: 74 } ]; var reduceSum = _.partial(_.reduce, collection, sum, 0); //167 console.log(reduceSum({ prop: \'low\' }));
■ 对象集合,先为对象元素增加一个字段,再对所有对象求和,求和自定义算法
var collection = [ { name: \'Wade\', balance: 100 }, { name: \'Donna\', balance: 125 }, { name: \'Glenn\', balance: 90 }, { name: \'Floyd\', balance: 110 } ], bonus = 25; //为每个集合元素增加了一个bonus字段 var mapped = _.map(collection, function(item) { return _.extend({ bonus: item.balance + bonus }, item); }); //求和 //item是集合中的元素 //index是集合中元素的索引 //coll是集合 //result是累计结果 var result = _.reduce(mapped, function(result, item, index, coll) { result += (item.bonus - item.balance) / item.bonus; //如果累加到最后一个集合元素 if (index === (coll.length - 1)) { result = result / coll.length * 100; } return result; }, 0).toFixed(2) + \'%\'; //19.23% console.log(result);
参考资料:lodash essentials
未完待续~~