Lodash学习笔记
有多年开发经验的工程师,往往都会有自己的一套工具库,称为utils、helpers等等,这套库一方面是自己的技术积累,另一方面也是对某项技术的扩展,领先于技术规范的制订和实现。
Lodash就是这样的一套工具库,它内部封装了诸多对字符串、数组、对象等常见数据类型的处理函数,其中部分是目前ECMAScript尚未制订的规范,但同时被业界所认可的辅助函数。莫倩每天使用npm安装Lodash的数量在百万级以上,这在一定程度上证明了其代码的健壮性,值得我们在项目中一试。
模块组成
Lodash听得辅助函数主要分为以下几类,函数列表和用法实力请查看Lodash的官方文档:
Array, 适合于数组类型,比如填充数据、查找元素、数组分片等操作
Collocation, 适用于数组和对象类型,部分适用于字符串,比如分组、查找、过滤等操作
Function, 适用于函数类型,比如节流、延迟、缓存、设置钩子等操作
Lang, 普遍适用于各种类型,常用于执行类型判断和类型转换
Math, 使用与数值类型,常用于执行数学运算
Number, 适用于生成随机数,比较数值与数值区间的关系
Object, 适用于对象类型,常用于对象的创建、扩展、类型转换、检索、集合等操作
Seq, 常用于创建链式调用,提高执行性能(惰性计算)
String, 适用于字符串类型
lodash/fp 模块提供了更接近函数式编程的开发方法,其内部的函数经过包装,具有immutable、auto-curried、iteratee-first、data-last(官方介绍)等特点。
Fixed Arity,固化参数个数,便于柯里化
Rearragned Arguments, 重新调整参数位置,便于函数之间的聚合
Capped Iteratee Argument, 封装Iteratee参数
在React + Webpack + Babel(ES6)的开发环境中,使用Lodash需要安装插件babel-plugin-lodash并更新Babel配置文件:
npm install --save lodash
npm install --save-dev babel-plugin-lodash
更新Bable的配置文件 .babelrc:
{
"presets":[
"react",
"es2015",
"stage-0"
],
"plugins":[
"lodash"
]
}
使用方式:
import _ from 'lodash';
import { add } from 'lodash/fp'; const addOne = add(1);
_.map([1, 2, 3], addOne);
性能
在 Filip Zawada的文章《How to Speed Up Lo-Dash ×100? Introducing Lazy Evaluation》中提到了Lodash提高执行速度的思路,主要有三点: Lazy Evaluation、Pipelining和Deferred Execution。下面两张图来自Filip的博客:

假设有如上图所示的问题: 从若干个求中取出三个面值小于10的球。第一步是从所有的求中取出所有面值小于10的球,第二部是从上一步的结果中去三个球。

上图是另一个解决方案,如果一个球能够通过第一步,那么就继续执行第二步,直至结束然后测试下一个球。。。当我们取到三个球之后就中断整个循环。Filip称这是Lazy Evaluation Algorithm, 就个人理解这并不全面,他后续提到的Pipelining(管道计算),再加上一个中断循环执行的算法应该更符合这里的图示。
此外,使用Lodash的链式调用时,只有现实或隐式调用 .value 方法才会对链式调用的整个操作进行取值,这种不在声明时立即求值,而在使用时进行求职的方式,是Lazy Evaluation最大的特点。
九个实例
收益于Lodash的普及程度,使用它可以提高很多人开发时于都代码的效率,减少彼此之间的误解(Loss of Consciousness)。在《Lodash: 10 Javascript Utility Functions That You Should Probably Stop Rewriting》一文中,作者列举了多个常用的Lodash函数,实例演示了使用Lodash的技巧。
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也可以模拟循环,但在上面代码的使用场景下,_.tiems()的解决方法更加简洁和易于理解。
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_6]
在上面的代码中,我们要创建一个初始值不同、长度为6的数组,其中 _.uniqueId 方法用于生成独一无二的标示符(递增的数字,在程序运行期间保持独一无二), _.partial 方法是对 bind 的封装。
4. 深拷贝
var objA = {
"name": "colin"
}
// 常用的方法一般会比较长,循环对象等
// 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. 随机数
// Native 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, ojbB);
_.assign 是浅拷贝, 和ES6新增的 Object.assign 函数功能一致(建议优先使用Object.assign)。
7. 筛选属性
// Native method: Remove an array of keys from object
Object.prototype.remove = function(arr) {
var that = this;
arr.forEach(function(key){
delete(this[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", "car": "suzuki"};
大多数情况下,Lodash所提供的辅助函数都会比原声的函数更贴近开发需求。在上面的代码中,开发者可以使用数组、字符串以及函数的方式筛选对象的属性,并且最终会返回一个新的对象,中间执行筛选时不会对旧对象产生影响。
// Native method: Returning a new object with selected properties
Object.prototype.pick = function(arr) {
var _this = this;
var obj = {};
arr.forEach(function(){
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 luckDraw = ["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 个可用 ES6 替代的 Lodash 特性》。
其中有两处分厂值得一看:
// 使用箭头函数创建可复用的路径
const object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; [
obj => obj.a[0].b.c,
obj => ojb.a[1]
].map(path => path(object)); // 使用箭头函数编写链式调用
const pipe = function => 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 (c) {
return a + b + c;
}
}
}

Lodash学习笔记的更多相关文章
- lodash 学习笔记
一.介绍 官方文档: 中文 - https://www.lodashjs.com/docs/latest 英文- https://lodash.com/docs/4.17.15 1.作用 lodash ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
随机推荐
- (转)IHS配置安全漏洞: 支持不推荐使用的 SSL 版本、在降级的旧加密上填充 Oracle、检测到 RC4 密码套件、支持弱 SSL 密码套件、 重构 RSA 导出键(又称为 FREAK)
原文:https://blog.csdn.net/lyd135364/article/details/52179426 都是由于ihs配置中支持不推荐使用的ssl版本和弱密码套件引起的. 只要在配置文 ...
- CSS动画原理及硬件加速
一.图层 图层即层叠上下文,具体概念和应用大家可以看我之前转自张鑫旭大神博客的<CSS层叠上下文和层叠顺序>,这里我们简单复习一下产生层叠上下文的原因. 1.根层叠上下文 指的是页面根元素 ...
- SpringBoot入门 (十四) Security安全控制
本文记录在SpringBoot使用SpringSecurity进行安全访问控制. 一 什么是Security Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访 ...
- Flutter踩坑日记:Tab导航栏保持子页面状态
最近应邀票圈小伙伴躺坑Flutter,项目初步雏形完结.以原来的工具链版本为基础做了Flutter版本,不过后面还是需要优化下项目接入Redux,以及扩展一些Native方法. 这里记录一下在开发过程 ...
- [转]MSSQL中利用TOP提高IF EXISTS查询语句的性能
本文转自:https://blog.csdn.net/f_r_e_e_x/article/details/51704784 --有可能返回一条或多个结果集,其实我们只需要知道是否 --有数据即可,这样 ...
- 没有什么,开发ASP.NET时随便写写,想到什么写什么
没有什么,开发ASP.NET时随便写写,想到什么写什么,这次想写点开发过程中,比如在数据库,某一张表中有一个字段,如下: 上面代码示例中高亮字段,数据类型为BIT,它存储的值将为"True& ...
- C# Hadoop学习笔记(二)—架构原理
一,架构 二.名词解释 (一)NameNode(简称NN),Hadoop的主节点,负责侦听节点是否活跃,对外开放接口等.在未来的大数据处理过程中,由于访问量和节点数量的不断增多,需要该节点的处理能 ...
- 【Redis】1、Jedis对管道、事务以及Watch的操作来应对高并发
对于一个互联网平台来说,高并发是经常会遇到的场景.最有代表性的比如秒杀和抢购.高并发会出现三个特点: 1.高并发读取 2.高并发写入(一致性) 3.出现超卖问题 前端如何应对? 1.缓存静态数据,例如 ...
- tomcat学习步骤,附带打破双亲委派模型企业应用实战
1. tomcat入门 入门模块仅做学习大纲梳理,忽略了具体操作指引. Tomcat的三种部署模式: 简单架构模型 连接器的非阻塞模式(NIO) 通道(Channel).缓冲区(Buffer).选择器 ...
- Java三大特性:封装,继承,多态
java提高篇(一)-----理解java的三大特性之封装 概念: 封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独 ...