• 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

    本系列结束

  • 相关阅读:
    ModelFirst的CRUD
    EF中逆变和协变
    ERP客户关系渠管理(二十)
    ERP反馈信息管理(十九)
    ERP系统上传文档信息下载(十八)
    比较 数组与对象的同源特性
    对android的认识
    我的知乎
    HTTP来源地址
    BroadcastReceiver 翻译
  • 原文地址:https://www.cnblogs.com/darrenji/p/5011515.html
Copyright © 2020-2023  润新知