lodash用法详解以及与ES6的对比

一、讲在前:

1、版本:VERSION = 4.17.5;
2、中文文档:https://www.lodashjs.com/
3、安装引入:

<script src="lodash.js"></script>

通过 npm:

$ npm i -g npm
$ npm i --save lodash

import _ from 'lodash';

二、功能简介

  • Array,适用于数组类型,比如填充数据、查找元素、数组分片等操作
  • Collection,适用于数组和对象类型,部分适用于字符串,比如分组、查找、过滤等操作
  • Function,适用于函数类型,比如节流、延迟、缓存、设置钩子等操作
  • Lang,普遍适用于各种类型,常用于执行类型判断和类型转换
  • Math,适用于数值类型,常用于执行数学运算
  • Number,适用于生成随机数,比较数值与数值区间的关系
  • Object,适用于对象类型,常用于对象的创建、扩展、类型转换、检索、集合等操作
  • Seq,常用于创建链式调用,提高执行性能(惰性计算)
  • String,适用于字符串类型

lodash/fp 模块提供了更接近函数式编程的开发方式,其内部的函数经过包装,具有 immutable、auto-curried、iteratee-first、data-last(官方介绍)等特点。Lodash 在 GitHub Wiki 中对 lodash/fp 的特点做了如下概述:

  • Fixed Arity,固化参数个数,便于柯里化
  • Rearragned Arguments,重新调整参数位置,便于函数之间的聚合
  • Capped Iteratee Argument,封装 Iteratee 参数
  • New Methods

三、基本使用对比原生js

1. N 次循环

// 1\. Basic for loop.
for(var i = 0; i < 5; i++) {
    // ...
}

// 2\. Using Array's join and split methods
Array.apply(null, Array(5)).forEach(function(){
    // ...
});

// Lodash
_.times(5, function(){
    // ...
});

for 语句是执行循环的不二选择,Array.apply 也可以模拟循环,但在上面代码的使用场景下,_.times() 的解决方式更加简洁和易于理解。

2. 深层查找属性值

// Fetch the name of the first pet from each owner
var ownerArr = [{
    "owner": "Colin",
    "pets": [{"name":"dog1"}, {"name": "dog2"}]
}, {
    "owner": "John",
    "pets": [{"name":"dog3"}, {"name": "dog4"}]
}];

// Array's map method.
ownerArr.map(function(owner){
   return owner.pets[0].name;
});

// Lodash
_.map(ownerArr, 'pets[0].name');

_.map 方法是对原生 map 方法的改进,其中使用 pets[0].name 字符串对嵌套数据取值的方式简化了很多冗余的代码,非常类似使用 jQuery 选择 DOM 节点 ul > li > a,对于前端开发者来说有种久违的亲切感。

3. 个性化数组

// Array's map method.
Array.apply(null, Array(6)).map(function(item, index){
    return "ball_" + index;
});

// Lodash
_.times(6, _.uniqueId.bind(null, 'ball_'));

// Lodash
_.times(6, _.partial(_.uniqueId, 'ball_'));
// eg. [ball_0, ball_1, ball_2, ball_3, ball_4, ball_5]

在上面的代码中,我们要创建一个初始值不同、长度为 6 的数组,其中 _.uniqueId 方法用于生成独一无二的标识符(递增的数字,在程序运行期间保持独一无二),_partial 方法是对 bind 的封装。

4. 深拷贝

var objA = {
    "name": "colin"
}

// Normal method? Too long. See Stackoverflow for solution:
// http://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript

// Lodash
var objB = _.cloneDeep(objA);
objB === objA // false

JavaScript 没有直接提供深拷贝的函数,但我们可以用其他函数来模拟,比如 JSON.parse(JSON.stringify(objectToClone)),但这种方法要求对象中的属性值不能是函数。Lodash 中的 _.cloneDeep 函数封装了深拷贝的逻辑,用起来更加简洁。

5. 随机数

// Naive utility method
function getRandomNumber(min, max){
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

getRandomNumber(15, 20);

// Lodash
_.random(15, 20);

Lodash 的随机数生成函数更贴近实际开发,ECMAScript 的随机数生成函数是底层必备的接口,两者都不可或缺。此外,使用 _.random(15, 20, true) 还可以在 15 到 20 之间生成随机的浮点数。

6. 对象扩展

// Adding extend function to Object.prototype
Object.prototype.extend = function(obj) {
    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            this[i] = obj[i];
        }
    }
};

var objA = {"name": "colin", "car": "suzuki"};
var objB = {"name": "james", "age": 17};

objA.extend(objB);
objA; // {"name": "james", "age": 17, "car": "suzuki"};

// Lodash
_.assign(objA, objB);

_.assign 是浅拷贝,和 ES6 新增的 Ojbect.assign 函数功能一致(建议优先使用 Object.assign)。

7. 筛选属性

// Naive method: Remove an array of keys from object
Object.prototype.remove = function(arr) {
    var that = this;
    arr.forEach(function(key){
        delete(that[key]);
    });
};

var objA = {"name": "colin", "car": "suzuki", "age": 17};

objA.remove(['car', 'age']);
objA; // {"name": "colin"}

// Lodash
objA = _.omit(objA, ['car', 'age']);
// => {"name": "colin"}
objA = _.omit(objA, 'car');
// => {"name": "colin", "age": 17};
objA = _.omit(objA, _.isNumber);
// => {"name": "colin"};

大多数情况下,Lodash 所提供的辅助函数都会比原生的函数更贴近开发需求。在上面的代码中,开发者可以使用数组、字符串以及函数的方式筛选对象的属性,并且最终会返回一个新的对象,中间执行筛选时不会对旧对象产生影响。

// Naive method: Returning a new object with selected properties
Object.prototype.pick = function(arr) {
    var _this = this;
    var obj = {};
    arr.forEach(function(key){
        obj[key] = _this[key];
    });

    return obj;
};

var objA = {"name": "colin", "car": "suzuki", "age": 17};

var objB = objA.pick(['car', 'age']);
// {"car": "suzuki", "age": 17}

// Lodash
var objB = _.pick(objA, ['car', 'age']);
// {"car": "suzuki", "age": 17}

_.pick_.omit 的相反操作,用于从其他对象中挑选属性生成新的对象。

8. 随机元素

var luckyDraw = ["Colin", "John", "James", "Lily", "Mary"];

function pickRandomPerson(luckyDraw){
    var index = Math.floor(Math.random() * (luckyDraw.length -1));
    return luckyDraw[index];
}

pickRandomPerson(luckyDraw); // John

// Lodash
_.sample(luckyDraw); // Colin

// Lodash - Getting 2 random item
_.sample(luckyDraw, 2); // ['John','Lily']

_.sample 支持随机挑选多个元素并返回心的数组。

9. 针对 JSON.parse 的错误处理

// Using try-catch to handle the JSON.parse error
function parse(str){
    try {
        return JSON.parse(str);
    }

    catch(e) {
        return false;
    }
}

// With Lodash
function parseLodash(str){
    return _.attempt(JSON.parse.bind(null, str));
}

parse('a');
// => false
parseLodash('a');
// => Return an error object

parse('{"name": "colin"}');
// => Return {"name": "colin"}
parseLodash('{"name": "colin"}');
// => Return {"name": "colin"}

如果你在使用 JSON.parse 时没有预置错误处理,那么它很有可能会成为一个定时炸弹,我们不应该默认接收的 JSON 对象都是有效的。try-catch 是最常见的错误处理方式,如果项目中 Lodash,那么可以使用 _.attmpt 替代 try-catch 的方式,当解析 JSON 出错时,该方法会返回一个 Error 对象。

随着 ES6 的普及,Lodash 的功能或多或少会被原生功能所替代,所以使用时还需要进一步甄别,建议优先使用原生函数,有关 ES6 替代 Lodash 的部分,请参考文章《10 Lodash Features You Can Replace with ES6》(中文版《10 个可用 ES6 替代的 Lodash 特性》)。

其中有两处非常值得一看:

// 使用箭头函数创建可复用的路径
const object = { 'a': [{ 'b': { 'c': 3 } }, 4] };

[
    obj => obj.a[0].b.c,
    obj => obj.a[1]
].map(path => path(object));

// 使用箭头函数编写链式调用
const pipe = functions => data => {
    return functions.reduce(
        (value, func) => func(value),
        data
    );
};

const pipeline = pipe([
    x => x * 2,
    x => x / 3,
    x => x > 5,
    b => !b
]);

pipeline(5);
// true
pipeline(20);
// false

在 ES6 中,如果一个函数只接收一个形参且函数体是一个 return 语句,就可以使用箭头函数简化为:

const func = p => v;

// 类似于(不完全相同)
const func = function (p) {
    return v;
}

当有多重嵌套时,可以简化为:

const func = a => b => c => a + b + c;
func(1)(2)(3);
// => 6

// 类似于
const func = function (a) {
    return function (b) {
        return function (e) {
            return a + b + c;
        }
    }
}

四、10 个可用 ES6 替代的 Lodash 特性

原文链接: www.sitepoint.com

中文:https://www.zcfy.cc/article/10-lodash-features-you-can-replace-with-es6-467.html

现在ES6 确实已经大行其道了,但是 lodash 仍然有不可取代的地方。对我而言主要是两点:
1、lodash 的操作(例如 forEach)都是对对象数组都可用的,而 ES6 原生方法往往只对数组有效。
2、lodash 的所有操作都是 null-safe 的,而 ES6 完全不考虑。结果就变成了

const obj={a: {b: {c: {one: 'blue', two: 'red'}}}}
_.map(_.get(obj, 'a.b.c'), (item, key)=> item)   // ["blue", "red"]

这样的代码想用原生 ES6 实现,就变得繁琐了很多

const obj={a: {b: {c: {one: 'blue', two: 'red'}}}}
let tmp = obj && obj.a && obj.a.b && obj.a.b.c
tmp && Object.keys(tmp).map(key => tmp[key])  // / ["blue", "red"]
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,453评论 1 45
  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,550评论 0 5
  • 早晨7:30,老公将我送到办公楼下,掉转车头上了高速。 今天他要去170公里外的另外一座城市讲课。14:30开始讲...
    对花情味阅读 689评论 4 4
  • 有一段时间,夜晚睡不着,关了灯,站在窗户边,观察这个小区。 夜归的女生,进了房间、立刻洗澡,然后睡觉...
    天小下阅读 457评论 1 6
  • 是的,好久没感谢自己了。感谢一下吧~ 亲爱滴wj你是最棒的:你那么善良,是发自内心的善良。虽然现在的社会,你的这种...