Lodash 含有 Array, Collection, Date, Function, Lang, Math, Number, Object, String 等多个功能模块,总共几百个功能函数。官方文档上以字典顺序排序,不容易总结记忆。通过这5天的学习,我们对这一框架进行总结。主要从lodash的使用优势和迷人细节来辩证看待这一框架。lodash函数的实现非常严谨、高效、兼容性强,以及具有一定的前瞻性。但考虑与ES6部分重合,也不一定要用它完全替代。
目录
lodash优势:
1.lodash在具体使用时按需引入,避免引入不必要的代码:
2.lodash提供的api具有ES6没有的功能,可以省去很多复杂逻辑,优雅而便捷;
3.lodash 的所有操作都是 null-safe 的,而 ES6 完全不考虑
4.lodash 的操作(例如 forEach)都是对对象数组都可用的,而 ES6 原生方法往往只对数组有效。
5.Lodash 还提供了几乎所有浏览器的兼容,很多浏览器对ES6-12的兼容还没完全,所以先使用lodash替代。
6.lodash对于server 端、框架或是工具库开发而言,如果无法预测代码会跑在什么环境,有 lodash 能少考虑很多兼容的问题少做很多测试。
7.lodash很多方法都提供了 path 以及一些很方便的参数,可以大幅度减少代码量.
8.lodash很多immutable,生成新的数据,不影响老数据。是而 JS 原生的 Array 方法,有一些是 mutable 的,有一些是 immutable 的,导致很多坑。
Lodash的迷人细节:
1.length = start > end ? 0 : ((end - start) >>> 0)
2.arr instanceof Array
3._.eq(value, other)
4._.isNaN
5. (-0).toString() === '0'?苦恼!
6. JS 的世界里,谁不能转化为数字?
7. _.repeat 的优化手段
所以我们一起来学习Lodash,今天打卡第五天,加油!
lodash优势:
1.lodash在具体使用时按需引入,避免引入不必要的代码:
// 方式1:引入整个lodash对象
import _ from "lodash";
// 方式2:按模块引入
import map from 'lodash/fp/map';
// 方式3:按名称引入特定的函数
import { cloneDeep } from "lodash";
2.lodash提供的api具有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"]
// lodash 优雅简化
const obj={a: {b: {c: {one: 'blue', two: 'red'}}}}
_.map(_.get(obj, 'a.b.c'), (item, key)=> item) // ["blue", "red"]
3.lodash 的所有操作都是 null-safe 的,而 ES6 完全不考虑
4.lodash 的操作(例如 forEach)都是对对象数组都可用的,而 ES6 原生方法往往只对数组有效。
5.Lodash 还提供了几乎所有浏览器的兼容,很多浏览器对ES6-12的兼容还没完全,所以先使用lodash替代。
6.lodash对于server 端、框架或是工具库开发而言,如果无法预测代码会跑在什么环境,有 lodash 能少考虑很多兼容的问题少做很多测试。
7.lodash很多方法都提供了 path 以及一些很方便的参数,可以大幅度减少代码量.
8.lodash很多immutable,生成新的数据,不影响老数据。是而 JS 原生的 Array 方法,有一些是 mutable 的,有一些是 immutable 的,导致很多坑。
Lodash的迷人细节:
1.length = start > end ? 0 : ((end - start) >>> 0)
在有用到 Array.length 的场景,可用 >>> 0 做参数防护,在 JS 中,Array.length 是一个 32 位无符号整型数字,而通过无符号位移运算 >>> 0
,就是为了确保我们得到的正确的 length 值,它总是能得到一个 32-bit unsigned ints 。
2.arr instanceof Array
我们会用 instanceof 去判断实例与类之间的关系,但是这种关系可靠吗?
arr instanceof Array 为 true 肯定 arr 就是一个数组,但是为 false 是不是就表示 arr 肯定不是数组呢?
不能!在有多个 frame 的时候就不能...
let xArray = window.frames[0].Array; // origin from iframe's window
let arr = new xArray(1, 2, 3);
arr instanceof Array; // false
Array.isArray(arr); // true
也就是,你以为的并不都是你以为的 ... 虽然我们平时不常会有多个 frame 间这种级别的类的混用,但是以防万一...
通常,在需要判断是否是数组时,可以使用 Array.isArray
或者它的 Polyfill:
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
3._.eq(value, other)
判断 value 和 other 是否(强)相等,在 ECMA 规范中对于相等其实是有明确的定义的,其中 NaN === NaN
,但是在 JS 中,NaN 是不与任何值相等的,包括自身,而 Lodash 弥补了这部分的不足,那怎么判断 NaN === NaN 呢?
function eq(value, other) {
return value === other || (value !== value && other !== other)
}
我们知道 NaN 是唯一个不与自身相等的值,因此可以通过这个特性分别得到 value 和 other 是否是 NaN,如果是,则两者相等,返回 true.
4._.isNaN
如何判断是否是 NaN ?
通过 isNaN 全局方法?
isNaN('x') // true
isNaN(NaN) // true
isNaN(0) // false
全局方法 isNaN 是有坑的,它的 NaN 定义估计真的是 not a number, 而不是值得 NaN 这个s数值,也就是除了 NaN, 对于 不能转化为数字 的情况都会返回 true ... 糟心!其实这个问题已经在 ES6 中被改善啦,Number.isNaN
分分钟教isNaN
做人,Number.isNaN 只会对 NaN 返回 true, 其他情况都是 false...
5. (-0).toString() === '0'
?苦恼!
-0 的 toString 竟然没有保留 -
,坑爹嘛不是...
但是,_.toString(-0) === '-0'
,如何做的?
// 一系列的前置检查和转化后...
const INFINITY = 1 / 0; // 手动 INFINITY
const res = `${value}`;
if (res === '0' && 1 / value === -INFINITY) {
return '-0';
} else {
return res;
}
6. JS 的世界里,谁不能转化为数字?
数字、数字字符串肯定是可以的...
对象?或者非数字的字符串?它们也能得到 NaN
Symbol !
Number('xx') // NaN
Number(new Object()) // NaN
Number(Symbol())
// --> Uncaught TypeError: Cannot convert a Symbol value to a number
另外,Symbol 可以显示的转化为 String 和 Boolean, 但是,不能进行任何隐式转换,也就是不能对 Sybmol 进行运算,比如:
const symbol = Symbol();
1 + symbol // TypeError
'1' + symbol // TypeError
// 可显示转化为 布尔 和 字符串
Boolean(symbol) // true
String(symbol) // "Symbol()"
7. _.repeat
的优化手段
_.repeat([str = ''], [times = 1])
指定 string 重复 n 次输出,可以很简单的通过循环实现:
const repeat = (str = '', times = 1) => {
let res = str;
while (--times) {
res += str;
}
return res;
}
repeat('6', 3); // 666
Easy ? 好像不是特别完美吧,设想 repeat('6', 4)
按照上述实现需要循环 4 次,但是其实是可以通过两次操作就把最终结果拼接出来的,就相当于 repeat(repeat('6', 2), 2)
,所以这块是有优化空间的,来看优化后的算法:
const repeat = (str = '', times = 1) => {
let result = '';
if (!str || times < 1) {
return result;
}
do {
if (times % 2) {
result += str;
}
times = Math.floor(times / 2);
if (times) {
str += str;
}
} while (times)
return result;
}
性能对比:repeat('hello world', 100000)
测试的 benchmark:
远远超出 ...
总结:Lodash这个库真香,但是还是要辩证看待,需要了解它的安全漏洞,安全避开,还要了解它部分修改原数据的api,然后注意按需引入。
以上就是今天的学习,欢迎关注我,大家一起进步!
欢迎点赞,评论,谢谢!~
参考学习:
Lodash 源码中的那些迷人的细节 - 知乎