Lodash源码阅读-reverse

功能概述

reverse 函数是 Lodash 中的一个数组操作工具函数,用于反转数组中元素的顺序。它是对 JavaScript 原生 Array.prototype.reverse 方法的封装,提供了更安全的使用方式,能够处理 null 和 undefined 等边缘情况,同时保持了与原生方法一致的返回值特性。

前置学习

在深入理解 reverse 函数之前,建议先了解以下相关概念:

  • JavaScript 原生的 Array.prototype.reverse 方法:数组原型上的反转方法,会改变原数组
  • 函数式编程中的安全调用:处理 null/undefined 等边缘情况的编程模式
  • call 方法:Function.prototype.call,用于指定 this 值调用函数

源码实现

js 复制代码
function reverse(array) {
  return array == null ? array : nativeReverse.call(array);
}

其中:

js 复制代码
var arrayProto = Array.prototype,
  // ... 其他变量定义

  // 原生方法引用
  nativeReverse = arrayProto.reverse;

实现原理解析

原理概述

reverse 函数的实现非常简洁,但包含了函数式编程中常见的安全调用模式。它的核心原理是:

  1. 首先检查输入数组是否为 null 或 undefined
  2. 如果是 null 或 undefined,则直接返回原值,避免报错
  3. 如果是有效数组,则调用 JavaScript 原生的 Array.prototype.reverse 方法
  4. 使用 call 方法确保正确的 this 上下文,使其能够处理类数组对象

这种实现方式既保持了原生方法的高性能,又增加了对边缘情况的处理,提高了函数的健壮性。

代码解析

1. 空值检查

js 复制代码
return array == null ? array : nativeReverse.call(array);

这一行代码首先进行了空值检查:

  • array == null:使用宽松等于检查 array 是否为 null 或 undefined
  • 如果条件为真,则直接返回 array(即 null 或 undefined)

这种检查方式是 Lodash 中常见的安全调用模式,避免在传入 null 或 undefined 时抛出错误。

示例:

js 复制代码
// 处理null和undefined
_.reverse(null); // 返回 null
_.reverse(undefined); // 返回 undefined

// 原生方法会报错
Array.prototype.reverse.call(null); // 抛出TypeError
Array.prototype.reverse.call(undefined); // 抛出TypeError

2. 原生方法引用

js 复制代码
var arrayProto = Array.prototype,
  // ... 其他变量定义
  nativeReverse = arrayProto.reverse;

Lodash 在初始化时缓存了原生的 Array.prototype.reverse 方法:

  • 将原生方法存储在变量中,避免重复查找原型链
  • 这种缓存提高了性能,特别是在多次调用时
  • 同时防止了原生方法被修改后影响 Lodash 的行为

3. 调用原生方法

js 复制代码
nativeReverse.call(array);

使用 Array.prototype.call 方法调用原生的 reverse 函数:

  • call方法允许指定函数执行时的 this 值
  • 这里将 array 作为 this 值传递给 nativeReverse 函数
  • 这种方式使得 reverse 函数不仅可以处理数组,还可以处理类数组对象

示例:

js 复制代码
// 处理普通数组
var arr = [1, 2, 3];
_.reverse(arr); // 返回 [3, 2, 1],同时arr变为[3, 2, 1]

// 处理类数组对象
var arrayLike = { 0: "a", 1: "b", 2: "c", length: 3 };
_.reverse(arrayLike); // 返回 { 0: 'c', 1: 'b', 2: 'a', length: 3 }

4. 返回值

js 复制代码
return array == null ? array : nativeReverse.call(array);

reverse 函数的返回值与原生 Array.prototype.reverse 保持一致:

  • 如果输入为 null 或 undefined,则返回原值
  • 否则返回反转后的数组或类数组对象(与输入是同一个引用)

这保持了与原生方法一致的行为,使得用户可以链式调用或直接使用返回值。

使用示例

1. 基本用法

js 复制代码
// 创建一个数组
var numbers = [1, 2, 3, 4, 5];

// 反转数组
_.reverse(numbers);
console.log(numbers); // [5, 4, 3, 2, 1]

// 原生方法的等效用法
var numbers2 = [1, 2, 3, 4, 5];
Array.prototype.reverse.call(numbers2);
console.log(numbers2); // [5, 4, 3, 2, 1]

2. 处理 null 和 undefined

js 复制代码
// Lodash的reverse可以安全处理null和undefined
console.log(_.reverse(null)); // null
console.log(_.reverse(undefined)); // undefined

// 原生方法会抛出错误
try {
  Array.prototype.reverse.call(null);
} catch (e) {
  console.log(e.message); // "Cannot convert null or undefined to object"
}

3. 处理类数组对象

js 复制代码
// 创建一个类数组对象
var arrayLike = {
  0: "a",
  1: "b",
  2: "c",
  length: 3,
};

// 使用Lodash的reverse
_.reverse(arrayLike);
console.log(arrayLike); // { 0: 'c', 1: 'b', 2: 'a', length: 3 }

// 使用原生方法
var arrayLike2 = {
  0: "a",
  1: "b",
  2: "c",
  length: 3,
};
Array.prototype.reverse.call(arrayLike2);
console.log(arrayLike2); // { 0: 'c', 1: 'b', 2: 'a', length: 3 }

注意事项

1. 修改原数组

与原生的 Array.prototype.reverse 一样,Lodash 的 reverse 函数会修改原数组:

js 复制代码
var array = [1, 2, 3];
var result = _.reverse(array);

console.log(array); // [3, 2, 1]
console.log(result === array); // true,返回的是同一个引用

如果不想修改原数组,可以先创建一个副本:

js 复制代码
var array = [1, 2, 3];
var reversed = _.reverse(_.clone(array));

console.log(array); // [1, 2, 3],原数组保持不变
console.log(reversed); // [3, 2, 1]

总结

Lodash 的 reverse 函数是对 JavaScript 原生 Array.prototype.reverse 方法的一个安全封装,主要特点是:

  1. 安全调用:能够处理 null 和 undefined 等边缘情况
  2. 保持一致性:与原生方法行为一致,修改并返回原数组
  3. 灵活性:可以处理普通数组和类数组对象
相关推荐
摸鱼仙人~1 分钟前
styled-components:现代React样式解决方案
前端·react.js·前端框架
sasaraku.35 分钟前
serviceWorker缓存资源
前端
RadiumAg2 小时前
记一道有趣的面试题
前端·javascript
yangzhi_emo2 小时前
ES6笔记2
开发语言·前端·javascript
yanlele2 小时前
我用爬虫抓取了 25 年 5 月掘金热门面试文章
前端·javascript·面试
中微子3 小时前
React状态管理最佳实践
前端
烛阴3 小时前
void 0 的奥秘:解锁 JavaScript 中 undefined 的正确打开方式
前端·javascript
中微子3 小时前
JavaScript 事件与 React 合成事件完全指南:从入门到精通
前端
Hexene...4 小时前
【前端Vue】如何实现echarts图表根据父元素宽度自适应大小
前端·vue.js·echarts
初遇你时动了情4 小时前
腾讯地图 vue3 使用 封装 地图组件
javascript·vue.js·腾讯地图