如何详细解析JavaScript中比较两个值是否相等的方法?
- 内容介绍
- 文章标签
- 相关推荐
本文共计2295个文字,预计阅读时间需要10分钟。
目录前言非严格相等严格相等相同值零相同值总结前言在JavaScript中,如何判断两个值是否相等是一个常见的问题。这个问题看似简单,但实际上并非如此,因为JavaScript中存在四种不同的相等逻辑。
非严格相等严格相等相同值零相同值总结在JavaScript中,存在两种基本的比较操作符:`==`(非严格相等)和`===`(严格相等)。除了这两种,还有两种特殊的相等逻辑:相同值零和相同值。
非严格相等(==)非严格相等(==)在进行比较时,如果两个值的类型不同,JavaScript会尝试进行类型转换,使其类型相同后再进行比较。例如:
javascript
0=='0' // true,因为'0'会被转换为数字0
NaN==NaN // false,因为NaN与任何值都不相等严格相等(===)严格相等(===)在比较时不会进行类型转换,如果两个值的类型不同,则直接返回false。例如:
javascript
0==='0' // false,因为类型不同
NaN===NaN // false,因为NaN与任何值都不相等相同值零相同值零是一个特殊的逻辑,用于处理JavaScript中的特殊值`-0`和`+0`。在JavaScript中,`-0`和`+0`被视为相同值,但在比较时可能会出现不一致的结果:
javascript-0===+0 // true,相同值零逻辑-0==+0 // true,类型相同,值也相同
相同值相同值逻辑用于比较两个对象是否指向同一内存地址,或者两个引用值是否相同:
javascripta={}; // 创建一个新对象b={}; // 创建另一个新对象,与a不同a===b // false,两个对象指向不同的内存地址
function createObj() { return {};}
c=createObj(); // 创建一个新对象,与a相同a===c // true,两个对象指向相同的内存地址
总结在JavaScript中,理解不同的相等逻辑非常重要,因为它们可能会在比较过程中产生意外的结果。通过使用正确的比较操作符和了解每个操作符的行为,可以避免常见的错误,并确保代码的准确性和一致性。
目录
- 前言
- 非严格相等
- 严格相等
- 同值零
- 同值
- 总结
前言
在 JavaScript 中如何判断两个值相等,这个问题看起来非常简单,但并非如此,在 JavaScript 中存在 4 种不同的相等逻辑,如果你不知道他们的区别,或者认为判断相等非常简单,那么本文非常适合你阅读。
ECMAScript 是 JavaScript 的语言规范,在ECMAScript 规范中存在四种相等算法,如下图所示:
上图中四种算法对应的中文名字如下,大部分前端应该熟悉严格相等和非严格相等,但对于同值零和同值却不熟悉,下面我们分别介绍这四种算法。
- 同值
- 同值零
- 非严格相等
- 严格相等
非严格相等
非严格相等使用两个等号,也就是我们熟悉的双等,非严格相等表示语义相等,不要求类型一样,非严格相等在比较前会先将比较参数类型转换为一致,再进行比较,代码示例如下:
1 == 1; // true 1 == '1'; // true 类型不同,不影响比较结果
非严格相等有非常复杂的转换规则,非常难以记忆,社区中有人将上面的规则总结成了图片,一图胜千言,如下图所示:
为了方便记住非严格相等的的转换逻辑,作者将非对象值,可以总结为如下三条规则:
- Undefined 只和 Null 相等
- 和 Number 比较时,另一个值会自动转换为 Number
- 和 Boolean 比较时,另一个值会转换为 Number
如果值为对象,会使用内部的 ToPrimitive 转换,可以通过自定义 Symbol.toPrimitive 改变返回值,需要注意的是在相等的判断中 Symbol.toPrimitive 接受的 hint 参数都是 default。
const obj = { [Symbol.toPrimitive](hint) { console.log(hint); if (hint == 'number') { return 1; } if (hint == 'string') { return 'yan'; } return true; }, }; console.log(obj == 1); // obj 返回 true console.log(obj == '1'); // obj 返回 true console.log(obj == true); // obj 返回 true
非严格相等并非带来了很多便利,通过隐式的自动转换,简化了部分场景的工作,比如 Number 和 String 的自动转换,简化了前端从表单,url 参数中获取值的比较问题,但自动转换带来的问题比便利还多。
隐式转换的规则,大部分情况下难以驾驭,现在主流的观点已经不建议使用,作者建议只在判断 undefined 和 null 的场景下可以使用非严格相等。
严格相等
严格相等是另一种比较算法,其和非严格想等的区别是不会进行类型转换,类型不一致时直接返回 false,严格相等对应===操作符,因为使用三个等号,也被称作三等或者全等,严格相等示例如下:
1 === 1; // true 1 === '1'; // false 类型不同,影响比较结果
不同类型值判断规则如下,和前面的非严格相等对比,严格相等更符合直觉。
严格相等解决了非严格相等中隐式转换带来的问题,但也丢失了隐式转换带来的便利,对于类型可能不一致的情况下,比如从表单中获取的值都是字符串,保险的做法是,在比较前手动类型转换,代码示例如下:
1 === Number('1'); // true 手动类型转换,类型防御
严格相等几乎总是正确的,但也有例外情况,比如 NaN 和正负 0 的问题。
Number 类型有个特殊的值 NaN,用来表示计算错误的情概况,比较常见是非 Number 类型和 Number 类型计算时,会得到 NaN 值,代码示例如下所示,这是从表单和接口请求获取数据时很容易出现的问题。
const a = 0 / 0; // NaN const b = 'a' / 1; const c = undefined + 1; // NaN
在严格相等中,NaN 是不等于自己的,NaN 是(x !== x) 成立的唯一情况,在某些场景下其实是希望能够判断 NaN 的,可以使用 isNaN 进行判断,ECMAScript 2015 引入了新的 Number.isNaN,和 isNaN 的区别是不会对传入的参数做类型转换,建议使用语义更清晰的 Number.isNaN,但是要注意兼容性问题,判断 NaN 代码示例如下:
NaN === NaN; // false isNaN(NaN); // true Number.isNaN(NaN); // true isNaN('aaa'); // true 自动转换类型 'aaa'转换为Number为NaN Number.isNaN('aaa'); // false 不进行转换,类型不为Number,直接返回false
严格相等另一个例外情况是,无法区分+0 和-0,代码示例如下,在一些数学计算场景中是要区分语义的。
+0 === -0; // true
JavaScript 中很多系统函数都使用严格相等,比如数组的 indexOf,lastIndexOf 和 switch-case 等,需要注意,这些对于 NaN 无法返回正确结果,代码示例如下:
[NaN].indexOf(NaN); // -1 数组中其实存在NaN [NaN].lastIndexOf(NaN); // -1
同值零
同值零是另一种相等算法,名字来源于规范的直译,规范中叫做 SameValueZero,同值零和严格相等功能一样,除了处理 NaN 的方式,同值零认为 NaN 和 NaN 相等,这在判断 NaN 是否在集合中的语义下是非常合理的。
ECMAScript 2016 引入的 includes 使用此算法,此外 Map 的键去重和 Set 的值去重,使用此算法,代码示例如下:
[NaN].incdudes(NaN); // true 注意和indexOf的区别,incdudes的语义更合理 new Set([NaN, NaN]); // [NaN] set中只会有个一个NaN,如果 NaN !== NaN的话,应该是[NaN, NaN] new Map([ [NaN, 1], [NaN, 2], ]); // {NaN => 2} 如果 NaN !== NaN的话,应该是 {NaN => 1, NaN => 2}
同值
同值是最后一种相等算法,其和同值零类似,但认为 +0 不等于 -0,ECMAScript 2015 带来的 Object.is 使用同值算法,代码示例如下:
Object.is(NaN, NaN); // true Object.is(+0, -0); // false
本文共计2295个文字,预计阅读时间需要10分钟。
目录前言非严格相等严格相等相同值零相同值总结前言在JavaScript中,如何判断两个值是否相等是一个常见的问题。这个问题看似简单,但实际上并非如此,因为JavaScript中存在四种不同的相等逻辑。
非严格相等严格相等相同值零相同值总结在JavaScript中,存在两种基本的比较操作符:`==`(非严格相等)和`===`(严格相等)。除了这两种,还有两种特殊的相等逻辑:相同值零和相同值。
非严格相等(==)非严格相等(==)在进行比较时,如果两个值的类型不同,JavaScript会尝试进行类型转换,使其类型相同后再进行比较。例如:
javascript
0=='0' // true,因为'0'会被转换为数字0
NaN==NaN // false,因为NaN与任何值都不相等严格相等(===)严格相等(===)在比较时不会进行类型转换,如果两个值的类型不同,则直接返回false。例如:
javascript
0==='0' // false,因为类型不同
NaN===NaN // false,因为NaN与任何值都不相等相同值零相同值零是一个特殊的逻辑,用于处理JavaScript中的特殊值`-0`和`+0`。在JavaScript中,`-0`和`+0`被视为相同值,但在比较时可能会出现不一致的结果:
javascript-0===+0 // true,相同值零逻辑-0==+0 // true,类型相同,值也相同
相同值相同值逻辑用于比较两个对象是否指向同一内存地址,或者两个引用值是否相同:
javascripta={}; // 创建一个新对象b={}; // 创建另一个新对象,与a不同a===b // false,两个对象指向不同的内存地址
function createObj() { return {};}
c=createObj(); // 创建一个新对象,与a相同a===c // true,两个对象指向相同的内存地址
总结在JavaScript中,理解不同的相等逻辑非常重要,因为它们可能会在比较过程中产生意外的结果。通过使用正确的比较操作符和了解每个操作符的行为,可以避免常见的错误,并确保代码的准确性和一致性。
目录
- 前言
- 非严格相等
- 严格相等
- 同值零
- 同值
- 总结
前言
在 JavaScript 中如何判断两个值相等,这个问题看起来非常简单,但并非如此,在 JavaScript 中存在 4 种不同的相等逻辑,如果你不知道他们的区别,或者认为判断相等非常简单,那么本文非常适合你阅读。
ECMAScript 是 JavaScript 的语言规范,在ECMAScript 规范中存在四种相等算法,如下图所示:
上图中四种算法对应的中文名字如下,大部分前端应该熟悉严格相等和非严格相等,但对于同值零和同值却不熟悉,下面我们分别介绍这四种算法。
- 同值
- 同值零
- 非严格相等
- 严格相等
非严格相等
非严格相等使用两个等号,也就是我们熟悉的双等,非严格相等表示语义相等,不要求类型一样,非严格相等在比较前会先将比较参数类型转换为一致,再进行比较,代码示例如下:
1 == 1; // true 1 == '1'; // true 类型不同,不影响比较结果
非严格相等有非常复杂的转换规则,非常难以记忆,社区中有人将上面的规则总结成了图片,一图胜千言,如下图所示:
为了方便记住非严格相等的的转换逻辑,作者将非对象值,可以总结为如下三条规则:
- Undefined 只和 Null 相等
- 和 Number 比较时,另一个值会自动转换为 Number
- 和 Boolean 比较时,另一个值会转换为 Number
如果值为对象,会使用内部的 ToPrimitive 转换,可以通过自定义 Symbol.toPrimitive 改变返回值,需要注意的是在相等的判断中 Symbol.toPrimitive 接受的 hint 参数都是 default。
const obj = { [Symbol.toPrimitive](hint) { console.log(hint); if (hint == 'number') { return 1; } if (hint == 'string') { return 'yan'; } return true; }, }; console.log(obj == 1); // obj 返回 true console.log(obj == '1'); // obj 返回 true console.log(obj == true); // obj 返回 true
非严格相等并非带来了很多便利,通过隐式的自动转换,简化了部分场景的工作,比如 Number 和 String 的自动转换,简化了前端从表单,url 参数中获取值的比较问题,但自动转换带来的问题比便利还多。
隐式转换的规则,大部分情况下难以驾驭,现在主流的观点已经不建议使用,作者建议只在判断 undefined 和 null 的场景下可以使用非严格相等。
严格相等
严格相等是另一种比较算法,其和非严格想等的区别是不会进行类型转换,类型不一致时直接返回 false,严格相等对应===操作符,因为使用三个等号,也被称作三等或者全等,严格相等示例如下:
1 === 1; // true 1 === '1'; // false 类型不同,影响比较结果
不同类型值判断规则如下,和前面的非严格相等对比,严格相等更符合直觉。
严格相等解决了非严格相等中隐式转换带来的问题,但也丢失了隐式转换带来的便利,对于类型可能不一致的情况下,比如从表单中获取的值都是字符串,保险的做法是,在比较前手动类型转换,代码示例如下:
1 === Number('1'); // true 手动类型转换,类型防御
严格相等几乎总是正确的,但也有例外情况,比如 NaN 和正负 0 的问题。
Number 类型有个特殊的值 NaN,用来表示计算错误的情概况,比较常见是非 Number 类型和 Number 类型计算时,会得到 NaN 值,代码示例如下所示,这是从表单和接口请求获取数据时很容易出现的问题。
const a = 0 / 0; // NaN const b = 'a' / 1; const c = undefined + 1; // NaN
在严格相等中,NaN 是不等于自己的,NaN 是(x !== x) 成立的唯一情况,在某些场景下其实是希望能够判断 NaN 的,可以使用 isNaN 进行判断,ECMAScript 2015 引入了新的 Number.isNaN,和 isNaN 的区别是不会对传入的参数做类型转换,建议使用语义更清晰的 Number.isNaN,但是要注意兼容性问题,判断 NaN 代码示例如下:
NaN === NaN; // false isNaN(NaN); // true Number.isNaN(NaN); // true isNaN('aaa'); // true 自动转换类型 'aaa'转换为Number为NaN Number.isNaN('aaa'); // false 不进行转换,类型不为Number,直接返回false
严格相等另一个例外情况是,无法区分+0 和-0,代码示例如下,在一些数学计算场景中是要区分语义的。
+0 === -0; // true
JavaScript 中很多系统函数都使用严格相等,比如数组的 indexOf,lastIndexOf 和 switch-case 等,需要注意,这些对于 NaN 无法返回正确结果,代码示例如下:
[NaN].indexOf(NaN); // -1 数组中其实存在NaN [NaN].lastIndexOf(NaN); // -1
同值零
同值零是另一种相等算法,名字来源于规范的直译,规范中叫做 SameValueZero,同值零和严格相等功能一样,除了处理 NaN 的方式,同值零认为 NaN 和 NaN 相等,这在判断 NaN 是否在集合中的语义下是非常合理的。
ECMAScript 2016 引入的 includes 使用此算法,此外 Map 的键去重和 Set 的值去重,使用此算法,代码示例如下:
[NaN].incdudes(NaN); // true 注意和indexOf的区别,incdudes的语义更合理 new Set([NaN, NaN]); // [NaN] set中只会有个一个NaN,如果 NaN !== NaN的话,应该是[NaN, NaN] new Map([ [NaN, 1], [NaN, 2], ]); // {NaN => 2} 如果 NaN !== NaN的话,应该是 {NaN => 1, NaN => 2}
同值
同值是最后一种相等算法,其和同值零类似,但认为 +0 不等于 -0,ECMAScript 2015 带来的 Object.is 使用同值算法,代码示例如下:
Object.is(NaN, NaN); // true Object.is(+0, -0); // false

