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 中的其他比较函数提供了基础。

相关推荐
灵感__idea7 小时前
Hello 算法:贪心的世界
前端·javascript·算法
GreenTea8 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
killerbasd10 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌10 小时前
ES6——二进制数组详解
前端·ecmascript·es6
码事漫谈10 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
ZC跨境爬虫10 小时前
【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级
前端·爬虫·scrapy·html
爱上好庆祝11 小时前
svg图片
前端·css·学习·html·css3
橘子编程11 小时前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
王夏奇11 小时前
python中的__all__ 具体用法
java·前端·python
叫我一声阿雷吧11 小时前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint