Lodash源码阅读-eq

功能概述

eq 函数是 Lodash 中的一个基础工具函数,主要用于比较两个值是否相等。它实现了 ECMAScript 规范中的 SameValueZero 比较算法,不仅能处理普通的相等性比较,还能正确处理 JavaScript 中的特殊情况,如 NaN 与自身的比较。这个函数虽然看起来简单,但它解决了 JavaScript 中 === 操作符无法正确处理 NaN 相等性的问题,是 Lodash 中许多其他比较函数的基础。

源码实现

js 复制代码
function eq(value, other) {
  return value === other || (value !== value && other !== other);
}

实现原理解析

原理概述

eq 函数的实现原理非常巧妙:它首先使用严格相等操作符 === 比较两个值,如果相等则直接返回 true;如果不相等,则检查两个值是否都是 NaN(通过 value !== value 这一特性判断),如果都是 NaN 则也返回 true。这种实现方式完美地符合了 ECMAScript 的 SameValueZero 算法规范,既保持了 === 的高性能,又解决了它无法正确处理 NaN 的问题。

整个过程可以概括为:

  1. 使用严格相等操作符 === 比较两个值
  2. 如果相等,返回 true
  3. 如果不相等,检查两个值是否都是 NaN
  4. 如果都是 NaN,返回 true;否则返回 false

代码解析

js 复制代码
return value === other || (value !== value && other !== other);

这一行代码看似简单,但包含了两个关键部分:

1. 严格相等比较:value === other

首先使用 JavaScript 的严格相等操作符 === 比较两个值。严格相等操作符具有以下特性:

  • 不进行类型转换,类型不同的值总是不相等
  • 对象(包括数组)只有在引用同一个对象时才相等
  • undefined 只与 undefined 相等,null 只与 null 相等
  • +0-0 被视为相等
  • NaN 与任何值(包括自身)都不相等

示例:

js 复制代码
// 基本类型比较
eq(1, 1); // true,数字相等
eq("a", "a"); // true,字符串相等
eq(true, true); // true,布尔值相等

// 不同类型比较
eq(1, "1"); // false,类型不同
eq(0, false); // false,类型不同

// 对象比较
var obj = { a: 1 };
eq(obj, obj); // true,同一引用
eq(obj, { a: 1 }); // false,不同引用

// 特殊值比较
eq(null, null); // true
eq(undefined, undefined); // true
eq(+0, -0); // true,在 === 中 +0 和 -0 相等

2. NaN 处理:(value !== value && other !== other)

这部分代码利用了 JavaScript 中 NaN 的一个独特特性:NaN 是唯一一个自身不等于自身的值。也就是说,NaN !== NaN 总是返回 true

因此,表达式 value !== value 只有在 valueNaN 时才为 true。同样,other !== other 只有在 otherNaN 时才为 true

整个表达式 (value !== value && other !== other) 只有在两个值都是 NaN 时才返回 true

示例:

js 复制代码
// NaN 比较
eq(NaN, NaN); // true,两个值都是 NaN
eq(NaN, 1); // false,只有一个值是 NaN
eq(1, NaN); // false,只有一个值是 NaN

// 验证 NaN 的特性
NaN === NaN; // false,严格相等操作符无法正确处理 NaN
NaN !== NaN; // true,NaN 不等于自身

使用示例

js 复制代码
// 基本类型比较
_.eq(1, 1);
// => true

_.eq("a", "a");
// => true

_.eq(true, true);
// => true

// 不同类型比较
_.eq(1, "1");
// => false

_.eq(0, false);
// => false

// 对象比较
var object = { a: 1 };
var other = { a: 1 };

_.eq(object, object);
// => true

_.eq(object, other);
// => false

// 特殊值比较
_.eq(NaN, NaN);
// => true

_.eq(+0, -0);
// => true

_.eq(null, null);
// => true

_.eq(undefined, undefined);
// => true

// 包装对象与原始值比较
_.eq("a", Object("a"));
// => false

_.eq(1, Object(1));
// => false

与其他方法的比较

  1. eq vs === :与严格相等操作符相比,eq 能正确处理 NaN 的比较。
js 复制代码
// 严格相等操作符无法正确处理 NaN
NaN === NaN; // false

// eq 函数能正确处理 NaN
_.eq(NaN, NaN); // true
  1. eq vs ==:与相等操作符相比,eq 不进行类型转换。
js 复制代码
// 相等操作符会进行类型转换
1 == "1"; // true
0 == false; // true

// eq 不进行类型转换
_.eq(1, "1"); // false
_.eq(0, false); // false
  1. eq vs isEqual:eq 只进行浅比较,而 isEqual 进行深比较。
js 复制代码
// eq 只进行浅比较
_.eq({ a: 1 }, { a: 1 }); // false,不同引用

// isEqual 进行深比较
_.isEqual({ a: 1 }, { a: 1 }); // true,内容相同
  1. eq vs Object.is:eq 与 Object.is 类似,但对待 +0 和 -0 的方式不同。
js 复制代码
// Object.is 区分 +0 和 -0
Object.is(+0, -0); // false

// eq 不区分 +0 和 -0
_.eq(+0, -0); // true

注意事项

  1. 对象比较 :eq 只进行引用比较,不比较对象的内容。如果需要比较对象内容,应使用 _.isEqual
js 复制代码
// eq 只比较引用
_.eq({ a: 1 }, { a: 1 }); // false,不同引用

// isEqual 比较内容
_.isEqual({ a: 1 }, { a: 1 }); // true,内容相同
  1. 原始值与包装对象:eq 区分原始值和其对应的包装对象。
js 复制代码
// 原始字符串与字符串对象
_.eq("a", Object("a")); // false

// 原始数字与数字对象
_.eq(1, Object(1)); // false
  1. +0 与 -0:eq 将 +0 和 -0 视为相等,这在大多数情况下是符合预期的,但在某些特殊场景可能需要区分它们。
js 复制代码
// eq 不区分 +0 和 -0
_.eq(+0, -0); // true

// 如果需要区分,可以使用 Object.is
Object.is(+0, -0); // false

总结

Lodash 的 eq 函数是一个简单但非常实用的工具,它通过巧妙的实现解决了 JavaScript 中 === 操作符无法正确处理 NaN 相等性的问题。虽然只有一行代码,但它完美地实现了 ECMAScript 的 SameValueZero 算法,为 Lodash 中的其他比较函数提供了基础。

相关推荐
rudy_zhou13 分钟前
使用纯CSS 实现 侧边栏 拖拽效果
前端·css
samroom14 分钟前
Node.js学习分享(下)
前端·学习·node.js
zru_960237 分钟前
Rule-Engine 使用介绍
java·前端·数据库
清清ww1 小时前
elementUI改样式失败问题——DatePicker 日期选择器
前端·javascript·elementui
做想做的,1 小时前
el-table表格样式设置单元格样式方法 :cell-class-name
前端·javascript·vue.js·spring boot
liuyang___1 小时前
vue左侧边框点击后让字体高亮
前端·javascript·vue.js
丁总学Java1 小时前
小程序渲染之谜:如何解决“加载中...”不消失的 Bug(glass-easel)
前端·小程序·bug·glass·glass-easel·easel
只有干货1 小时前
elementui table 自动滚动 纯js实现
前端·javascript·elementui
码云之上1 小时前
奇技淫巧——element-ui组件"无损"拓展自身能力
前端·vue.js·element
前端Hardy1 小时前
HTML&CSS :美如画的音乐播放器卡片
javascript·css·html