Lodash实战练习之手写get函数

Lodash的介绍

Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库,Lodash 通过降低 array、number、objects、string 等等的使用难度从而让 JavaScript 变得更简单。

简单来说,Lodash 是一套工具库,内部封装了很多字符串、数组、对象等常见数据类型的处理函数,大大提高工作效率。

你可能会说 Lodash 里面的好多方法都能自己实现,没必要再引入额外的工具库来增加项目的体积,但是并不能保证实现得比 Lodash 好。我们自己在项目中封装的工具函数,很多时候功能并不是完善的,尤其是一些边界值的处理,而且需要考虑到各种使用场景,Lodash 这些方面就做得很好。

而且 Lodash 支持多种模块化方案,配合 tree-shaking 技术或者使用单独的函数模块,几乎不会导致冗余代码。

js 复制代码
// 方式1:引入整个lodash对象
import _ from "lodash";
// 方式2:按名称引入特定的函数
import { cloneDeep } from "lodash";
 
// 上述2种方式都会引入整个lodash库,体积大,而下面2种方式都能实现按需引入,减小体积
// 1.只引入cloneDeep函数
import cloneDeep from "lodash/cloneDeep";
// 2.使用lodash-es
import { cloneDeep } from "lodash-es";

基于上面的这些优点,Lodash 已经变得非常流行,目前被很多项目应用,越来越受欢迎,Github 上目前已经有 59.1k 的 Star

既然 Lodash 这么优秀,那么我们很应该去学习一下它内部函数的实现,从而提升自己的编码水平,因此这篇文章与大家一同手写实现 get 函数,手写 get 函数也是前端一道高频的面试题。

get函数的使用

首先我们得知道 get 函数是如何使用的?有哪些参数?每个参数的具体作用?

通过文档可以知道,Lodash.get 的使用:_.get(object, path, [defaultValue]) ,接收三个参数

  1. object (Object) : 要检索的对象
  2. path (Array|string) : 要获取属性的路径
  3. [defaultValue] : 如果解析值是 undefined ,这值会被返回

来看一个例子:

js 复制代码
var object = { 'a': [{ 'b': { 'c': 3 } }] };
 
_.get(object, 'a[0].b.c');
// => 3
 
_.get(object, ['a', '0', 'b', 'c']);
// => 3
 
_.get(object, 'a.b.c', 'default');
// => 'default'

通过这个例子 get 函数的作用已经很明显了:根据 path 去依次取对象 object 中的成员的值,比如 _.get(object, 'a[0].b.c'),首先取 object 中的 a 属性,然后取 0 属性,接着取 b 属性,最后取 c 属性,如果对象中没有对应要取的属性,返回 undefined,这时若指定第三个参数 default,那么当前面取值解析为 undefined 时会返回 default。

手写实现简易版

下面开始手写实现一个简易版的 get 函数

1. 基本功能的实现

先考虑 path 为数组的情况,并且先不管第三个参数;path 为数组类型比较好处理,直接遍历数组拿到所有属性即可:

js 复制代码
function _get(object, path) {
  let obj = object;
  for (const key of path) {
    obj = obj[key];
  }
  return obj;
};

测试代码:

js 复制代码
const object = { a: [{ b: { c: 3 } }] };
console.log('-------', _get(object, ['a', '0', 'b', 'c']));
console.log('-------', _get(object, ['a', '0']));
console.log('-------', _get(object, ['a', '0', 'b']));
console.log('-------', _get(object, ['a']));

结果如下,已经基本符合 get 函数的功能:

2. 路径类型的处理

接着考虑 path 为字符串的情况,我这里的思路是,只需加一个类型转化的逻辑,将字符串转为对应的数组即可,然后其他的逻辑与上面保持一致。

利用正则表达式,匹配字符串中的非[ ] . 字符,使用 match 方法得到一个数组,举个例子:a[0].b.c => ['a', '0', 'b', 'c']

Lodash 源码里对字符串的匹配更加复杂,需要考虑到各种字符,我这里的正则表达式比较简单,怎么简单怎么来~

js 复制代码
function _get(object, path) {
  let obj = object;
  if (typeof path === 'string') {
    const reg = /[^\[\].]+/g;
    path = path.match(reg);
  }
  for (const key of path) {
    obj = obj[key];
  }
  return obj;
}

测试代码:

js 复制代码
const object = { a: [{ b: { c: 3 } }] };
console.log('-------', _get(object, 'a[0].b.c'));
console.log('-------', _get(object, 'a[0]'));
console.log('-------', _get(object, 'a[0].b'));
console.log('-------', _get(object, 'a'));

结果如下,与上面 path 为数组的结果是一样的,说明代码没问题:

3. 处理访问不到的属性

现在的 get 方法还存在一个问题,那就是如果我访问对象 object 中不存在的属性:

js 复制代码
console.log(_get(object, ['w', '0', 'b', 'c']));

是会报错的,但是 Lodash 的 get 函数不会报错,而是会返回 undefined,所以需要做些处理:

结果打印 undefined,不会报错。

4. 第三个参数

最后考虑下第三个参数,就是当我前面取值解析为 undefined 时会返回 default,这里很简单,在刚刚的判断语句里返回默认值就好了:

这里还有个小问题,就是如果最后一个属性取不到,目前会返回 undefined

js 复制代码
console.log(_get(object, ['a', '0', 'b', 'w'], '我是默认值'));  // undefined

但是正常情况下应该返回第三个参数才对的,因此需要对 get 函数的返回值做处理:

5. 最终版代码

js 复制代码
function _get(object, path, defaultValue) {
  let obj = object;
  if (typeof path === 'string') {
    const reg = /[^\[\].]+/g;
    path = path.match(reg);
  }
  for (const key of path) {
    if (!obj) {
      return defaultValue;
    }
    obj = obj[key];
  }
  return obj === undefined ? defaultValue : obj;
}

最终版的代码如上,代码不多,看起来也很好理解,关键在于一些细节以及边界值的处理,希望能帮到对大家有所帮助!

写在最后

这就是一个 get 函数简易版本的实现了,Lodash 的源码里其实比这还要复杂,我们实现成上面的样子已经足够了,至少原理方面已经理解透彻,面试时手写也没啥问题,已经达到了手写 get 函数的目的!

如果有讲得不好的地方,大家可以批评指正,一起交流进步🥳🥳

期待大家的点赞 + 关注,多多支持,你的支持是我前进的动力!🤗🤗

相关推荐
清灵xmf22 分钟前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据29 分钟前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_3901617737 分钟前
防抖函数--应用场景及示例
前端·javascript
334554321 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v1 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript