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
未完待續~~
