前军教程网

中小站长与DIV+CSS网页布局开发技术人员的首选CSS学习平台

lodash那些功能强大的API「JS篇」



作者:JS强迫症患者

转发链接:https://juejin.im/post/5ed3cd366fb9a047f129c39a

前言

本文初衷是想列举一些比较“多余”的API以及对应原生JS写法;后面发现API过多,精力有限,慢慢的变成记录那些有助于提高开发效率的API,希望对您有所帮助。对于那些,根据名字或者描述便能知道其实际用途的API,笔者未做Demo演示。各位看官可以查看对应官方文档便能快速应用于实际开发,Lodash中文API上有详细介绍。

官网:https://www.lodashjs.com/

一、收获

  1. lodash那些功能强大的API
  2. lodash那些“多余”的API及原生JS对应写法

二、 Lodash

? Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。采用函数类API,多数API都不修改传入的参数;

? Lodash功能强大,涵盖了前端开发中能遇到的大部分逻辑功能点,使用Lodash能大大提高我们的开发效率。但这也有一个弊端:便利往往会使我们变"懒"。仁者见仁智者见智,Lodash带来便利同时,我们应该时刻记住:JavaScript才是我们的根本;

? Lodash中“多余”的API并不多余,API内部处理了很多开发者常常忽略的异常情况,使代码更加安全;

? 对于大部分Lodash API对比手写JS对应逻辑功能点,并不会提高性能;

? Lodash,gitHub star数为45K。同时是一个学习教材,通过阅读源码能帮助我们夯实JavaScript基础。函数式API让每个逻辑功能点代码量不大,比较容易理解。基础差的同学可以通过阅读源码,手写源码的方式来夯实JavaScript,比如手写:柯里化,防抖,节流,bind,字符串template等。

三、数组 Array

“多余”指数:☆☆

  1. compact(过滤假值)
   lodash.compact([0, 1, false, 2, '', 3])
   [0, 1, false, 2, '', 3].filter(_ => _)
   // [1, 2, 3]
复制代码
  1. concat(数组拼接)
   lodash.concat([1], [2, 3, 4], [5, 6])
   [1, ...[2, 3, 4], ...[5, 6]]
   // [1, 2, 3, 4, 5, 6]
复制代码
  1. fill(填充)
   lodash.fill([1,2,3],'a')
   [1,2,3].fill('a'))
   // ['a', 'a', 'a']
   
   lodash.fill(Array(3),'b')
   Array(3).fill('b')
   // ['b', 'b', 'b']
复制代码
  1. head(获取第一个元素)
   const first1 = lodash.head([1, 2, 3])
   const [first2] = [1, 2, 3]
   // 1
复制代码
  1. flatten(降1个维度)
   lodash.flatten([1, [2, [3, [4]], 5]]))
   [1, [2, [3, [4]], 5]].flat(1))
   // [1, 2, [3, [4]], 5]
复制代码
  1. flattenDeep | flattenDepth(降为一维数组)
   lodash.flattenDeep([1, [2, [3, [4]], 5]])
   lodash.flattenDepth([1, [2, [3, [4]], 5]], 3)
   [1, [2, [3, [4]], 5]].flat(Infinity)
   // [1, 2, 3, 4, 5]
复制代码
  1. fromPairs(entries类型数组转换为对象)
   lodash.fromPairs([['fred', 30], ['barney', 40]])
   Object.fromEntries([['fred', 30], ['barney', 40]])
   // {fred: 30, barney: 40}
复制代码
  1. pull(移除指定元素)
   lodash.pull([1, 2, 3, 1, 2, 3], 2, 3)
   [1, 2, 3, 1, 2, 3].filter(item => ![2, 3].includes(item))
   // [1, 1]
复制代码
  1. Array自带的reverse (数组翻转)、slice(切割)、join(字符串拼接)、indexOf | lastIndexOf(匹配索引)等

“多余”指数:☆

  1. difference
   lodash.difference([3, 2, 1], [4, 2])
   [3, 2, 1].filter(item => ![4, 2].includes(item))
复制代码
  1. tail(返回不包含第一个元素的数组)
   var other = lodash.tail([1, 2, 3])
   var [, ...other] = [1, 2, 3] // 可扩展不包含前第n个元素
复制代码
  1. take (0 - n的元素),如果用于删除数组元素有点"多余"
   let arr1 = [1, 2, 3, 4, 5]
   arr1 = lodash.take(arr1, 2) // 做赋值,删除元素
   const arr2 = [1, 2, 3, 4, 5]
   arr2.length = 2 // 修改长度,直接删除后面元素,可用于清空数组
   // [1, 2]
复制代码

眼前一亮的API

  1. pullAt (根据下标选择元素,分到两个数组)
  2. takeRight ( 返回从结尾元素开始n个元素的数组切片 )
   // 倒数解构
   const [beforeLast, last] = lodash.takeRight([1, 2, 3, 4], 2)
   console.log(beforeLast, last) // 3 4
复制代码
  1. zipObject
   lodash.zipObject(['a', 'b'], [1, 2]);
   // => { 'a': 1, 'b': 2 }
复制代码
  1. zipObjectDeep
   lodash.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
   // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
复制代码
  1. xor( 创建一个给定数组唯一值的数组 )

眼前二亮的API

  1. remove(元素筛选,分到两个数组)
  2. sortedUniq (去重,排序)
  3. takeRightWhile ( 从array数组的最后一个元素开始提取元素,直到 predicate 返回价值 )
  4. uniqBy (去重,排序)

四、集合 Collection

? Collection很多API都能让人眼前一亮,在实际开发中都能得到应用。

  1. forEach(遍历数组或对象) | forEachRight(反序遍历数组或对象)
   // 遍历数组有点多余
   lodash([1, 2]).forEach((val) => {
     console.log(val)
   })
   // 遍历对象就
   lodash({ a: 1, b: 2 }).forEach((val, key) => {
     console.log(val, key)
   })
   // 原生js写法                      **** 注意数组解构顺序
   Object.entries({ a: 1, b: 2 }).forEach(([key, val]) => {
     console.log(val, key)
   })
复制代码
  1. every(每个元素都符合条件)| some(某个元素符合条件)| filter(过滤)| find(查找第一个)| findLast(查找最后一个)| includes(包含某个元素)。亮点:可以传入一个对象进行匹配
   console.log(lodash([true, 1, null, 'yes']).every(Boolean)) // false
   // 等效于
   console.log([true, 1, null, 'yes'].every(Boolean)) // false
   
   const users = [
       { user: 'barney', age: 40, active: false },
       { user: 'fred', age: 40, active: false },
   ]
   
   // *******眼前一亮的用法********
   console.log(lodash(users).every({ active: false, age: 40 })) // true
   // 等效于
   console.log(users.every((item) => item.active === false && item.age === 40)) // true
   
   console.log(lodash.find(users, { user: 'fred' }) === users[1]) // true
   console.log(lodash.filter(users, { user: 'fred' })) // object for ['fred']
   console.log(lodash.some(users, { user: 'fred' })) // true
复制代码
  1. groupBy(分组)
   const users = [
       { id: 'a', age: 40, height: 1 },
       { id: 'b', age: 39, height: 2 },
       { id: 'c', age: 38, height: 2 },
       { id: 'd', age: 40, height: 2 },
   ]
   console.log(lodash.groupBy(users, 'age'))
   // 按age分组:{38:obj for ['a'], 39:obj for ['b'], 40:obj for ['c', 'd']}
   console.log(lodash.groupBy(users, ({ age, height }) => age + height))
   // 按age+height结果分组:{40:obj for ['c'], 41:obj for ['a', 'b'], 42:obj for ['d']}
复制代码
  1. invokeMap (分解item:循环调用方法,方法返回值替换集合item)
  2. keyBy ( 生成对象:组成聚合的对象 ;key值来源于回调,回调参数为对应集合item;value为item)
  3. orderBy | sortBy(排序:可指定多个排序字段,有优先级;可控制升序和反序)
  4. partition (站队:根据回调返回值,返回 [ 返回值为true的item数组 , 返回值为false的item数组])
  5. reject (找茬:找出不符合条件的item集合,类似!filter)
  6. sample (抽签:集合中随机取一个)
  7. sampleSize (抽签:集合随机抽取n个)
  8. shuffle (打乱)

五、函数 Function

? 下面列举的是实际开发中应用场景较多的API,具体的用法就不做demo了,具体可参看官网API。

  1. after(n, func) :调用执行n次后才能执行func
  2. before(n, func):调用n次后不再执行func,n次后的返回值为第n次返回值
  3. curry | curryRight :柯里化
  4. debounce :防抖
  5. defer : 推迟调用func,直到当前堆栈清理完毕
  6. throttle :节流
  7. unary : 创建一个最多接受一个参数的函数,忽略多余的参数

六、Lang

? Lang下多为判断类型的API,常规的isXxx判断类型API就不做过多的介绍。下面介绍一些好用的API。

  1. 克隆系列:clone、cloneDeep、cloneWith、cloneDeepWith
  2. eq :判断相等,能判断NaN
  3. isEqual :判断两个对象可枚举value相等,注意不能用于对比DOM对象
  4. isEqualWith:定制isEqual比较
  5. isMatch :判断两个对象部分可枚举value相等
  6. isMatchWith :定制isMatch比较

七、数学 Math

? maxBy(最大值) | minBy(最小值)| meanBy (求平局值)| sumBy (求和)

const users = [
    { id: 'b', age: 39, height: 2 },
    { id: 'a', age: 40, height: 1 },
    { id: 'c', age: 38, height: 2 },
    { id: 'd', age: 40, height: 2 },
]
console.log(lodash.maxBy(users, 'age'))
// obj for 'a'
console.log(lodash.maxBy(users, ({ age, height }) => age + height))
// obj for 'd'
复制代码

八、数字 Number

  1. inRange:判断大于等于且小于等于。改进实现isInRange
   /**
    * 判断数字是否在某个区间
    * @param string 范围
    * demo:
    * const ten = 10
    * ten.isInRange('[1,10]') // true
    * ten.isInRange('[1,10)') // false
    */
   Number.prototype.isInRange = function (range = '[1,10]') {
     // 1. 应该对range进行正则校验
     const val = this.valueOf()
     const isStartEqual = range.startsWith('[')
     const isEndEqual = range.endsWith(']')
   
     let [start, end] = range
       .slice(1, range.length - 1) // 去头尾符号 '1,10'
       .split(',') // 切割字符串 ['1', '10']
       .map(Number) // 转换数字 [1, 10]
   
     start > end && ([start, end] = [end, start]) // 保证start < end
   
     const isGt = isStartEqual ? val >= start : val > start // >start
     const isLt = isEndEqual ? val <= end : val < end // <end
     return isGt && isLt
   }
   const ten = 10
   console.log(ten.isInRange('[1,10]')) // true
   console.log(ten.isInRange('[1,10)')) // false
复制代码

九、对象 Object

? 下面只记录让人眼前一亮的API

  1. at | get :字符串key链路取值
   const object = { a: [{ b: { c: 3 } }, 4] }
   console.log(lodash.at(object, ['a[0].b.c', 'a[1]']))
   // [3, 4]
   console.log(lodash.at(object, 'a[0].b.c'))
   // [3]
   console.log(lodash.get(object, 'a[0].b.c'))
   // 3
复制代码
  1. defaultsDeep :深层设置默认值
   const defaultData = { a: { b: 1, c: 3 } } // 默认值
   const settingData = { a: { b: 2 } } // 设置的值
   
   // 当对象只有一层的时候对象结构还挺好用,类似于lodash.defaults
   // 当对象层级不止一层的时候,层级深的默认值就被冲刷掉了
   const mergeData = {
       ...defaultData, // 默认值放在前面
       ...settingData,
   }
   console.log(mergeData)
   // {a:{b:2}}
   
   // 会改变settingData,所以取副本
   const mergeDataGood = JSON.parse(JSON.stringify(settingData))
   lodash.defaultsDeep(mergeDataGood, defaultData) // 默认值在最后
   console.log(mergeDataGood)
   // {a:{b: 2, c: 3}}
复制代码
  1. has | hasIn : 判断是否有属性链。有时候为了避免代码报错,需要进行串联取值:const dValue = a&&a.b&&a.b.c&&a.b.c.d。ES2020已定稿增加了操作符:?.来解决上述问题。上面等价写法为:const dValue = a?.b?.c?.d
   const obj = { a: { b: { c: { d: 'dValue' } } } }
   const obj2 = {}
   console.log(lodash.has(obj,'a.b.c.d')) // true
   console.log(lodash.has(obj2,'a.b.c.d')) // false
复制代码
  1. invert : key-value反转,返回新对象,新对象为旧对象的value-key;
  2. invertBy :类似invert,能对新对象的key进行处理;
  3. mapKeys :处理对象的key,生成新对象;
  4. mapValues :处理对象value,生成新对象;
  5. merge | mergeWith :对象合并
   var object = {
       a: [{ b: 2 }, { d: 4 }],
       obj: { key1: 'value1', key2: 'value2' },
   }
   var other = {
       a: [{ c: 3 }, { e: 5 }],
       obj: { key1: 'valueOther1', key3: 'valueOther2' },
   }
   console.log(lodash.merge(object, other))
   /**
   {
     a: [
         { b: 2, c: 3 },
         { d: 4, e: 5 },
     ],
     obj: { key1: 'valueOther1', key2: 'value2', key3: 'valueOther2' },
   }
   */
复制代码
  1. omit | omitBy :剔除对象属性。用在抽取保存到后端数据,后端校验严格,不能有多余字段等场景。
   const model = {
       key1: 'value1', // 需要发送到后端的数据
       key2: 'value2',
       key3: 'value3',
       pageKey1: 'pageValue1', // 页面用到的字段
       pageKey2: 'pageValue2',
       pageKey3: 'pageValue3',
   }
   // 1. 原始写法
   const postData1 = {
       key1: model.key1,
       key2: model.key2,
       key3: model.key3,
   }
   // omit
   const postData2 = lodash.omit(model, ['pageKey1', 'pageKey2', 'pageKey3'])
   
   // omitBy                                               // 剔除key包含page字段
   const postData3 = lodash.omitBy(model, (value, key) => key.includes('page'))
   
   console.log(lodash.isEqual(postData1, postData2)) // true
   console.log(lodash.isEqual(postData1, postData3)) // true
复制代码
  1. pick | pickBy:摘选对象属性,功能和omit | omitBy 相反。当要剔除的属性比保留属性多的时候采用pick
  2. set:字符串key链路设置值,和get对应

十、Seq

? API过多,下面只记录Seq让人眼前一亮的API

  1. chain :解决lodash不能链式调用
   var users = [
       { user: 'barney', age: 36 },
       { user: 'fred', age: 40 },
       { user: 'pebbles', age: 1 },
   ]
   const first = lodash
       .chain(users)
       .sortBy('age')
       .map(function (o) {
           return o.user + ' is ' + o.age
       })
       .head()
       .value() // 注意这里要运行.value()才运行,得到结果
   console.log(first) // pebbles is 1
复制代码

十一、字符串 String

? lodash的String API多为转换不同值的API,如:首字母大写、驼峰式、html属性式、下划线连接式、全小写、首字母小写、编码、填充,去空格等API。

? 唯一亮眼的API:template(字符串模板)。可应用于 动态国际化、拼接国际化较优实现

const compiled = lodash.template('hello <%= user.name %>!')
console.log(compiled({ user: { name: 'fred' } }))
// hello fred!

推荐JavaScript经典实例学习资料文章

实践教你从零构建前端 Lint 工作流「干货」

高性能多级多选级联组件开发「JS篇」

深入浅出讲解Node.js CLI 工具最佳实战

延迟加载图像以提高Web网站性能的五种方法「实践」

比较 JavaScript 对象的四种方式「实践」

使用Service Worker让你的 Web 应用如虎添翼(上)「干货」

使用Service Worker让你的 Web 应用如虎添翼(中)「干货」

使用Service Worker让你的 Web 应用如虎添翼(下)「干货」

前端如何一次性处理10万条数据「进阶篇」

推荐三款正则可视化工具「JS篇」

如何让用户选择是否离开当前页面?「JS篇」

JavaScript开发人员更喜欢Deno的五大原因

仅用18行JavaScript实现一个倒数计时器

图文细说JavaScript 的运行机制

一个轻量级 JavaScript 全文搜索库,轻松实现站内离线搜索

推荐Web程序员常用的15个源代码编辑器

10个实用的JS技巧「值得收藏」

细品269个JavaScript小函数,让你少加班熬夜(一)「值得收藏」

细品269个JavaScript小函数,让你少加班熬夜(二)「值得收藏」

细品269个JavaScript小函数,让你少加班熬夜(三)「值得收藏」

细品269个JavaScript小函数,让你少加班熬夜(四)「值得收藏」

细品269个JavaScript小函数,让你少加班熬夜(五)「值得收藏」

细品269个JavaScript小函数,让你少加班熬夜(六)「值得收藏」

深入JavaScript教你内存泄漏如何防范

手把手教你7个有趣的JavaScript 项目-上「附源码」

手把手教你7个有趣的JavaScript 项目-下「附源码」

JavaScript 使用 mediaDevices API 访问摄像头自拍

手把手教你前端代码如何做错误上报「JS篇」

一文让你彻底搞懂移动前端和Web 前端区别在哪里

63个JavaScript 正则大礼包「值得收藏」

提高你的 JavaScript 技能10 个问答题

JavaScript图表库的5个首选

一文彻底搞懂JavaScript 中Object.freeze与Object.seal的用法

可视化的 JS:动态图演示 - 事件循环 Event Loop的过程

教你如何用动态规划和贪心算法实现前端瀑布流布局「实践」

可视化的 js:动态图演示 Promises & Async/Await 的过程

原生JS封装拖动验证滑块你会吗?「实践」

如何实现高性能的在线 PDF 预览

细说使用字体库加密数据-仿58同城

Node.js要完了吗?

Pug 3.0.0正式发布,不再支持 Node.js 6/8

纯JS手写轮播图(代码逻辑清晰,通俗易懂)

JavaScript 20 年 中文版之创立标准

值得收藏的前端常用60余种工具方法「JS篇」

箭头函数和常规函数之间的 5 个区别

通过发布/订阅的设计模式搞懂 Node.js 核心模块 Events

「前端篇」不再为正则烦恼

「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能

深入细品浏览器原理「流程图」

JavaScript 已进入第三个时代,未来将何去何从?

前端上传前预览文件 image、text、json、video、audio「实践」

深入细品 EventLoop 和浏览器渲染、帧动画、空闲回调的关系

推荐13个有用的JavaScript数组技巧「值得收藏」

前端必备基础知识:window.location 详解

不要再依赖CommonJS了

犀牛书作者:最该忘记的JavaScript特性

36个工作中常用的JavaScript函数片段「值得收藏」

Node + H5 实现大文件分片上传、断点续传

一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」

【实践总结】关于小程序挣脱枷锁实现批量上传

手把手教你前端的各种文件上传攻略和大文件断点续传

字节跳动面试官:请你实现一个大文件上传和断点续传

谈谈前端关于文件上传下载那些事【实践】

手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件

最全的 JavaScript 模块化方案和工具

「前端进阶」JS中的内存管理

JavaScript正则深入以及10个非常有意思的正则实战

前端面试者经常忽视的一道JavaScript 面试题

一行JS代码实现一个简单的模板字符串替换「实践」

JS代码是如何被压缩的「前端高级进阶」

前端开发规范:命名规范、html规范、css规范、js规范

【规范篇】前端团队代码规范最佳实践

100个原生JavaScript代码片段知识点详细汇总【实践】

关于前端174道 JavaScript知识点汇总(一)

关于前端174道 JavaScript知识点汇总(二)

关于前端174道 JavaScript知识点汇总(三)

几个非常有意思的javascript知识点总结【实践】

都2020年了,你还不会JavaScript 装饰器?

JavaScript实现图片合成下载

70个JavaScript知识点详细总结(上)【实践】

70个JavaScript知识点详细总结(下)【实践】

开源了一个 JavaScript 版敏感词过滤库

送你 43 道 JavaScript 面试题

3个很棒的小众JavaScript库,你值得拥有

手把手教你深入巩固JavaScript知识体系【思维导图】

推荐7个很棒的JavaScript产品步骤引导库

Echa哥教你彻底弄懂 JavaScript 执行机制

一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧

深入解析高频项目中运用到的知识点汇总【JS篇】

JavaScript 工具函数大全【新】

从JavaScript中看设计模式(总结)

身份证号码的正则表达式及验证详解(JavaScript,Regex)

浏览器中实现JavaScript计时器的4种创新方式

Three.js 动效方案

手把手教你常用的59个JS类方法

127个常用的JS代码片段,每段代码花30秒就能看懂-【上】

深入浅出讲解 js 深拷贝 vs 浅拷贝

手把手教你JS开发H5游戏【消灭星星】

深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】

手把手教你全方位解读JS中this真正含义【实践】

书到用时方恨少,一大波JS开发工具函数来了

干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)

手把手教你JS 异步编程六种方案【实践】

让你减少加班的15条高效JS技巧知识点汇总【实践】

手把手教你JS开发H5游戏【黄金矿工】

手把手教你JS实现监控浏览器上下左右滚动

JS 经典实例知识点整理汇总【实践】

2.6万字JS干货分享,带你领略前端魅力【基础篇】

2.6万字JS干货分享,带你领略前端魅力【实践篇】

简单几步让你的 JS 写得更漂亮

恭喜你获得治疗JS this的详细药方

谈谈前端关于文件上传下载那些事【实践】

面试中教你绕过关于 JavaScript 作用域的 5 个坑

Jquery插件(常用的插件库)

【JS】如何防止重复发送ajax请求

JavaScript+Canvas实现自定义画板

Continuation 在 JS 中的应用「前端篇」


作者:JS强迫症患者
转发链接:https://juejin.im/post/5ed3cd366fb9a047f129c39a

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言