lodash用法系列(6),函數種種


 

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: '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 darren
console.log(sayHello('darren'));

//輸入兩個實參,第一個用占位符
var greetJack = _.partial(greet, _, 'jack');

//hi jack
console.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);

//11
console.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.75
console.log(result);

 

參考資料:lodash essentials

 

本系列結束

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM