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 函数的目的!

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

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

相关推荐
一只特立独行的猪6111 小时前
Java面试——集合篇
java·开发语言·面试
让开,我要吃人了2 小时前
HarmonyOS开发实战(5.0)实现二楼上划进入首页效果详解
前端·华为·程序员·移动开发·harmonyos·鸿蒙·鸿蒙系统
everyStudy3 小时前
前端五种排序
前端·算法·排序算法
甜兒.4 小时前
鸿蒙小技巧
前端·华为·typescript·harmonyos
她似晚风般温柔7896 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
王中阳Go7 小时前
字节跳动的微服务独家面经
微服务·面试·golang
Jiaberrr7 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy8 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白8 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http
前端小趴菜、8 小时前
Web Worker 简单使用
前端